diff options
Diffstat (limited to 'drivers')
542 files changed, 13977 insertions, 7143 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 80998958cf45..119d58db8342 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
| @@ -385,8 +385,8 @@ config ACPI_CUSTOM_METHOD | |||
| 385 | to override that restriction). | 385 | to override that restriction). |
| 386 | 386 | ||
| 387 | config ACPI_BGRT | 387 | config ACPI_BGRT |
| 388 | tristate "Boottime Graphics Resource Table support" | 388 | bool "Boottime Graphics Resource Table support" |
| 389 | default n | 389 | depends on EFI |
| 390 | help | 390 | help |
| 391 | This driver adds support for exposing the ACPI Boottime Graphics | 391 | This driver adds support for exposing the ACPI Boottime Graphics |
| 392 | Resource Table, which allows the operating system to obtain | 392 | Resource Table, which allows the operating system to obtain |
diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c index 6680df36b963..be6039958545 100644 --- a/drivers/acpi/bgrt.c +++ b/drivers/acpi/bgrt.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright 2012 Red Hat, Inc <mjg@redhat.com> | 2 | * Copyright 2012 Red Hat, Inc <mjg@redhat.com> |
| 3 | * Copyright 2012 Intel Corporation | ||
| 3 | * | 4 | * |
| 4 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
| @@ -11,20 +12,10 @@ | |||
| 11 | #include <linux/init.h> | 12 | #include <linux/init.h> |
| 12 | #include <linux/device.h> | 13 | #include <linux/device.h> |
| 13 | #include <linux/sysfs.h> | 14 | #include <linux/sysfs.h> |
| 14 | #include <linux/io.h> | 15 | #include <linux/efi-bgrt.h> |
| 15 | #include <acpi/acpi.h> | ||
| 16 | #include <acpi/acpi_bus.h> | ||
| 17 | 16 | ||
| 18 | static struct acpi_table_bgrt *bgrt_tab; | ||
| 19 | static struct kobject *bgrt_kobj; | 17 | static struct kobject *bgrt_kobj; |
| 20 | 18 | ||
| 21 | struct bmp_header { | ||
| 22 | u16 id; | ||
| 23 | u32 size; | ||
| 24 | } __attribute ((packed)); | ||
| 25 | |||
| 26 | static struct bmp_header bmp_header; | ||
| 27 | |||
| 28 | static ssize_t show_version(struct device *dev, | 19 | static ssize_t show_version(struct device *dev, |
| 29 | struct device_attribute *attr, char *buf) | 20 | struct device_attribute *attr, char *buf) |
| 30 | { | 21 | { |
| @@ -63,18 +54,7 @@ static DEVICE_ATTR(yoffset, S_IRUGO, show_yoffset, NULL); | |||
| 63 | static ssize_t show_image(struct file *file, struct kobject *kobj, | 54 | static ssize_t show_image(struct file *file, struct kobject *kobj, |
| 64 | struct bin_attribute *attr, char *buf, loff_t off, size_t count) | 55 | struct bin_attribute *attr, char *buf, loff_t off, size_t count) |
| 65 | { | 56 | { |
| 66 | int size = attr->size; | 57 | memcpy(buf, attr->private + off, count); |
| 67 | void __iomem *image = attr->private; | ||
| 68 | |||
| 69 | if (off >= size) { | ||
| 70 | count = 0; | ||
| 71 | } else { | ||
| 72 | if (off + count > size) | ||
| 73 | count = size - off; | ||
| 74 | |||
| 75 | memcpy_fromio(buf, image+off, count); | ||
| 76 | } | ||
| 77 | |||
| 78 | return count; | 58 | return count; |
| 79 | } | 59 | } |
| 80 | 60 | ||
| @@ -101,45 +81,18 @@ static struct attribute_group bgrt_attribute_group = { | |||
| 101 | 81 | ||
| 102 | static int __init bgrt_init(void) | 82 | static int __init bgrt_init(void) |
| 103 | { | 83 | { |
| 104 | acpi_status status; | ||
| 105 | int ret; | 84 | int ret; |
| 106 | void __iomem *bgrt; | ||
| 107 | 85 | ||
| 108 | if (acpi_disabled) | 86 | if (!bgrt_image) |
| 109 | return -ENODEV; | ||
| 110 | |||
| 111 | status = acpi_get_table("BGRT", 0, | ||
| 112 | (struct acpi_table_header **)&bgrt_tab); | ||
| 113 | |||
| 114 | if (ACPI_FAILURE(status)) | ||
| 115 | return -ENODEV; | 87 | return -ENODEV; |
| 116 | 88 | ||
| 117 | sysfs_bin_attr_init(&image_attr); | 89 | sysfs_bin_attr_init(&image_attr); |
| 118 | 90 | image_attr.private = bgrt_image; | |
| 119 | bgrt = ioremap(bgrt_tab->image_address, sizeof(struct bmp_header)); | 91 | image_attr.size = bgrt_image_size; |
| 120 | |||
| 121 | if (!bgrt) { | ||
| 122 | ret = -EINVAL; | ||
| 123 | goto out_err; | ||
| 124 | } | ||
| 125 | |||
| 126 | memcpy_fromio(&bmp_header, bgrt, sizeof(bmp_header)); | ||
| 127 | image_attr.size = bmp_header.size; | ||
| 128 | iounmap(bgrt); | ||
| 129 | |||
| 130 | image_attr.private = ioremap(bgrt_tab->image_address, image_attr.size); | ||
| 131 | |||
| 132 | if (!image_attr.private) { | ||
| 133 | ret = -EINVAL; | ||
| 134 | goto out_err; | ||
| 135 | } | ||
| 136 | |||
| 137 | 92 | ||
| 138 | bgrt_kobj = kobject_create_and_add("bgrt", acpi_kobj); | 93 | bgrt_kobj = kobject_create_and_add("bgrt", acpi_kobj); |
| 139 | if (!bgrt_kobj) { | 94 | if (!bgrt_kobj) |
| 140 | ret = -EINVAL; | 95 | return -EINVAL; |
| 141 | goto out_iounmap; | ||
| 142 | } | ||
| 143 | 96 | ||
| 144 | ret = sysfs_create_group(bgrt_kobj, &bgrt_attribute_group); | 97 | ret = sysfs_create_group(bgrt_kobj, &bgrt_attribute_group); |
| 145 | if (ret) | 98 | if (ret) |
| @@ -155,22 +108,11 @@ out_group: | |||
| 155 | sysfs_remove_group(bgrt_kobj, &bgrt_attribute_group); | 108 | sysfs_remove_group(bgrt_kobj, &bgrt_attribute_group); |
| 156 | out_kobject: | 109 | out_kobject: |
| 157 | kobject_put(bgrt_kobj); | 110 | kobject_put(bgrt_kobj); |
| 158 | out_iounmap: | ||
| 159 | iounmap(image_attr.private); | ||
| 160 | out_err: | ||
| 161 | return ret; | 111 | return ret; |
| 162 | } | 112 | } |
| 163 | 113 | ||
| 164 | static void __exit bgrt_exit(void) | ||
| 165 | { | ||
| 166 | iounmap(image_attr.private); | ||
| 167 | sysfs_remove_group(bgrt_kobj, &bgrt_attribute_group); | ||
| 168 | sysfs_remove_bin_file(bgrt_kobj, &image_attr); | ||
| 169 | } | ||
| 170 | |||
| 171 | module_init(bgrt_init); | 114 | module_init(bgrt_init); |
| 172 | module_exit(bgrt_exit); | ||
| 173 | 115 | ||
| 174 | MODULE_AUTHOR("Matthew Garrett"); | 116 | MODULE_AUTHOR("Matthew Garrett, Josh Triplett <josh@joshtriplett.org>"); |
| 175 | MODULE_DESCRIPTION("BGRT boot graphic support"); | 117 | MODULE_DESCRIPTION("BGRT boot graphic support"); |
| 176 | MODULE_LICENSE("GPL"); | 118 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 9628652e080c..e0596954290b 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
| @@ -237,6 +237,16 @@ static int __acpi_bus_get_power(struct acpi_device *device, int *state) | |||
| 237 | } else if (result == ACPI_STATE_D3_HOT) { | 237 | } else if (result == ACPI_STATE_D3_HOT) { |
| 238 | result = ACPI_STATE_D3; | 238 | result = ACPI_STATE_D3; |
| 239 | } | 239 | } |
| 240 | |||
| 241 | /* | ||
| 242 | * If we were unsure about the device parent's power state up to this | ||
| 243 | * point, the fact that the device is in D0 implies that the parent has | ||
| 244 | * to be in D0 too. | ||
| 245 | */ | ||
| 246 | if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN | ||
| 247 | && result == ACPI_STATE_D0) | ||
| 248 | device->parent->power.state = ACPI_STATE_D0; | ||
| 249 | |||
| 240 | *state = result; | 250 | *state = result; |
| 241 | 251 | ||
| 242 | out: | 252 | out: |
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index fc1803414629..40e38a06ba85 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c | |||
| @@ -107,6 +107,7 @@ struct acpi_power_resource { | |||
| 107 | 107 | ||
| 108 | /* List of devices relying on this power resource */ | 108 | /* List of devices relying on this power resource */ |
| 109 | struct acpi_power_resource_device *devices; | 109 | struct acpi_power_resource_device *devices; |
| 110 | struct mutex devices_lock; | ||
| 110 | }; | 111 | }; |
| 111 | 112 | ||
| 112 | static struct list_head acpi_power_resource_list; | 113 | static struct list_head acpi_power_resource_list; |
| @@ -225,7 +226,6 @@ static void acpi_power_on_device(struct acpi_power_managed_device *device) | |||
| 225 | 226 | ||
| 226 | static int __acpi_power_on(struct acpi_power_resource *resource) | 227 | static int __acpi_power_on(struct acpi_power_resource *resource) |
| 227 | { | 228 | { |
| 228 | struct acpi_power_resource_device *device_list = resource->devices; | ||
| 229 | acpi_status status = AE_OK; | 229 | acpi_status status = AE_OK; |
| 230 | 230 | ||
| 231 | status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL); | 231 | status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL); |
| @@ -238,19 +238,15 @@ static int __acpi_power_on(struct acpi_power_resource *resource) | |||
| 238 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n", | 238 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n", |
| 239 | resource->name)); | 239 | resource->name)); |
| 240 | 240 | ||
| 241 | while (device_list) { | ||
| 242 | acpi_power_on_device(device_list->device); | ||
| 243 | |||
| 244 | device_list = device_list->next; | ||
| 245 | } | ||
| 246 | |||
| 247 | return 0; | 241 | return 0; |
| 248 | } | 242 | } |
| 249 | 243 | ||
| 250 | static int acpi_power_on(acpi_handle handle) | 244 | static int acpi_power_on(acpi_handle handle) |
| 251 | { | 245 | { |
| 252 | int result = 0; | 246 | int result = 0; |
| 247 | bool resume_device = false; | ||
| 253 | struct acpi_power_resource *resource = NULL; | 248 | struct acpi_power_resource *resource = NULL; |
| 249 | struct acpi_power_resource_device *device_list; | ||
| 254 | 250 | ||
| 255 | result = acpi_power_get_context(handle, &resource); | 251 | result = acpi_power_get_context(handle, &resource); |
| 256 | if (result) | 252 | if (result) |
| @@ -266,10 +262,25 @@ static int acpi_power_on(acpi_handle handle) | |||
| 266 | result = __acpi_power_on(resource); | 262 | result = __acpi_power_on(resource); |
| 267 | if (result) | 263 | if (result) |
| 268 | resource->ref_count--; | 264 | resource->ref_count--; |
| 265 | else | ||
| 266 | resume_device = true; | ||
| 269 | } | 267 | } |
| 270 | 268 | ||
| 271 | mutex_unlock(&resource->resource_lock); | 269 | mutex_unlock(&resource->resource_lock); |
| 272 | 270 | ||
| 271 | if (!resume_device) | ||
| 272 | return result; | ||
| 273 | |||
| 274 | mutex_lock(&resource->devices_lock); | ||
| 275 | |||
| 276 | device_list = resource->devices; | ||
| 277 | while (device_list) { | ||
| 278 | acpi_power_on_device(device_list->device); | ||
| 279 | device_list = device_list->next; | ||
| 280 | } | ||
| 281 | |||
| 282 | mutex_unlock(&resource->devices_lock); | ||
| 283 | |||
| 273 | return result; | 284 | return result; |
| 274 | } | 285 | } |
| 275 | 286 | ||
| @@ -355,7 +366,7 @@ static void __acpi_power_resource_unregister_device(struct device *dev, | |||
| 355 | if (acpi_power_get_context(res_handle, &resource)) | 366 | if (acpi_power_get_context(res_handle, &resource)) |
| 356 | return; | 367 | return; |
| 357 | 368 | ||
| 358 | mutex_lock(&resource->resource_lock); | 369 | mutex_lock(&resource->devices_lock); |
| 359 | prev = NULL; | 370 | prev = NULL; |
| 360 | curr = resource->devices; | 371 | curr = resource->devices; |
| 361 | while (curr) { | 372 | while (curr) { |
| @@ -372,7 +383,7 @@ static void __acpi_power_resource_unregister_device(struct device *dev, | |||
| 372 | prev = curr; | 383 | prev = curr; |
| 373 | curr = curr->next; | 384 | curr = curr->next; |
| 374 | } | 385 | } |
| 375 | mutex_unlock(&resource->resource_lock); | 386 | mutex_unlock(&resource->devices_lock); |
| 376 | } | 387 | } |
| 377 | 388 | ||
| 378 | /* Unlink dev from all power resources in _PR0 */ | 389 | /* Unlink dev from all power resources in _PR0 */ |
| @@ -414,10 +425,10 @@ static int __acpi_power_resource_register_device( | |||
| 414 | 425 | ||
| 415 | power_resource_device->device = powered_device; | 426 | power_resource_device->device = powered_device; |
| 416 | 427 | ||
| 417 | mutex_lock(&resource->resource_lock); | 428 | mutex_lock(&resource->devices_lock); |
| 418 | power_resource_device->next = resource->devices; | 429 | power_resource_device->next = resource->devices; |
| 419 | resource->devices = power_resource_device; | 430 | resource->devices = power_resource_device; |
| 420 | mutex_unlock(&resource->resource_lock); | 431 | mutex_unlock(&resource->devices_lock); |
| 421 | 432 | ||
| 422 | return 0; | 433 | return 0; |
| 423 | } | 434 | } |
| @@ -462,7 +473,7 @@ int acpi_power_resource_register_device(struct device *dev, acpi_handle handle) | |||
| 462 | return ret; | 473 | return ret; |
| 463 | 474 | ||
| 464 | no_power_resource: | 475 | no_power_resource: |
| 465 | printk(KERN_WARNING PREFIX "Invalid Power Resource to register!"); | 476 | printk(KERN_DEBUG PREFIX "Invalid Power Resource to register!"); |
| 466 | return -ENODEV; | 477 | return -ENODEV; |
| 467 | } | 478 | } |
| 468 | EXPORT_SYMBOL_GPL(acpi_power_resource_register_device); | 479 | EXPORT_SYMBOL_GPL(acpi_power_resource_register_device); |
| @@ -721,6 +732,7 @@ static int acpi_power_add(struct acpi_device *device) | |||
| 721 | 732 | ||
| 722 | resource->device = device; | 733 | resource->device = device; |
| 723 | mutex_init(&resource->resource_lock); | 734 | mutex_init(&resource->resource_lock); |
| 735 | mutex_init(&resource->devices_lock); | ||
| 724 | strcpy(resource->name, device->pnp.bus_id); | 736 | strcpy(resource->name, device->pnp.bus_id); |
| 725 | strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); | 737 | strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); |
| 726 | strcpy(acpi_device_class(device), ACPI_POWER_CLASS); | 738 | strcpy(acpi_device_class(device), ACPI_POWER_CLASS); |
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 50d5dea0ff59..7862d17976b7 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
| @@ -268,6 +268,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { | |||
| 268 | /* JMicron 360/1/3/5/6, match class to avoid IDE function */ | 268 | /* JMicron 360/1/3/5/6, match class to avoid IDE function */ |
| 269 | { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, | 269 | { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, |
| 270 | PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr }, | 270 | PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr }, |
| 271 | /* JMicron 362B and 362C have an AHCI function with IDE class code */ | ||
| 272 | { PCI_VDEVICE(JMICRON, 0x2362), board_ahci_ign_iferr }, | ||
| 273 | { PCI_VDEVICE(JMICRON, 0x236f), board_ahci_ign_iferr }, | ||
| 271 | 274 | ||
| 272 | /* ATI */ | 275 | /* ATI */ |
| 273 | { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */ | 276 | { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */ |
| @@ -393,6 +396,8 @@ static const struct pci_device_id ahci_pci_tbl[] = { | |||
| 393 | .driver_data = board_ahci_yes_fbs }, /* 88se9125 */ | 396 | .driver_data = board_ahci_yes_fbs }, /* 88se9125 */ |
| 394 | { PCI_DEVICE(0x1b4b, 0x917a), | 397 | { PCI_DEVICE(0x1b4b, 0x917a), |
| 395 | .driver_data = board_ahci_yes_fbs }, /* 88se9172 */ | 398 | .driver_data = board_ahci_yes_fbs }, /* 88se9172 */ |
| 399 | { PCI_DEVICE(0x1b4b, 0x9192), | ||
| 400 | .driver_data = board_ahci_yes_fbs }, /* 88se9172 on some Gigabyte */ | ||
| 396 | { PCI_DEVICE(0x1b4b, 0x91a3), | 401 | { PCI_DEVICE(0x1b4b, 0x91a3), |
| 397 | .driver_data = board_ahci_yes_fbs }, | 402 | .driver_data = board_ahci_yes_fbs }, |
| 398 | 403 | ||
| @@ -400,7 +405,10 @@ static const struct pci_device_id ahci_pci_tbl[] = { | |||
| 400 | { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */ | 405 | { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */ |
| 401 | 406 | ||
| 402 | /* Asmedia */ | 407 | /* Asmedia */ |
| 403 | { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1061 */ | 408 | { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci }, /* ASM1060 */ |
| 409 | { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci }, /* ASM1060 */ | ||
| 410 | { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */ | ||
| 411 | { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ | ||
| 404 | 412 | ||
| 405 | /* Generic, PCI class code for AHCI */ | 413 | /* Generic, PCI class code for AHCI */ |
| 406 | { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, | 414 | { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, |
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index a89734621e51..5b6b1d8e6cc0 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c | |||
| @@ -16,12 +16,14 @@ | |||
| 16 | #include <linux/irq.h> | 16 | #include <linux/irq.h> |
| 17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
| 18 | #include <linux/irqdomain.h> | 18 | #include <linux/irqdomain.h> |
| 19 | #include <linux/pm_runtime.h> | ||
| 19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
| 20 | 21 | ||
| 21 | #include "internal.h" | 22 | #include "internal.h" |
| 22 | 23 | ||
| 23 | struct regmap_irq_chip_data { | 24 | struct regmap_irq_chip_data { |
| 24 | struct mutex lock; | 25 | struct mutex lock; |
| 26 | struct irq_chip irq_chip; | ||
| 25 | 27 | ||
| 26 | struct regmap *map; | 28 | struct regmap *map; |
| 27 | const struct regmap_irq_chip *chip; | 29 | const struct regmap_irq_chip *chip; |
| @@ -59,6 +61,14 @@ static void regmap_irq_sync_unlock(struct irq_data *data) | |||
| 59 | struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); | 61 | struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); |
| 60 | struct regmap *map = d->map; | 62 | struct regmap *map = d->map; |
| 61 | int i, ret; | 63 | int i, ret; |
| 64 | u32 reg; | ||
| 65 | |||
| 66 | if (d->chip->runtime_pm) { | ||
| 67 | ret = pm_runtime_get_sync(map->dev); | ||
| 68 | if (ret < 0) | ||
| 69 | dev_err(map->dev, "IRQ sync failed to resume: %d\n", | ||
| 70 | ret); | ||
| 71 | } | ||
| 62 | 72 | ||
| 63 | /* | 73 | /* |
| 64 | * If there's been a change in the mask write it back to the | 74 | * If there's been a change in the mask write it back to the |
| @@ -66,15 +76,22 @@ static void regmap_irq_sync_unlock(struct irq_data *data) | |||
| 66 | * suppress pointless writes. | 76 | * suppress pointless writes. |
| 67 | */ | 77 | */ |
| 68 | for (i = 0; i < d->chip->num_regs; i++) { | 78 | for (i = 0; i < d->chip->num_regs; i++) { |
| 69 | ret = regmap_update_bits(d->map, d->chip->mask_base + | 79 | reg = d->chip->mask_base + |
| 70 | (i * map->reg_stride * | 80 | (i * map->reg_stride * d->irq_reg_stride); |
| 71 | d->irq_reg_stride), | 81 | if (d->chip->mask_invert) |
| 82 | ret = regmap_update_bits(d->map, reg, | ||
| 83 | d->mask_buf_def[i], ~d->mask_buf[i]); | ||
| 84 | else | ||
| 85 | ret = regmap_update_bits(d->map, reg, | ||
| 72 | d->mask_buf_def[i], d->mask_buf[i]); | 86 | d->mask_buf_def[i], d->mask_buf[i]); |
| 73 | if (ret != 0) | 87 | if (ret != 0) |
| 74 | dev_err(d->map->dev, "Failed to sync masks in %x\n", | 88 | dev_err(d->map->dev, "Failed to sync masks in %x\n", |
| 75 | d->chip->mask_base + (i * map->reg_stride)); | 89 | reg); |
| 76 | } | 90 | } |
| 77 | 91 | ||
| 92 | if (d->chip->runtime_pm) | ||
| 93 | pm_runtime_put(map->dev); | ||
| 94 | |||
| 78 | /* If we've changed our wakeup count propagate it to the parent */ | 95 | /* If we've changed our wakeup count propagate it to the parent */ |
| 79 | if (d->wake_count < 0) | 96 | if (d->wake_count < 0) |
| 80 | for (i = d->wake_count; i < 0; i++) | 97 | for (i = d->wake_count; i < 0; i++) |
| @@ -128,8 +145,7 @@ static int regmap_irq_set_wake(struct irq_data *data, unsigned int on) | |||
| 128 | return 0; | 145 | return 0; |
| 129 | } | 146 | } |
| 130 | 147 | ||
| 131 | static struct irq_chip regmap_irq_chip = { | 148 | static const struct irq_chip regmap_irq_chip = { |
| 132 | .name = "regmap", | ||
| 133 | .irq_bus_lock = regmap_irq_lock, | 149 | .irq_bus_lock = regmap_irq_lock, |
| 134 | .irq_bus_sync_unlock = regmap_irq_sync_unlock, | 150 | .irq_bus_sync_unlock = regmap_irq_sync_unlock, |
| 135 | .irq_disable = regmap_irq_disable, | 151 | .irq_disable = regmap_irq_disable, |
| @@ -144,6 +160,16 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) | |||
| 144 | struct regmap *map = data->map; | 160 | struct regmap *map = data->map; |
| 145 | int ret, i; | 161 | int ret, i; |
| 146 | bool handled = false; | 162 | bool handled = false; |
| 163 | u32 reg; | ||
| 164 | |||
| 165 | if (chip->runtime_pm) { | ||
| 166 | ret = pm_runtime_get_sync(map->dev); | ||
| 167 | if (ret < 0) { | ||
| 168 | dev_err(map->dev, "IRQ thread failed to resume: %d\n", | ||
| 169 | ret); | ||
| 170 | return IRQ_NONE; | ||
| 171 | } | ||
| 172 | } | ||
| 147 | 173 | ||
| 148 | /* | 174 | /* |
| 149 | * Ignore masked IRQs and ack if we need to; we ack early so | 175 | * Ignore masked IRQs and ack if we need to; we ack early so |
| @@ -160,20 +186,20 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) | |||
| 160 | if (ret != 0) { | 186 | if (ret != 0) { |
| 161 | dev_err(map->dev, "Failed to read IRQ status: %d\n", | 187 | dev_err(map->dev, "Failed to read IRQ status: %d\n", |
| 162 | ret); | 188 | ret); |
| 189 | if (chip->runtime_pm) | ||
| 190 | pm_runtime_put(map->dev); | ||
| 163 | return IRQ_NONE; | 191 | return IRQ_NONE; |
| 164 | } | 192 | } |
| 165 | 193 | ||
| 166 | data->status_buf[i] &= ~data->mask_buf[i]; | 194 | data->status_buf[i] &= ~data->mask_buf[i]; |
| 167 | 195 | ||
| 168 | if (data->status_buf[i] && chip->ack_base) { | 196 | if (data->status_buf[i] && chip->ack_base) { |
| 169 | ret = regmap_write(map, chip->ack_base + | 197 | reg = chip->ack_base + |
| 170 | (i * map->reg_stride * | 198 | (i * map->reg_stride * data->irq_reg_stride); |
| 171 | data->irq_reg_stride), | 199 | ret = regmap_write(map, reg, data->status_buf[i]); |
| 172 | data->status_buf[i]); | ||
| 173 | if (ret != 0) | 200 | if (ret != 0) |
| 174 | dev_err(map->dev, "Failed to ack 0x%x: %d\n", | 201 | dev_err(map->dev, "Failed to ack 0x%x: %d\n", |
| 175 | chip->ack_base + (i * map->reg_stride), | 202 | reg, ret); |
| 176 | ret); | ||
| 177 | } | 203 | } |
| 178 | } | 204 | } |
| 179 | 205 | ||
| @@ -185,6 +211,9 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) | |||
| 185 | } | 211 | } |
| 186 | } | 212 | } |
| 187 | 213 | ||
| 214 | if (chip->runtime_pm) | ||
| 215 | pm_runtime_put(map->dev); | ||
| 216 | |||
| 188 | if (handled) | 217 | if (handled) |
| 189 | return IRQ_HANDLED; | 218 | return IRQ_HANDLED; |
| 190 | else | 219 | else |
| @@ -197,7 +226,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq, | |||
| 197 | struct regmap_irq_chip_data *data = h->host_data; | 226 | struct regmap_irq_chip_data *data = h->host_data; |
| 198 | 227 | ||
| 199 | irq_set_chip_data(virq, data); | 228 | irq_set_chip_data(virq, data); |
| 200 | irq_set_chip_and_handler(virq, ®map_irq_chip, handle_edge_irq); | 229 | irq_set_chip(virq, &data->irq_chip); |
| 201 | irq_set_nested_thread(virq, 1); | 230 | irq_set_nested_thread(virq, 1); |
| 202 | 231 | ||
| 203 | /* ARM needs us to explicitly flag the IRQ as valid | 232 | /* ARM needs us to explicitly flag the IRQ as valid |
| @@ -238,6 +267,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
| 238 | struct regmap_irq_chip_data *d; | 267 | struct regmap_irq_chip_data *d; |
| 239 | int i; | 268 | int i; |
| 240 | int ret = -ENOMEM; | 269 | int ret = -ENOMEM; |
| 270 | u32 reg; | ||
| 241 | 271 | ||
| 242 | for (i = 0; i < chip->num_irqs; i++) { | 272 | for (i = 0; i < chip->num_irqs; i++) { |
| 243 | if (chip->irqs[i].reg_offset % map->reg_stride) | 273 | if (chip->irqs[i].reg_offset % map->reg_stride) |
| @@ -284,6 +314,13 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
| 284 | goto err_alloc; | 314 | goto err_alloc; |
| 285 | } | 315 | } |
| 286 | 316 | ||
| 317 | d->irq_chip = regmap_irq_chip; | ||
| 318 | d->irq_chip.name = chip->name; | ||
| 319 | if (!chip->wake_base) { | ||
| 320 | d->irq_chip.irq_set_wake = NULL; | ||
| 321 | d->irq_chip.flags |= IRQCHIP_MASK_ON_SUSPEND | | ||
| 322 | IRQCHIP_SKIP_SET_WAKE; | ||
| 323 | } | ||
| 287 | d->irq = irq; | 324 | d->irq = irq; |
| 288 | d->map = map; | 325 | d->map = map; |
| 289 | d->chip = chip; | 326 | d->chip = chip; |
| @@ -303,16 +340,37 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
| 303 | /* Mask all the interrupts by default */ | 340 | /* Mask all the interrupts by default */ |
| 304 | for (i = 0; i < chip->num_regs; i++) { | 341 | for (i = 0; i < chip->num_regs; i++) { |
| 305 | d->mask_buf[i] = d->mask_buf_def[i]; | 342 | d->mask_buf[i] = d->mask_buf_def[i]; |
| 306 | ret = regmap_write(map, chip->mask_base + (i * map->reg_stride | 343 | reg = chip->mask_base + |
| 307 | * d->irq_reg_stride), | 344 | (i * map->reg_stride * d->irq_reg_stride); |
| 308 | d->mask_buf[i]); | 345 | if (chip->mask_invert) |
| 346 | ret = regmap_update_bits(map, reg, | ||
| 347 | d->mask_buf[i], ~d->mask_buf[i]); | ||
| 348 | else | ||
| 349 | ret = regmap_update_bits(map, reg, | ||
| 350 | d->mask_buf[i], d->mask_buf[i]); | ||
| 309 | if (ret != 0) { | 351 | if (ret != 0) { |
| 310 | dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", | 352 | dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", |
| 311 | chip->mask_base + (i * map->reg_stride), ret); | 353 | reg, ret); |
| 312 | goto err_alloc; | 354 | goto err_alloc; |
| 313 | } | 355 | } |
| 314 | } | 356 | } |
| 315 | 357 | ||
| 358 | /* Wake is disabled by default */ | ||
| 359 | if (d->wake_buf) { | ||
| 360 | for (i = 0; i < chip->num_regs; i++) { | ||
| 361 | d->wake_buf[i] = d->mask_buf_def[i]; | ||
| 362 | reg = chip->wake_base + | ||
| 363 | (i * map->reg_stride * d->irq_reg_stride); | ||
| 364 | ret = regmap_update_bits(map, reg, d->wake_buf[i], | ||
| 365 | d->wake_buf[i]); | ||
| 366 | if (ret != 0) { | ||
| 367 | dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", | ||
| 368 | reg, ret); | ||
| 369 | goto err_alloc; | ||
| 370 | } | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 316 | if (irq_base) | 374 | if (irq_base) |
| 317 | d->domain = irq_domain_add_legacy(map->dev->of_node, | 375 | d->domain = irq_domain_add_legacy(map->dev->of_node, |
| 318 | chip->num_irqs, irq_base, 0, | 376 | chip->num_irqs, irq_base, 0, |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index c241ae2f2f10..52069d29ff12 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
| @@ -659,13 +659,12 @@ EXPORT_SYMBOL_GPL(devm_regmap_init); | |||
| 659 | * new cache. This can be used to restore the cache to defaults or to | 659 | * new cache. This can be used to restore the cache to defaults or to |
| 660 | * update the cache configuration to reflect runtime discovery of the | 660 | * update the cache configuration to reflect runtime discovery of the |
| 661 | * hardware. | 661 | * hardware. |
| 662 | * | ||
| 663 | * No explicit locking is done here, the user needs to ensure that | ||
| 664 | * this function will not race with other calls to regmap. | ||
| 662 | */ | 665 | */ |
| 663 | int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) | 666 | int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) |
| 664 | { | 667 | { |
| 665 | int ret; | ||
| 666 | |||
| 667 | map->lock(map); | ||
| 668 | |||
| 669 | regcache_exit(map); | 668 | regcache_exit(map); |
| 670 | regmap_debugfs_exit(map); | 669 | regmap_debugfs_exit(map); |
| 671 | 670 | ||
| @@ -681,11 +680,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) | |||
| 681 | map->cache_bypass = false; | 680 | map->cache_bypass = false; |
| 682 | map->cache_only = false; | 681 | map->cache_only = false; |
| 683 | 682 | ||
| 684 | ret = regcache_init(map, config); | 683 | return regcache_init(map, config); |
| 685 | |||
| 686 | map->unlock(map); | ||
| 687 | |||
| 688 | return ret; | ||
| 689 | } | 684 | } |
| 690 | EXPORT_SYMBOL_GPL(regmap_reinit_cache); | 685 | EXPORT_SYMBOL_GPL(regmap_reinit_cache); |
| 691 | 686 | ||
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index de0435e63b02..887f68f6d79a 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c | |||
| @@ -35,6 +35,7 @@ new_skb(ulong len) | |||
| 35 | skb_reset_mac_header(skb); | 35 | skb_reset_mac_header(skb); |
| 36 | skb_reset_network_header(skb); | 36 | skb_reset_network_header(skb); |
| 37 | skb->protocol = __constant_htons(ETH_P_AOE); | 37 | skb->protocol = __constant_htons(ETH_P_AOE); |
| 38 | skb_checksum_none_assert(skb); | ||
| 38 | } | 39 | } |
| 39 | return skb; | 40 | return skb; |
| 40 | } | 41 | } |
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 38aa6dda6b81..da3311129a0c 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c | |||
| @@ -795,6 +795,7 @@ static void complete_scsi_command(CommandList_struct *c, int timeout, | |||
| 795 | } | 795 | } |
| 796 | break; | 796 | break; |
| 797 | case CMD_PROTOCOL_ERR: | 797 | case CMD_PROTOCOL_ERR: |
| 798 | cmd->result = DID_ERROR << 16; | ||
| 798 | dev_warn(&h->pdev->dev, | 799 | dev_warn(&h->pdev->dev, |
| 799 | "%p has protocol error\n", c); | 800 | "%p has protocol error\n", c); |
| 800 | break; | 801 | break; |
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index a8fddeb3d638..f946d31d6917 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c | |||
| @@ -1148,11 +1148,15 @@ static bool mtip_pause_ncq(struct mtip_port *port, | |||
| 1148 | reply = port->rxfis + RX_FIS_D2H_REG; | 1148 | reply = port->rxfis + RX_FIS_D2H_REG; |
| 1149 | task_file_data = readl(port->mmio+PORT_TFDATA); | 1149 | task_file_data = readl(port->mmio+PORT_TFDATA); |
| 1150 | 1150 | ||
| 1151 | if ((task_file_data & 1) || (fis->command == ATA_CMD_SEC_ERASE_UNIT)) | 1151 | if (fis->command == ATA_CMD_SEC_ERASE_UNIT) |
| 1152 | clear_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag); | ||
| 1153 | |||
| 1154 | if ((task_file_data & 1)) | ||
| 1152 | return false; | 1155 | return false; |
| 1153 | 1156 | ||
| 1154 | if (fis->command == ATA_CMD_SEC_ERASE_PREP) { | 1157 | if (fis->command == ATA_CMD_SEC_ERASE_PREP) { |
| 1155 | set_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags); | 1158 | set_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags); |
| 1159 | set_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag); | ||
| 1156 | port->ic_pause_timer = jiffies; | 1160 | port->ic_pause_timer = jiffies; |
| 1157 | return true; | 1161 | return true; |
| 1158 | } else if ((fis->command == ATA_CMD_DOWNLOAD_MICRO) && | 1162 | } else if ((fis->command == ATA_CMD_DOWNLOAD_MICRO) && |
| @@ -1900,7 +1904,7 @@ static int exec_drive_command(struct mtip_port *port, u8 *command, | |||
| 1900 | int rv = 0, xfer_sz = command[3]; | 1904 | int rv = 0, xfer_sz = command[3]; |
| 1901 | 1905 | ||
| 1902 | if (xfer_sz) { | 1906 | if (xfer_sz) { |
| 1903 | if (user_buffer) | 1907 | if (!user_buffer) |
| 1904 | return -EFAULT; | 1908 | return -EFAULT; |
| 1905 | 1909 | ||
| 1906 | buf = dmam_alloc_coherent(&port->dd->pdev->dev, | 1910 | buf = dmam_alloc_coherent(&port->dd->pdev->dev, |
| @@ -2043,7 +2047,7 @@ static void mtip_set_timeout(struct host_to_dev_fis *fis, unsigned int *timeout) | |||
| 2043 | *timeout = 240000; /* 4 minutes */ | 2047 | *timeout = 240000; /* 4 minutes */ |
| 2044 | break; | 2048 | break; |
| 2045 | case ATA_CMD_STANDBYNOW1: | 2049 | case ATA_CMD_STANDBYNOW1: |
| 2046 | *timeout = 10000; /* 10 seconds */ | 2050 | *timeout = 120000; /* 2 minutes */ |
| 2047 | break; | 2051 | break; |
| 2048 | case 0xF7: | 2052 | case 0xF7: |
| 2049 | case 0xFA: | 2053 | case 0xFA: |
| @@ -2588,9 +2592,6 @@ static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf, | |||
| 2588 | if (!len || size) | 2592 | if (!len || size) |
| 2589 | return 0; | 2593 | return 0; |
| 2590 | 2594 | ||
| 2591 | if (size < 0) | ||
| 2592 | return -EINVAL; | ||
| 2593 | |||
| 2594 | size += sprintf(&buf[size], "H/ S ACTive : [ 0x"); | 2595 | size += sprintf(&buf[size], "H/ S ACTive : [ 0x"); |
| 2595 | 2596 | ||
| 2596 | for (n = dd->slot_groups-1; n >= 0; n--) | 2597 | for (n = dd->slot_groups-1; n >= 0; n--) |
| @@ -2660,9 +2661,6 @@ static ssize_t mtip_hw_read_flags(struct file *f, char __user *ubuf, | |||
| 2660 | if (!len || size) | 2661 | if (!len || size) |
| 2661 | return 0; | 2662 | return 0; |
| 2662 | 2663 | ||
| 2663 | if (size < 0) | ||
| 2664 | return -EINVAL; | ||
| 2665 | |||
| 2666 | size += sprintf(&buf[size], "Flag-port : [ %08lX ]\n", | 2664 | size += sprintf(&buf[size], "Flag-port : [ %08lX ]\n", |
| 2667 | dd->port->flags); | 2665 | dd->port->flags); |
| 2668 | size += sprintf(&buf[size], "Flag-dd : [ %08lX ]\n", | 2666 | size += sprintf(&buf[size], "Flag-dd : [ %08lX ]\n", |
| @@ -3214,8 +3212,8 @@ static int mtip_hw_init(struct driver_data *dd) | |||
| 3214 | "Unable to check write protect progress\n"); | 3212 | "Unable to check write protect progress\n"); |
| 3215 | else | 3213 | else |
| 3216 | dev_info(&dd->pdev->dev, | 3214 | dev_info(&dd->pdev->dev, |
| 3217 | "Write protect progress: %d%% (%d blocks)\n", | 3215 | "Write protect progress: %u%% (%u blocks)\n", |
| 3218 | attr242.cur, attr242.data); | 3216 | attr242.cur, le32_to_cpu(attr242.data)); |
| 3219 | return rv; | 3217 | return rv; |
| 3220 | 3218 | ||
| 3221 | out3: | 3219 | out3: |
| @@ -3619,6 +3617,10 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) | |||
| 3619 | bio_endio(bio, -ENODATA); | 3617 | bio_endio(bio, -ENODATA); |
| 3620 | return; | 3618 | return; |
| 3621 | } | 3619 | } |
| 3620 | if (unlikely(test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag))) { | ||
| 3621 | bio_endio(bio, -ENODATA); | ||
| 3622 | return; | ||
| 3623 | } | ||
| 3622 | } | 3624 | } |
| 3623 | 3625 | ||
| 3624 | if (unlikely(!bio_has_data(bio))) { | 3626 | if (unlikely(!bio_has_data(bio))) { |
| @@ -4168,7 +4170,13 @@ static void mtip_pci_shutdown(struct pci_dev *pdev) | |||
| 4168 | 4170 | ||
| 4169 | /* Table of device ids supported by this driver. */ | 4171 | /* Table of device ids supported by this driver. */ |
| 4170 | static DEFINE_PCI_DEVICE_TABLE(mtip_pci_tbl) = { | 4172 | static DEFINE_PCI_DEVICE_TABLE(mtip_pci_tbl) = { |
| 4171 | { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320_DEVICE_ID) }, | 4173 | { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320H_DEVICE_ID) }, |
| 4174 | { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320M_DEVICE_ID) }, | ||
| 4175 | { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320S_DEVICE_ID) }, | ||
| 4176 | { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P325M_DEVICE_ID) }, | ||
| 4177 | { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P420H_DEVICE_ID) }, | ||
| 4178 | { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P420M_DEVICE_ID) }, | ||
| 4179 | { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P425M_DEVICE_ID) }, | ||
| 4172 | { 0 } | 4180 | { 0 } |
| 4173 | }; | 4181 | }; |
| 4174 | 4182 | ||
| @@ -4199,12 +4207,12 @@ static int __init mtip_init(void) | |||
| 4199 | { | 4207 | { |
| 4200 | int error; | 4208 | int error; |
| 4201 | 4209 | ||
| 4202 | printk(KERN_INFO MTIP_DRV_NAME " Version " MTIP_DRV_VERSION "\n"); | 4210 | pr_info(MTIP_DRV_NAME " Version " MTIP_DRV_VERSION "\n"); |
| 4203 | 4211 | ||
| 4204 | /* Allocate a major block device number to use with this driver. */ | 4212 | /* Allocate a major block device number to use with this driver. */ |
| 4205 | error = register_blkdev(0, MTIP_DRV_NAME); | 4213 | error = register_blkdev(0, MTIP_DRV_NAME); |
| 4206 | if (error <= 0) { | 4214 | if (error <= 0) { |
| 4207 | printk(KERN_ERR "Unable to register block device (%d)\n", | 4215 | pr_err("Unable to register block device (%d)\n", |
| 4208 | error); | 4216 | error); |
| 4209 | return -EBUSY; | 4217 | return -EBUSY; |
| 4210 | } | 4218 | } |
| @@ -4213,7 +4221,7 @@ static int __init mtip_init(void) | |||
| 4213 | if (!dfs_parent) { | 4221 | if (!dfs_parent) { |
| 4214 | dfs_parent = debugfs_create_dir("rssd", NULL); | 4222 | dfs_parent = debugfs_create_dir("rssd", NULL); |
| 4215 | if (IS_ERR_OR_NULL(dfs_parent)) { | 4223 | if (IS_ERR_OR_NULL(dfs_parent)) { |
| 4216 | printk(KERN_WARNING "Error creating debugfs parent\n"); | 4224 | pr_warn("Error creating debugfs parent\n"); |
| 4217 | dfs_parent = NULL; | 4225 | dfs_parent = NULL; |
| 4218 | } | 4226 | } |
| 4219 | } | 4227 | } |
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index f51fc23d17bb..18627a1d04c5 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h | |||
| @@ -76,7 +76,13 @@ | |||
| 76 | 76 | ||
| 77 | /* Micron Vendor ID & P320x SSD Device ID */ | 77 | /* Micron Vendor ID & P320x SSD Device ID */ |
| 78 | #define PCI_VENDOR_ID_MICRON 0x1344 | 78 | #define PCI_VENDOR_ID_MICRON 0x1344 |
| 79 | #define P320_DEVICE_ID 0x5150 | 79 | #define P320H_DEVICE_ID 0x5150 |
| 80 | #define P320M_DEVICE_ID 0x5151 | ||
| 81 | #define P320S_DEVICE_ID 0x5152 | ||
| 82 | #define P325M_DEVICE_ID 0x5153 | ||
| 83 | #define P420H_DEVICE_ID 0x5160 | ||
| 84 | #define P420M_DEVICE_ID 0x5161 | ||
| 85 | #define P425M_DEVICE_ID 0x5163 | ||
| 80 | 86 | ||
| 81 | /* Driver name and version strings */ | 87 | /* Driver name and version strings */ |
| 82 | #define MTIP_DRV_NAME "mtip32xx" | 88 | #define MTIP_DRV_NAME "mtip32xx" |
| @@ -131,10 +137,12 @@ enum { | |||
| 131 | MTIP_PF_SVC_THD_STOP_BIT = 8, | 137 | MTIP_PF_SVC_THD_STOP_BIT = 8, |
| 132 | 138 | ||
| 133 | /* below are bit numbers in 'dd_flag' defined in driver_data */ | 139 | /* below are bit numbers in 'dd_flag' defined in driver_data */ |
| 140 | MTIP_DDF_SEC_LOCK_BIT = 0, | ||
| 134 | MTIP_DDF_REMOVE_PENDING_BIT = 1, | 141 | MTIP_DDF_REMOVE_PENDING_BIT = 1, |
| 135 | MTIP_DDF_OVER_TEMP_BIT = 2, | 142 | MTIP_DDF_OVER_TEMP_BIT = 2, |
| 136 | MTIP_DDF_WRITE_PROTECT_BIT = 3, | 143 | MTIP_DDF_WRITE_PROTECT_BIT = 3, |
| 137 | MTIP_DDF_STOP_IO = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) | \ | 144 | MTIP_DDF_STOP_IO = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) | \ |
| 145 | (1 << MTIP_DDF_SEC_LOCK_BIT) | \ | ||
| 138 | (1 << MTIP_DDF_OVER_TEMP_BIT) | \ | 146 | (1 << MTIP_DDF_OVER_TEMP_BIT) | \ |
| 139 | (1 << MTIP_DDF_WRITE_PROTECT_BIT)), | 147 | (1 << MTIP_DDF_WRITE_PROTECT_BIT)), |
| 140 | 148 | ||
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index d07c9f7fded6..0c03411c59eb 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c | |||
| @@ -449,6 +449,14 @@ static void nbd_clear_que(struct nbd_device *nbd) | |||
| 449 | req->errors++; | 449 | req->errors++; |
| 450 | nbd_end_request(req); | 450 | nbd_end_request(req); |
| 451 | } | 451 | } |
| 452 | |||
| 453 | while (!list_empty(&nbd->waiting_queue)) { | ||
| 454 | req = list_entry(nbd->waiting_queue.next, struct request, | ||
| 455 | queuelist); | ||
| 456 | list_del_init(&req->queuelist); | ||
| 457 | req->errors++; | ||
| 458 | nbd_end_request(req); | ||
| 459 | } | ||
| 452 | } | 460 | } |
| 453 | 461 | ||
| 454 | 462 | ||
| @@ -598,6 +606,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, | |||
| 598 | nbd->file = NULL; | 606 | nbd->file = NULL; |
| 599 | nbd_clear_que(nbd); | 607 | nbd_clear_que(nbd); |
| 600 | BUG_ON(!list_empty(&nbd->queue_head)); | 608 | BUG_ON(!list_empty(&nbd->queue_head)); |
| 609 | BUG_ON(!list_empty(&nbd->waiting_queue)); | ||
| 601 | if (file) | 610 | if (file) |
| 602 | fput(file); | 611 | fput(file); |
| 603 | return 0; | 612 | return 0; |
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c index c95ca0f8ff84..931769e133e5 100644 --- a/drivers/block/nvme.c +++ b/drivers/block/nvme.c | |||
| @@ -79,6 +79,7 @@ struct nvme_dev { | |||
| 79 | char serial[20]; | 79 | char serial[20]; |
| 80 | char model[40]; | 80 | char model[40]; |
| 81 | char firmware_rev[8]; | 81 | char firmware_rev[8]; |
| 82 | u32 max_hw_sectors; | ||
| 82 | }; | 83 | }; |
| 83 | 84 | ||
| 84 | /* | 85 | /* |
| @@ -835,15 +836,15 @@ static int nvme_identify(struct nvme_dev *dev, unsigned nsid, unsigned cns, | |||
| 835 | } | 836 | } |
| 836 | 837 | ||
| 837 | static int nvme_get_features(struct nvme_dev *dev, unsigned fid, | 838 | static int nvme_get_features(struct nvme_dev *dev, unsigned fid, |
| 838 | unsigned dword11, dma_addr_t dma_addr) | 839 | unsigned nsid, dma_addr_t dma_addr) |
| 839 | { | 840 | { |
| 840 | struct nvme_command c; | 841 | struct nvme_command c; |
| 841 | 842 | ||
| 842 | memset(&c, 0, sizeof(c)); | 843 | memset(&c, 0, sizeof(c)); |
| 843 | c.features.opcode = nvme_admin_get_features; | 844 | c.features.opcode = nvme_admin_get_features; |
| 845 | c.features.nsid = cpu_to_le32(nsid); | ||
| 844 | c.features.prp1 = cpu_to_le64(dma_addr); | 846 | c.features.prp1 = cpu_to_le64(dma_addr); |
| 845 | c.features.fid = cpu_to_le32(fid); | 847 | c.features.fid = cpu_to_le32(fid); |
| 846 | c.features.dword11 = cpu_to_le32(dword11); | ||
| 847 | 848 | ||
| 848 | return nvme_submit_admin_cmd(dev, &c, NULL); | 849 | return nvme_submit_admin_cmd(dev, &c, NULL); |
| 849 | } | 850 | } |
| @@ -862,11 +863,51 @@ static int nvme_set_features(struct nvme_dev *dev, unsigned fid, | |||
| 862 | return nvme_submit_admin_cmd(dev, &c, result); | 863 | return nvme_submit_admin_cmd(dev, &c, result); |
| 863 | } | 864 | } |
| 864 | 865 | ||
| 866 | /** | ||
| 867 | * nvme_cancel_ios - Cancel outstanding I/Os | ||
| 868 | * @queue: The queue to cancel I/Os on | ||
| 869 | * @timeout: True to only cancel I/Os which have timed out | ||
| 870 | */ | ||
| 871 | static void nvme_cancel_ios(struct nvme_queue *nvmeq, bool timeout) | ||
| 872 | { | ||
| 873 | int depth = nvmeq->q_depth - 1; | ||
| 874 | struct nvme_cmd_info *info = nvme_cmd_info(nvmeq); | ||
| 875 | unsigned long now = jiffies; | ||
| 876 | int cmdid; | ||
| 877 | |||
| 878 | for_each_set_bit(cmdid, nvmeq->cmdid_data, depth) { | ||
| 879 | void *ctx; | ||
| 880 | nvme_completion_fn fn; | ||
| 881 | static struct nvme_completion cqe = { | ||
| 882 | .status = cpu_to_le16(NVME_SC_ABORT_REQ) << 1, | ||
| 883 | }; | ||
| 884 | |||
| 885 | if (timeout && !time_after(now, info[cmdid].timeout)) | ||
| 886 | continue; | ||
| 887 | dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d\n", cmdid); | ||
| 888 | ctx = cancel_cmdid(nvmeq, cmdid, &fn); | ||
| 889 | fn(nvmeq->dev, ctx, &cqe); | ||
| 890 | } | ||
| 891 | } | ||
| 892 | |||
| 893 | static void nvme_free_queue_mem(struct nvme_queue *nvmeq) | ||
| 894 | { | ||
| 895 | dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth), | ||
| 896 | (void *)nvmeq->cqes, nvmeq->cq_dma_addr); | ||
| 897 | dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth), | ||
| 898 | nvmeq->sq_cmds, nvmeq->sq_dma_addr); | ||
| 899 | kfree(nvmeq); | ||
| 900 | } | ||
| 901 | |||
| 865 | static void nvme_free_queue(struct nvme_dev *dev, int qid) | 902 | static void nvme_free_queue(struct nvme_dev *dev, int qid) |
| 866 | { | 903 | { |
| 867 | struct nvme_queue *nvmeq = dev->queues[qid]; | 904 | struct nvme_queue *nvmeq = dev->queues[qid]; |
| 868 | int vector = dev->entry[nvmeq->cq_vector].vector; | 905 | int vector = dev->entry[nvmeq->cq_vector].vector; |
| 869 | 906 | ||
| 907 | spin_lock_irq(&nvmeq->q_lock); | ||
| 908 | nvme_cancel_ios(nvmeq, false); | ||
| 909 | spin_unlock_irq(&nvmeq->q_lock); | ||
| 910 | |||
| 870 | irq_set_affinity_hint(vector, NULL); | 911 | irq_set_affinity_hint(vector, NULL); |
| 871 | free_irq(vector, nvmeq); | 912 | free_irq(vector, nvmeq); |
| 872 | 913 | ||
| @@ -876,18 +917,15 @@ static void nvme_free_queue(struct nvme_dev *dev, int qid) | |||
| 876 | adapter_delete_cq(dev, qid); | 917 | adapter_delete_cq(dev, qid); |
| 877 | } | 918 | } |
| 878 | 919 | ||
| 879 | dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth), | 920 | nvme_free_queue_mem(nvmeq); |
| 880 | (void *)nvmeq->cqes, nvmeq->cq_dma_addr); | ||
| 881 | dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth), | ||
| 882 | nvmeq->sq_cmds, nvmeq->sq_dma_addr); | ||
| 883 | kfree(nvmeq); | ||
| 884 | } | 921 | } |
| 885 | 922 | ||
| 886 | static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, | 923 | static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, |
| 887 | int depth, int vector) | 924 | int depth, int vector) |
| 888 | { | 925 | { |
| 889 | struct device *dmadev = &dev->pci_dev->dev; | 926 | struct device *dmadev = &dev->pci_dev->dev; |
| 890 | unsigned extra = (depth / 8) + (depth * sizeof(struct nvme_cmd_info)); | 927 | unsigned extra = DIV_ROUND_UP(depth, 8) + (depth * |
| 928 | sizeof(struct nvme_cmd_info)); | ||
| 891 | struct nvme_queue *nvmeq = kzalloc(sizeof(*nvmeq) + extra, GFP_KERNEL); | 929 | struct nvme_queue *nvmeq = kzalloc(sizeof(*nvmeq) + extra, GFP_KERNEL); |
| 892 | if (!nvmeq) | 930 | if (!nvmeq) |
| 893 | return NULL; | 931 | return NULL; |
| @@ -975,7 +1013,7 @@ static __devinit struct nvme_queue *nvme_create_queue(struct nvme_dev *dev, | |||
| 975 | 1013 | ||
| 976 | static int __devinit nvme_configure_admin_queue(struct nvme_dev *dev) | 1014 | static int __devinit nvme_configure_admin_queue(struct nvme_dev *dev) |
| 977 | { | 1015 | { |
| 978 | int result; | 1016 | int result = 0; |
| 979 | u32 aqa; | 1017 | u32 aqa; |
| 980 | u64 cap; | 1018 | u64 cap; |
| 981 | unsigned long timeout; | 1019 | unsigned long timeout; |
| @@ -1005,17 +1043,22 @@ static int __devinit nvme_configure_admin_queue(struct nvme_dev *dev) | |||
| 1005 | timeout = ((NVME_CAP_TIMEOUT(cap) + 1) * HZ / 2) + jiffies; | 1043 | timeout = ((NVME_CAP_TIMEOUT(cap) + 1) * HZ / 2) + jiffies; |
| 1006 | dev->db_stride = NVME_CAP_STRIDE(cap); | 1044 | dev->db_stride = NVME_CAP_STRIDE(cap); |
| 1007 | 1045 | ||
| 1008 | while (!(readl(&dev->bar->csts) & NVME_CSTS_RDY)) { | 1046 | while (!result && !(readl(&dev->bar->csts) & NVME_CSTS_RDY)) { |
| 1009 | msleep(100); | 1047 | msleep(100); |
| 1010 | if (fatal_signal_pending(current)) | 1048 | if (fatal_signal_pending(current)) |
| 1011 | return -EINTR; | 1049 | result = -EINTR; |
| 1012 | if (time_after(jiffies, timeout)) { | 1050 | if (time_after(jiffies, timeout)) { |
| 1013 | dev_err(&dev->pci_dev->dev, | 1051 | dev_err(&dev->pci_dev->dev, |
| 1014 | "Device not ready; aborting initialisation\n"); | 1052 | "Device not ready; aborting initialisation\n"); |
| 1015 | return -ENODEV; | 1053 | result = -ENODEV; |
| 1016 | } | 1054 | } |
| 1017 | } | 1055 | } |
| 1018 | 1056 | ||
| 1057 | if (result) { | ||
| 1058 | nvme_free_queue_mem(nvmeq); | ||
| 1059 | return result; | ||
| 1060 | } | ||
| 1061 | |||
| 1019 | result = queue_request_irq(dev, nvmeq, "nvme admin"); | 1062 | result = queue_request_irq(dev, nvmeq, "nvme admin"); |
| 1020 | dev->queues[0] = nvmeq; | 1063 | dev->queues[0] = nvmeq; |
| 1021 | return result; | 1064 | return result; |
| @@ -1037,6 +1080,8 @@ static struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write, | |||
| 1037 | offset = offset_in_page(addr); | 1080 | offset = offset_in_page(addr); |
| 1038 | count = DIV_ROUND_UP(offset + length, PAGE_SIZE); | 1081 | count = DIV_ROUND_UP(offset + length, PAGE_SIZE); |
| 1039 | pages = kcalloc(count, sizeof(*pages), GFP_KERNEL); | 1082 | pages = kcalloc(count, sizeof(*pages), GFP_KERNEL); |
| 1083 | if (!pages) | ||
| 1084 | return ERR_PTR(-ENOMEM); | ||
| 1040 | 1085 | ||
| 1041 | err = get_user_pages_fast(addr, count, 1, pages); | 1086 | err = get_user_pages_fast(addr, count, 1, pages); |
| 1042 | if (err < count) { | 1087 | if (err < count) { |
| @@ -1146,14 +1191,13 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) | |||
| 1146 | return status; | 1191 | return status; |
| 1147 | } | 1192 | } |
| 1148 | 1193 | ||
| 1149 | static int nvme_user_admin_cmd(struct nvme_ns *ns, | 1194 | static int nvme_user_admin_cmd(struct nvme_dev *dev, |
| 1150 | struct nvme_admin_cmd __user *ucmd) | 1195 | struct nvme_admin_cmd __user *ucmd) |
| 1151 | { | 1196 | { |
| 1152 | struct nvme_dev *dev = ns->dev; | ||
| 1153 | struct nvme_admin_cmd cmd; | 1197 | struct nvme_admin_cmd cmd; |
| 1154 | struct nvme_command c; | 1198 | struct nvme_command c; |
| 1155 | int status, length; | 1199 | int status, length; |
| 1156 | struct nvme_iod *iod; | 1200 | struct nvme_iod *uninitialized_var(iod); |
| 1157 | 1201 | ||
| 1158 | if (!capable(CAP_SYS_ADMIN)) | 1202 | if (!capable(CAP_SYS_ADMIN)) |
| 1159 | return -EACCES; | 1203 | return -EACCES; |
| @@ -1204,7 +1248,7 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, | |||
| 1204 | case NVME_IOCTL_ID: | 1248 | case NVME_IOCTL_ID: |
| 1205 | return ns->ns_id; | 1249 | return ns->ns_id; |
| 1206 | case NVME_IOCTL_ADMIN_CMD: | 1250 | case NVME_IOCTL_ADMIN_CMD: |
| 1207 | return nvme_user_admin_cmd(ns, (void __user *)arg); | 1251 | return nvme_user_admin_cmd(ns->dev, (void __user *)arg); |
| 1208 | case NVME_IOCTL_SUBMIT_IO: | 1252 | case NVME_IOCTL_SUBMIT_IO: |
| 1209 | return nvme_submit_io(ns, (void __user *)arg); | 1253 | return nvme_submit_io(ns, (void __user *)arg); |
| 1210 | default: | 1254 | default: |
| @@ -1218,26 +1262,6 @@ static const struct block_device_operations nvme_fops = { | |||
| 1218 | .compat_ioctl = nvme_ioctl, | 1262 | .compat_ioctl = nvme_ioctl, |
| 1219 | }; | 1263 | }; |
| 1220 | 1264 | ||
| 1221 | static void nvme_timeout_ios(struct nvme_queue *nvmeq) | ||
| 1222 | { | ||
| 1223 | int depth = nvmeq->q_depth - 1; | ||
| 1224 | struct nvme_cmd_info *info = nvme_cmd_info(nvmeq); | ||
| 1225 | unsigned long now = jiffies; | ||
| 1226 | int cmdid; | ||
| 1227 | |||
| 1228 | for_each_set_bit(cmdid, nvmeq->cmdid_data, depth) { | ||
| 1229 | void *ctx; | ||
| 1230 | nvme_completion_fn fn; | ||
| 1231 | static struct nvme_completion cqe = { .status = cpu_to_le16(NVME_SC_ABORT_REQ) << 1, }; | ||
| 1232 | |||
| 1233 | if (!time_after(now, info[cmdid].timeout)) | ||
| 1234 | continue; | ||
| 1235 | dev_warn(nvmeq->q_dmadev, "Timing out I/O %d\n", cmdid); | ||
| 1236 | ctx = cancel_cmdid(nvmeq, cmdid, &fn); | ||
| 1237 | fn(nvmeq->dev, ctx, &cqe); | ||
| 1238 | } | ||
| 1239 | } | ||
| 1240 | |||
| 1241 | static void nvme_resubmit_bios(struct nvme_queue *nvmeq) | 1265 | static void nvme_resubmit_bios(struct nvme_queue *nvmeq) |
| 1242 | { | 1266 | { |
| 1243 | while (bio_list_peek(&nvmeq->sq_cong)) { | 1267 | while (bio_list_peek(&nvmeq->sq_cong)) { |
| @@ -1269,7 +1293,7 @@ static int nvme_kthread(void *data) | |||
| 1269 | spin_lock_irq(&nvmeq->q_lock); | 1293 | spin_lock_irq(&nvmeq->q_lock); |
| 1270 | if (nvme_process_cq(nvmeq)) | 1294 | if (nvme_process_cq(nvmeq)) |
| 1271 | printk("process_cq did something\n"); | 1295 | printk("process_cq did something\n"); |
| 1272 | nvme_timeout_ios(nvmeq); | 1296 | nvme_cancel_ios(nvmeq, true); |
| 1273 | nvme_resubmit_bios(nvmeq); | 1297 | nvme_resubmit_bios(nvmeq); |
| 1274 | spin_unlock_irq(&nvmeq->q_lock); | 1298 | spin_unlock_irq(&nvmeq->q_lock); |
| 1275 | } | 1299 | } |
| @@ -1339,6 +1363,9 @@ static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, int nsid, | |||
| 1339 | ns->disk = disk; | 1363 | ns->disk = disk; |
| 1340 | lbaf = id->flbas & 0xf; | 1364 | lbaf = id->flbas & 0xf; |
| 1341 | ns->lba_shift = id->lbaf[lbaf].ds; | 1365 | ns->lba_shift = id->lbaf[lbaf].ds; |
| 1366 | blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift); | ||
| 1367 | if (dev->max_hw_sectors) | ||
| 1368 | blk_queue_max_hw_sectors(ns->queue, dev->max_hw_sectors); | ||
| 1342 | 1369 | ||
| 1343 | disk->major = nvme_major; | 1370 | disk->major = nvme_major; |
| 1344 | disk->minors = NVME_MINORS; | 1371 | disk->minors = NVME_MINORS; |
| @@ -1383,7 +1410,7 @@ static int set_queue_count(struct nvme_dev *dev, int count) | |||
| 1383 | 1410 | ||
| 1384 | static int __devinit nvme_setup_io_queues(struct nvme_dev *dev) | 1411 | static int __devinit nvme_setup_io_queues(struct nvme_dev *dev) |
| 1385 | { | 1412 | { |
| 1386 | int result, cpu, i, nr_io_queues, db_bar_size; | 1413 | int result, cpu, i, nr_io_queues, db_bar_size, q_depth; |
| 1387 | 1414 | ||
| 1388 | nr_io_queues = num_online_cpus(); | 1415 | nr_io_queues = num_online_cpus(); |
| 1389 | result = set_queue_count(dev, nr_io_queues); | 1416 | result = set_queue_count(dev, nr_io_queues); |
| @@ -1429,9 +1456,10 @@ static int __devinit nvme_setup_io_queues(struct nvme_dev *dev) | |||
| 1429 | cpu = cpumask_next(cpu, cpu_online_mask); | 1456 | cpu = cpumask_next(cpu, cpu_online_mask); |
| 1430 | } | 1457 | } |
| 1431 | 1458 | ||
| 1459 | q_depth = min_t(int, NVME_CAP_MQES(readq(&dev->bar->cap)) + 1, | ||
| 1460 | NVME_Q_DEPTH); | ||
| 1432 | for (i = 0; i < nr_io_queues; i++) { | 1461 | for (i = 0; i < nr_io_queues; i++) { |
| 1433 | dev->queues[i + 1] = nvme_create_queue(dev, i + 1, | 1462 | dev->queues[i + 1] = nvme_create_queue(dev, i + 1, q_depth, i); |
| 1434 | NVME_Q_DEPTH, i); | ||
| 1435 | if (IS_ERR(dev->queues[i + 1])) | 1463 | if (IS_ERR(dev->queues[i + 1])) |
| 1436 | return PTR_ERR(dev->queues[i + 1]); | 1464 | return PTR_ERR(dev->queues[i + 1]); |
| 1437 | dev->queue_count++; | 1465 | dev->queue_count++; |
| @@ -1480,6 +1508,10 @@ static int __devinit nvme_dev_add(struct nvme_dev *dev) | |||
| 1480 | memcpy(dev->serial, ctrl->sn, sizeof(ctrl->sn)); | 1508 | memcpy(dev->serial, ctrl->sn, sizeof(ctrl->sn)); |
| 1481 | memcpy(dev->model, ctrl->mn, sizeof(ctrl->mn)); | 1509 | memcpy(dev->model, ctrl->mn, sizeof(ctrl->mn)); |
| 1482 | memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr)); | 1510 | memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr)); |
| 1511 | if (ctrl->mdts) { | ||
| 1512 | int shift = NVME_CAP_MPSMIN(readq(&dev->bar->cap)) + 12; | ||
| 1513 | dev->max_hw_sectors = 1 << (ctrl->mdts + shift - 9); | ||
| 1514 | } | ||
| 1483 | 1515 | ||
| 1484 | id_ns = mem; | 1516 | id_ns = mem; |
| 1485 | for (i = 1; i <= nn; i++) { | 1517 | for (i = 1; i <= nn; i++) { |
| @@ -1523,8 +1555,6 @@ static int nvme_dev_remove(struct nvme_dev *dev) | |||
| 1523 | list_del(&dev->node); | 1555 | list_del(&dev->node); |
| 1524 | spin_unlock(&dev_list_lock); | 1556 | spin_unlock(&dev_list_lock); |
| 1525 | 1557 | ||
| 1526 | /* TODO: wait all I/O finished or cancel them */ | ||
| 1527 | |||
| 1528 | list_for_each_entry_safe(ns, next, &dev->namespaces, list) { | 1558 | list_for_each_entry_safe(ns, next, &dev->namespaces, list) { |
| 1529 | list_del(&ns->list); | 1559 | list_del(&ns->list); |
| 1530 | del_gendisk(ns->disk); | 1560 | del_gendisk(ns->disk); |
| @@ -1560,15 +1590,33 @@ static void nvme_release_prp_pools(struct nvme_dev *dev) | |||
| 1560 | dma_pool_destroy(dev->prp_small_pool); | 1590 | dma_pool_destroy(dev->prp_small_pool); |
| 1561 | } | 1591 | } |
| 1562 | 1592 | ||
| 1563 | /* XXX: Use an ida or something to let remove / add work correctly */ | 1593 | static DEFINE_IDA(nvme_instance_ida); |
| 1564 | static void nvme_set_instance(struct nvme_dev *dev) | 1594 | |
| 1595 | static int nvme_set_instance(struct nvme_dev *dev) | ||
| 1565 | { | 1596 | { |
| 1566 | static int instance; | 1597 | int instance, error; |
| 1567 | dev->instance = instance++; | 1598 | |
| 1599 | do { | ||
| 1600 | if (!ida_pre_get(&nvme_instance_ida, GFP_KERNEL)) | ||
| 1601 | return -ENODEV; | ||
| 1602 | |||
| 1603 | spin_lock(&dev_list_lock); | ||
| 1604 | error = ida_get_new(&nvme_instance_ida, &instance); | ||
| 1605 | spin_unlock(&dev_list_lock); | ||
| 1606 | } while (error == -EAGAIN); | ||
| 1607 | |||
| 1608 | if (error) | ||
| 1609 | return -ENODEV; | ||
| 1610 | |||
| 1611 | dev->instance = instance; | ||
| 1612 | return 0; | ||
| 1568 | } | 1613 | } |
| 1569 | 1614 | ||
| 1570 | static void nvme_release_instance(struct nvme_dev *dev) | 1615 | static void nvme_release_instance(struct nvme_dev *dev) |
| 1571 | { | 1616 | { |
| 1617 | spin_lock(&dev_list_lock); | ||
| 1618 | ida_remove(&nvme_instance_ida, dev->instance); | ||
| 1619 | spin_unlock(&dev_list_lock); | ||
| 1572 | } | 1620 | } |
| 1573 | 1621 | ||
| 1574 | static int __devinit nvme_probe(struct pci_dev *pdev, | 1622 | static int __devinit nvme_probe(struct pci_dev *pdev, |
| @@ -1601,7 +1649,10 @@ static int __devinit nvme_probe(struct pci_dev *pdev, | |||
| 1601 | pci_set_drvdata(pdev, dev); | 1649 | pci_set_drvdata(pdev, dev); |
| 1602 | dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); | 1650 | dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); |
| 1603 | dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); | 1651 | dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); |
| 1604 | nvme_set_instance(dev); | 1652 | result = nvme_set_instance(dev); |
| 1653 | if (result) | ||
| 1654 | goto disable; | ||
| 1655 | |||
| 1605 | dev->entry[0].vector = pdev->irq; | 1656 | dev->entry[0].vector = pdev->irq; |
| 1606 | 1657 | ||
| 1607 | result = nvme_setup_prp_pools(dev); | 1658 | result = nvme_setup_prp_pools(dev); |
| @@ -1704,15 +1755,17 @@ static struct pci_driver nvme_driver = { | |||
| 1704 | 1755 | ||
| 1705 | static int __init nvme_init(void) | 1756 | static int __init nvme_init(void) |
| 1706 | { | 1757 | { |
| 1707 | int result = -EBUSY; | 1758 | int result; |
| 1708 | 1759 | ||
| 1709 | nvme_thread = kthread_run(nvme_kthread, NULL, "nvme"); | 1760 | nvme_thread = kthread_run(nvme_kthread, NULL, "nvme"); |
| 1710 | if (IS_ERR(nvme_thread)) | 1761 | if (IS_ERR(nvme_thread)) |
| 1711 | return PTR_ERR(nvme_thread); | 1762 | return PTR_ERR(nvme_thread); |
| 1712 | 1763 | ||
| 1713 | nvme_major = register_blkdev(nvme_major, "nvme"); | 1764 | result = register_blkdev(nvme_major, "nvme"); |
| 1714 | if (nvme_major <= 0) | 1765 | if (result < 0) |
| 1715 | goto kill_kthread; | 1766 | goto kill_kthread; |
| 1767 | else if (result > 0) | ||
| 1768 | nvme_major = result; | ||
| 1716 | 1769 | ||
| 1717 | result = pci_register_driver(&nvme_driver); | 1770 | result = pci_register_driver(&nvme_driver); |
| 1718 | if (result) | 1771 | if (result) |
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 9917943a3572..54a55f03115d 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
| @@ -246,13 +246,12 @@ static int rbd_open(struct block_device *bdev, fmode_t mode) | |||
| 246 | { | 246 | { |
| 247 | struct rbd_device *rbd_dev = bdev->bd_disk->private_data; | 247 | struct rbd_device *rbd_dev = bdev->bd_disk->private_data; |
| 248 | 248 | ||
| 249 | rbd_get_dev(rbd_dev); | ||
| 250 | |||
| 251 | set_device_ro(bdev, rbd_dev->read_only); | ||
| 252 | |||
| 253 | if ((mode & FMODE_WRITE) && rbd_dev->read_only) | 249 | if ((mode & FMODE_WRITE) && rbd_dev->read_only) |
| 254 | return -EROFS; | 250 | return -EROFS; |
| 255 | 251 | ||
| 252 | rbd_get_dev(rbd_dev); | ||
| 253 | set_device_ro(bdev, rbd_dev->read_only); | ||
| 254 | |||
| 256 | return 0; | 255 | return 0; |
| 257 | } | 256 | } |
| 258 | 257 | ||
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 73f196ca713f..c6decb901e5e 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c | |||
| @@ -337,7 +337,7 @@ static void xen_blkbk_unmap(struct pending_req *req) | |||
| 337 | invcount++; | 337 | invcount++; |
| 338 | } | 338 | } |
| 339 | 339 | ||
| 340 | ret = gnttab_unmap_refs(unmap, pages, invcount, false); | 340 | ret = gnttab_unmap_refs(unmap, NULL, pages, invcount); |
| 341 | BUG_ON(ret); | 341 | BUG_ON(ret); |
| 342 | } | 342 | } |
| 343 | 343 | ||
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 11f36e502136..fc2de5528dcc 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c | |||
| @@ -86,6 +86,7 @@ static struct usb_device_id ath3k_table[] = { | |||
| 86 | 86 | ||
| 87 | /* Atheros AR5BBU22 with sflash firmware */ | 87 | /* Atheros AR5BBU22 with sflash firmware */ |
| 88 | { USB_DEVICE(0x0489, 0xE03C) }, | 88 | { USB_DEVICE(0x0489, 0xE03C) }, |
| 89 | { USB_DEVICE(0x0489, 0xE036) }, | ||
| 89 | 90 | ||
| 90 | { } /* Terminating entry */ | 91 | { } /* Terminating entry */ |
| 91 | }; | 92 | }; |
| @@ -109,6 +110,7 @@ static struct usb_device_id ath3k_blist_tbl[] = { | |||
| 109 | 110 | ||
| 110 | /* Atheros AR5BBU22 with sflash firmware */ | 111 | /* Atheros AR5BBU22 with sflash firmware */ |
| 111 | { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, | 112 | { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, |
| 113 | { USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 }, | ||
| 112 | 114 | ||
| 113 | { } /* Terminating entry */ | 115 | { } /* Terminating entry */ |
| 114 | }; | 116 | }; |
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index cef3bac1a543..654e248763ef 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c | |||
| @@ -52,6 +52,9 @@ static struct usb_device_id btusb_table[] = { | |||
| 52 | /* Generic Bluetooth USB device */ | 52 | /* Generic Bluetooth USB device */ |
| 53 | { USB_DEVICE_INFO(0xe0, 0x01, 0x01) }, | 53 | { USB_DEVICE_INFO(0xe0, 0x01, 0x01) }, |
| 54 | 54 | ||
| 55 | /* Apple-specific (Broadcom) devices */ | ||
| 56 | { USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01) }, | ||
| 57 | |||
| 55 | /* Broadcom SoftSailing reporting vendor specific */ | 58 | /* Broadcom SoftSailing reporting vendor specific */ |
| 56 | { USB_DEVICE(0x0a5c, 0x21e1) }, | 59 | { USB_DEVICE(0x0a5c, 0x21e1) }, |
| 57 | 60 | ||
| @@ -94,16 +97,14 @@ static struct usb_device_id btusb_table[] = { | |||
| 94 | 97 | ||
| 95 | /* Broadcom BCM20702A0 */ | 98 | /* Broadcom BCM20702A0 */ |
| 96 | { USB_DEVICE(0x0489, 0xe042) }, | 99 | { USB_DEVICE(0x0489, 0xe042) }, |
| 97 | { USB_DEVICE(0x0a5c, 0x21e3) }, | ||
| 98 | { USB_DEVICE(0x0a5c, 0x21e6) }, | ||
| 99 | { USB_DEVICE(0x0a5c, 0x21e8) }, | ||
| 100 | { USB_DEVICE(0x0a5c, 0x21f3) }, | ||
| 101 | { USB_DEVICE(0x0a5c, 0x21f4) }, | ||
| 102 | { USB_DEVICE(0x413c, 0x8197) }, | 100 | { USB_DEVICE(0x413c, 0x8197) }, |
| 103 | 101 | ||
| 104 | /* Foxconn - Hon Hai */ | 102 | /* Foxconn - Hon Hai */ |
| 105 | { USB_DEVICE(0x0489, 0xe033) }, | 103 | { USB_DEVICE(0x0489, 0xe033) }, |
| 106 | 104 | ||
| 105 | /*Broadcom devices with vendor specific id */ | ||
| 106 | { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }, | ||
| 107 | |||
| 107 | { } /* Terminating entry */ | 108 | { } /* Terminating entry */ |
| 108 | }; | 109 | }; |
| 109 | 110 | ||
| @@ -141,6 +142,7 @@ static struct usb_device_id blacklist_table[] = { | |||
| 141 | 142 | ||
| 142 | /* Atheros AR5BBU12 with sflash firmware */ | 143 | /* Atheros AR5BBU12 with sflash firmware */ |
| 143 | { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 }, | 144 | { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 }, |
| 145 | { USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 }, | ||
| 144 | 146 | ||
| 145 | /* Broadcom BCM2035 */ | 147 | /* Broadcom BCM2035 */ |
| 146 | { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU }, | 148 | { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU }, |
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 5869ea387054..72ce247a0e8d 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | # common clock types | 1 | # common clock types |
| 2 | obj-$(CONFIG_HAVE_CLK) += clk-devres.o | ||
| 2 | obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o | 3 | obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o |
| 3 | obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ | 4 | obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ |
| 4 | clk-mux.o clk-divider.o clk-fixed-factor.o | 5 | clk-mux.o clk-divider.o clk-fixed-factor.o |
diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c new file mode 100644 index 000000000000..8f571548870f --- /dev/null +++ b/drivers/clk/clk-devres.c | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | /* | ||
| 2 | * This program is free software; you can redistribute it and/or modify | ||
| 3 | * it under the terms of the GNU General Public License version 2 as | ||
| 4 | * published by the Free Software Foundation. | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/clk.h> | ||
| 8 | #include <linux/device.h> | ||
| 9 | #include <linux/export.h> | ||
| 10 | #include <linux/gfp.h> | ||
| 11 | |||
| 12 | static void devm_clk_release(struct device *dev, void *res) | ||
| 13 | { | ||
| 14 | clk_put(*(struct clk **)res); | ||
| 15 | } | ||
| 16 | |||
| 17 | struct clk *devm_clk_get(struct device *dev, const char *id) | ||
| 18 | { | ||
| 19 | struct clk **ptr, *clk; | ||
| 20 | |||
| 21 | ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); | ||
| 22 | if (!ptr) | ||
| 23 | return ERR_PTR(-ENOMEM); | ||
| 24 | |||
| 25 | clk = clk_get(dev, id); | ||
| 26 | if (!IS_ERR(clk)) { | ||
| 27 | *ptr = clk; | ||
| 28 | devres_add(dev, ptr); | ||
| 29 | } else { | ||
| 30 | devres_free(ptr); | ||
| 31 | } | ||
| 32 | |||
| 33 | return clk; | ||
| 34 | } | ||
| 35 | EXPORT_SYMBOL(devm_clk_get); | ||
| 36 | |||
| 37 | static int devm_clk_match(struct device *dev, void *res, void *data) | ||
| 38 | { | ||
| 39 | struct clk **c = res; | ||
| 40 | if (!c || !*c) { | ||
| 41 | WARN_ON(!c || !*c); | ||
| 42 | return 0; | ||
| 43 | } | ||
| 44 | return *c == data; | ||
| 45 | } | ||
| 46 | |||
| 47 | void devm_clk_put(struct device *dev, struct clk *clk) | ||
| 48 | { | ||
| 49 | int ret; | ||
| 50 | |||
| 51 | ret = devres_release(dev, devm_clk_release, devm_clk_match, clk); | ||
| 52 | |||
| 53 | WARN_ON(ret); | ||
| 54 | } | ||
| 55 | EXPORT_SYMBOL(devm_clk_put); | ||
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index d423c9bdd71a..442a31363873 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c | |||
| @@ -171,51 +171,6 @@ void clk_put(struct clk *clk) | |||
| 171 | } | 171 | } |
| 172 | EXPORT_SYMBOL(clk_put); | 172 | EXPORT_SYMBOL(clk_put); |
| 173 | 173 | ||
| 174 | static void devm_clk_release(struct device *dev, void *res) | ||
| 175 | { | ||
| 176 | clk_put(*(struct clk **)res); | ||
| 177 | } | ||
| 178 | |||
| 179 | struct clk *devm_clk_get(struct device *dev, const char *id) | ||
| 180 | { | ||
| 181 | struct clk **ptr, *clk; | ||
| 182 | |||
| 183 | ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); | ||
| 184 | if (!ptr) | ||
| 185 | return ERR_PTR(-ENOMEM); | ||
| 186 | |||
| 187 | clk = clk_get(dev, id); | ||
| 188 | if (!IS_ERR(clk)) { | ||
| 189 | *ptr = clk; | ||
| 190 | devres_add(dev, ptr); | ||
| 191 | } else { | ||
| 192 | devres_free(ptr); | ||
| 193 | } | ||
| 194 | |||
| 195 | return clk; | ||
| 196 | } | ||
| 197 | EXPORT_SYMBOL(devm_clk_get); | ||
| 198 | |||
| 199 | static int devm_clk_match(struct device *dev, void *res, void *data) | ||
| 200 | { | ||
| 201 | struct clk **c = res; | ||
| 202 | if (!c || !*c) { | ||
| 203 | WARN_ON(!c || !*c); | ||
| 204 | return 0; | ||
| 205 | } | ||
| 206 | return *c == data; | ||
| 207 | } | ||
| 208 | |||
| 209 | void devm_clk_put(struct device *dev, struct clk *clk) | ||
| 210 | { | ||
| 211 | int ret; | ||
| 212 | |||
| 213 | ret = devres_destroy(dev, devm_clk_release, devm_clk_match, clk); | ||
| 214 | |||
| 215 | WARN_ON(ret); | ||
| 216 | } | ||
| 217 | EXPORT_SYMBOL(devm_clk_put); | ||
| 218 | |||
| 219 | void clkdev_add(struct clk_lookup *cl) | 174 | void clkdev_add(struct clk_lookup *cl) |
| 220 | { | 175 | { |
| 221 | mutex_lock(&clocks_mutex); | 176 | mutex_lock(&clocks_mutex); |
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index d53cd0afc200..6a78073c3808 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
| @@ -35,3 +35,8 @@ config CLKSRC_DBX500_PRCMU_SCHED_CLOCK | |||
| 35 | default y | 35 | default y |
| 36 | help | 36 | help |
| 37 | Use the always on PRCMU Timer as sched_clock | 37 | Use the always on PRCMU Timer as sched_clock |
| 38 | |||
| 39 | config CLKSRC_ARM_GENERIC | ||
| 40 | def_bool y if ARM64 | ||
| 41 | help | ||
| 42 | This option enables support for the ARM generic timer. | ||
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index b65d0c56ab35..65919901a301 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
| @@ -13,3 +13,4 @@ obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o | |||
| 13 | obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o | 13 | obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o |
| 14 | obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o | 14 | obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o |
| 15 | obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o | 15 | obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o |
| 16 | obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o | ||
diff --git a/drivers/clocksource/arm_generic.c b/drivers/clocksource/arm_generic.c new file mode 100644 index 000000000000..c4d9f9566c64 --- /dev/null +++ b/drivers/clocksource/arm_generic.c | |||
| @@ -0,0 +1,232 @@ | |||
| 1 | /* | ||
| 2 | * Generic timers support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * Author: Marc Zyngier <marc.zyngier@arm.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/init.h> | ||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/delay.h> | ||
| 23 | #include <linux/device.h> | ||
| 24 | #include <linux/smp.h> | ||
| 25 | #include <linux/cpu.h> | ||
| 26 | #include <linux/jiffies.h> | ||
| 27 | #include <linux/interrupt.h> | ||
| 28 | #include <linux/clockchips.h> | ||
| 29 | #include <linux/of_irq.h> | ||
| 30 | #include <linux/io.h> | ||
| 31 | |||
| 32 | #include <clocksource/arm_generic.h> | ||
| 33 | |||
| 34 | #include <asm/arm_generic.h> | ||
| 35 | |||
| 36 | static u32 arch_timer_rate; | ||
| 37 | static u64 sched_clock_mult __read_mostly; | ||
| 38 | static DEFINE_PER_CPU(struct clock_event_device, arch_timer_evt); | ||
| 39 | static int arch_timer_ppi; | ||
| 40 | |||
| 41 | static irqreturn_t arch_timer_handle_irq(int irq, void *dev_id) | ||
| 42 | { | ||
| 43 | struct clock_event_device *evt = dev_id; | ||
| 44 | unsigned long ctrl; | ||
| 45 | |||
| 46 | ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); | ||
| 47 | if (ctrl & ARCH_TIMER_CTRL_ISTATUS) { | ||
| 48 | ctrl |= ARCH_TIMER_CTRL_IMASK; | ||
| 49 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); | ||
| 50 | evt->event_handler(evt); | ||
| 51 | return IRQ_HANDLED; | ||
| 52 | } | ||
| 53 | |||
| 54 | return IRQ_NONE; | ||
| 55 | } | ||
| 56 | |||
| 57 | static void arch_timer_stop(void) | ||
| 58 | { | ||
| 59 | unsigned long ctrl; | ||
| 60 | |||
| 61 | ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); | ||
| 62 | ctrl &= ~ARCH_TIMER_CTRL_ENABLE; | ||
| 63 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); | ||
| 64 | } | ||
| 65 | |||
| 66 | static void arch_timer_set_mode(enum clock_event_mode mode, | ||
| 67 | struct clock_event_device *clk) | ||
| 68 | { | ||
| 69 | switch (mode) { | ||
| 70 | case CLOCK_EVT_MODE_UNUSED: | ||
| 71 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 72 | arch_timer_stop(); | ||
| 73 | break; | ||
| 74 | default: | ||
| 75 | break; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | static int arch_timer_set_next_event(unsigned long evt, | ||
| 80 | struct clock_event_device *unused) | ||
| 81 | { | ||
| 82 | unsigned long ctrl; | ||
| 83 | |||
| 84 | ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); | ||
| 85 | ctrl |= ARCH_TIMER_CTRL_ENABLE; | ||
| 86 | ctrl &= ~ARCH_TIMER_CTRL_IMASK; | ||
| 87 | |||
| 88 | arch_timer_reg_write(ARCH_TIMER_REG_TVAL, evt); | ||
| 89 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); | ||
| 90 | |||
| 91 | return 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | static void __cpuinit arch_timer_setup(struct clock_event_device *clk) | ||
| 95 | { | ||
| 96 | /* Let's make sure the timer is off before doing anything else */ | ||
| 97 | arch_timer_stop(); | ||
| 98 | |||
| 99 | clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP; | ||
| 100 | clk->name = "arch_sys_timer"; | ||
| 101 | clk->rating = 400; | ||
| 102 | clk->set_mode = arch_timer_set_mode; | ||
| 103 | clk->set_next_event = arch_timer_set_next_event; | ||
| 104 | clk->irq = arch_timer_ppi; | ||
| 105 | clk->cpumask = cpumask_of(smp_processor_id()); | ||
| 106 | |||
| 107 | clockevents_config_and_register(clk, arch_timer_rate, | ||
| 108 | 0xf, 0x7fffffff); | ||
| 109 | |||
| 110 | enable_percpu_irq(clk->irq, 0); | ||
| 111 | |||
| 112 | /* Ensure the physical counter is visible to userspace for the vDSO. */ | ||
| 113 | arch_counter_enable_user_access(); | ||
| 114 | } | ||
| 115 | |||
| 116 | static void __init arch_timer_calibrate(void) | ||
| 117 | { | ||
| 118 | if (arch_timer_rate == 0) { | ||
| 119 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, 0); | ||
| 120 | arch_timer_rate = arch_timer_reg_read(ARCH_TIMER_REG_FREQ); | ||
| 121 | |||
| 122 | /* Check the timer frequency. */ | ||
| 123 | if (arch_timer_rate == 0) | ||
| 124 | panic("Architected timer frequency is set to zero.\n" | ||
| 125 | "You must set this in your .dts file\n"); | ||
| 126 | } | ||
| 127 | |||
| 128 | /* Cache the sched_clock multiplier to save a divide in the hot path. */ | ||
| 129 | |||
| 130 | sched_clock_mult = NSEC_PER_SEC / arch_timer_rate; | ||
| 131 | |||
| 132 | pr_info("Architected local timer running at %u.%02uMHz.\n", | ||
| 133 | arch_timer_rate / 1000000, (arch_timer_rate / 10000) % 100); | ||
| 134 | } | ||
| 135 | |||
| 136 | static cycle_t arch_counter_read(struct clocksource *cs) | ||
| 137 | { | ||
| 138 | return arch_counter_get_cntpct(); | ||
| 139 | } | ||
| 140 | |||
| 141 | static struct clocksource clocksource_counter = { | ||
| 142 | .name = "arch_sys_counter", | ||
| 143 | .rating = 400, | ||
| 144 | .read = arch_counter_read, | ||
| 145 | .mask = CLOCKSOURCE_MASK(56), | ||
| 146 | .flags = (CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_VALID_FOR_HRES), | ||
| 147 | }; | ||
| 148 | |||
| 149 | int read_current_timer(unsigned long *timer_value) | ||
| 150 | { | ||
| 151 | *timer_value = arch_counter_get_cntpct(); | ||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | |||
| 155 | unsigned long long notrace sched_clock(void) | ||
| 156 | { | ||
| 157 | return arch_counter_get_cntvct() * sched_clock_mult; | ||
| 158 | } | ||
| 159 | |||
| 160 | static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self, | ||
| 161 | unsigned long action, void *hcpu) | ||
| 162 | { | ||
| 163 | int cpu = (long)hcpu; | ||
| 164 | struct clock_event_device *clk = per_cpu_ptr(&arch_timer_evt, cpu); | ||
| 165 | |||
| 166 | switch(action) { | ||
| 167 | case CPU_STARTING: | ||
| 168 | case CPU_STARTING_FROZEN: | ||
| 169 | arch_timer_setup(clk); | ||
| 170 | break; | ||
| 171 | |||
| 172 | case CPU_DYING: | ||
| 173 | case CPU_DYING_FROZEN: | ||
| 174 | pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n", | ||
| 175 | clk->irq, cpu); | ||
| 176 | disable_percpu_irq(clk->irq); | ||
| 177 | arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk); | ||
| 178 | break; | ||
| 179 | } | ||
| 180 | |||
| 181 | return NOTIFY_OK; | ||
| 182 | } | ||
| 183 | |||
| 184 | static struct notifier_block __cpuinitdata arch_timer_cpu_nb = { | ||
| 185 | .notifier_call = arch_timer_cpu_notify, | ||
| 186 | }; | ||
| 187 | |||
| 188 | static const struct of_device_id arch_timer_of_match[] __initconst = { | ||
| 189 | { .compatible = "arm,armv8-timer" }, | ||
| 190 | {}, | ||
| 191 | }; | ||
| 192 | |||
| 193 | int __init arm_generic_timer_init(void) | ||
| 194 | { | ||
| 195 | struct device_node *np; | ||
| 196 | int err; | ||
| 197 | u32 freq; | ||
| 198 | |||
| 199 | np = of_find_matching_node(NULL, arch_timer_of_match); | ||
| 200 | if (!np) { | ||
| 201 | pr_err("arch_timer: can't find DT node\n"); | ||
| 202 | return -ENODEV; | ||
| 203 | } | ||
| 204 | |||
| 205 | /* Try to determine the frequency from the device tree or CNTFRQ */ | ||
| 206 | if (!of_property_read_u32(np, "clock-frequency", &freq)) | ||
| 207 | arch_timer_rate = freq; | ||
| 208 | arch_timer_calibrate(); | ||
| 209 | |||
| 210 | arch_timer_ppi = irq_of_parse_and_map(np, 0); | ||
| 211 | pr_info("arch_timer: found %s irq %d\n", np->name, arch_timer_ppi); | ||
| 212 | |||
| 213 | err = request_percpu_irq(arch_timer_ppi, arch_timer_handle_irq, | ||
| 214 | np->name, &arch_timer_evt); | ||
| 215 | if (err) { | ||
| 216 | pr_err("arch_timer: can't register interrupt %d (%d)\n", | ||
| 217 | arch_timer_ppi, err); | ||
| 218 | return err; | ||
| 219 | } | ||
| 220 | |||
| 221 | clocksource_register_hz(&clocksource_counter, arch_timer_rate); | ||
| 222 | |||
| 223 | /* Calibrate the delay loop directly */ | ||
| 224 | lpj_fine = arch_timer_rate / HZ; | ||
| 225 | |||
| 226 | /* Immediately configure the timer on the boot CPU */ | ||
| 227 | arch_timer_setup(per_cpu_ptr(&arch_timer_evt, smp_processor_id())); | ||
| 228 | |||
| 229 | register_cpu_notifier(&arch_timer_cpu_nb); | ||
| 230 | |||
| 231 | return 0; | ||
| 232 | } | ||
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index c0e816468e30..1a40935c85fd 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c | |||
| @@ -35,7 +35,6 @@ | |||
| 35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
| 36 | #include <linux/string.h> | 36 | #include <linux/string.h> |
| 37 | #include <linux/cpumask.h> | 37 | #include <linux/cpumask.h> |
| 38 | #include <linux/sched.h> /* for current / set_cpus_allowed() */ | ||
| 39 | #include <linux/io.h> | 38 | #include <linux/io.h> |
| 40 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
| 41 | 40 | ||
| @@ -1139,16 +1138,23 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, | |||
| 1139 | return res; | 1138 | return res; |
| 1140 | } | 1139 | } |
| 1141 | 1140 | ||
| 1142 | /* Driver entry point to switch to the target frequency */ | 1141 | struct powernowk8_target_arg { |
| 1143 | static int powernowk8_target(struct cpufreq_policy *pol, | 1142 | struct cpufreq_policy *pol; |
| 1144 | unsigned targfreq, unsigned relation) | 1143 | unsigned targfreq; |
| 1144 | unsigned relation; | ||
| 1145 | }; | ||
| 1146 | |||
| 1147 | static long powernowk8_target_fn(void *arg) | ||
| 1145 | { | 1148 | { |
| 1146 | cpumask_var_t oldmask; | 1149 | struct powernowk8_target_arg *pta = arg; |
| 1150 | struct cpufreq_policy *pol = pta->pol; | ||
| 1151 | unsigned targfreq = pta->targfreq; | ||
| 1152 | unsigned relation = pta->relation; | ||
| 1147 | struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); | 1153 | struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); |
| 1148 | u32 checkfid; | 1154 | u32 checkfid; |
| 1149 | u32 checkvid; | 1155 | u32 checkvid; |
| 1150 | unsigned int newstate; | 1156 | unsigned int newstate; |
| 1151 | int ret = -EIO; | 1157 | int ret; |
| 1152 | 1158 | ||
| 1153 | if (!data) | 1159 | if (!data) |
| 1154 | return -EINVAL; | 1160 | return -EINVAL; |
| @@ -1156,29 +1162,16 @@ static int powernowk8_target(struct cpufreq_policy *pol, | |||
| 1156 | checkfid = data->currfid; | 1162 | checkfid = data->currfid; |
| 1157 | checkvid = data->currvid; | 1163 | checkvid = data->currvid; |
| 1158 | 1164 | ||
| 1159 | /* only run on specific CPU from here on. */ | ||
| 1160 | /* This is poor form: use a workqueue or smp_call_function_single */ | ||
| 1161 | if (!alloc_cpumask_var(&oldmask, GFP_KERNEL)) | ||
| 1162 | return -ENOMEM; | ||
| 1163 | |||
| 1164 | cpumask_copy(oldmask, tsk_cpus_allowed(current)); | ||
| 1165 | set_cpus_allowed_ptr(current, cpumask_of(pol->cpu)); | ||
| 1166 | |||
| 1167 | if (smp_processor_id() != pol->cpu) { | ||
| 1168 | printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu); | ||
| 1169 | goto err_out; | ||
| 1170 | } | ||
| 1171 | |||
| 1172 | if (pending_bit_stuck()) { | 1165 | if (pending_bit_stuck()) { |
| 1173 | printk(KERN_ERR PFX "failing targ, change pending bit set\n"); | 1166 | printk(KERN_ERR PFX "failing targ, change pending bit set\n"); |
| 1174 | goto err_out; | 1167 | return -EIO; |
| 1175 | } | 1168 | } |
| 1176 | 1169 | ||
| 1177 | pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n", | 1170 | pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n", |
| 1178 | pol->cpu, targfreq, pol->min, pol->max, relation); | 1171 | pol->cpu, targfreq, pol->min, pol->max, relation); |
| 1179 | 1172 | ||
| 1180 | if (query_current_values_with_pending_wait(data)) | 1173 | if (query_current_values_with_pending_wait(data)) |
| 1181 | goto err_out; | 1174 | return -EIO; |
| 1182 | 1175 | ||
| 1183 | if (cpu_family != CPU_HW_PSTATE) { | 1176 | if (cpu_family != CPU_HW_PSTATE) { |
| 1184 | pr_debug("targ: curr fid 0x%x, vid 0x%x\n", | 1177 | pr_debug("targ: curr fid 0x%x, vid 0x%x\n", |
| @@ -1196,7 +1189,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, | |||
| 1196 | 1189 | ||
| 1197 | if (cpufreq_frequency_table_target(pol, data->powernow_table, | 1190 | if (cpufreq_frequency_table_target(pol, data->powernow_table, |
| 1198 | targfreq, relation, &newstate)) | 1191 | targfreq, relation, &newstate)) |
| 1199 | goto err_out; | 1192 | return -EIO; |
| 1200 | 1193 | ||
| 1201 | mutex_lock(&fidvid_mutex); | 1194 | mutex_lock(&fidvid_mutex); |
| 1202 | 1195 | ||
| @@ -1209,9 +1202,8 @@ static int powernowk8_target(struct cpufreq_policy *pol, | |||
| 1209 | ret = transition_frequency_fidvid(data, newstate); | 1202 | ret = transition_frequency_fidvid(data, newstate); |
| 1210 | if (ret) { | 1203 | if (ret) { |
| 1211 | printk(KERN_ERR PFX "transition frequency failed\n"); | 1204 | printk(KERN_ERR PFX "transition frequency failed\n"); |
| 1212 | ret = 1; | ||
| 1213 | mutex_unlock(&fidvid_mutex); | 1205 | mutex_unlock(&fidvid_mutex); |
| 1214 | goto err_out; | 1206 | return 1; |
| 1215 | } | 1207 | } |
| 1216 | mutex_unlock(&fidvid_mutex); | 1208 | mutex_unlock(&fidvid_mutex); |
| 1217 | 1209 | ||
| @@ -1220,12 +1212,25 @@ static int powernowk8_target(struct cpufreq_policy *pol, | |||
| 1220 | data->powernow_table[newstate].index); | 1212 | data->powernow_table[newstate].index); |
| 1221 | else | 1213 | else |
| 1222 | pol->cur = find_khz_freq_from_fid(data->currfid); | 1214 | pol->cur = find_khz_freq_from_fid(data->currfid); |
| 1223 | ret = 0; | ||
| 1224 | 1215 | ||
| 1225 | err_out: | 1216 | return 0; |
| 1226 | set_cpus_allowed_ptr(current, oldmask); | 1217 | } |
| 1227 | free_cpumask_var(oldmask); | 1218 | |
| 1228 | return ret; | 1219 | /* Driver entry point to switch to the target frequency */ |
| 1220 | static int powernowk8_target(struct cpufreq_policy *pol, | ||
| 1221 | unsigned targfreq, unsigned relation) | ||
| 1222 | { | ||
| 1223 | struct powernowk8_target_arg pta = { .pol = pol, .targfreq = targfreq, | ||
| 1224 | .relation = relation }; | ||
| 1225 | |||
| 1226 | /* | ||
| 1227 | * Must run on @pol->cpu. cpufreq core is responsible for ensuring | ||
| 1228 | * that we're bound to the current CPU and pol->cpu stays online. | ||
| 1229 | */ | ||
| 1230 | if (smp_processor_id() == pol->cpu) | ||
| 1231 | return powernowk8_target_fn(&pta); | ||
| 1232 | else | ||
| 1233 | return work_on_cpu(pol->cpu, powernowk8_target_fn, &pta); | ||
| 1229 | } | 1234 | } |
| 1230 | 1235 | ||
| 1231 | /* Driver entry point to verify the policy and range of frequencies */ | 1236 | /* Driver entry point to verify the policy and range of frequencies */ |
diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c index 002888185f17..d216cd3cc569 100644 --- a/drivers/crypto/caam/key_gen.c +++ b/drivers/crypto/caam/key_gen.c | |||
| @@ -120,3 +120,4 @@ u32 gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, | |||
| 120 | 120 | ||
| 121 | return ret; | 121 | return ret; |
| 122 | } | 122 | } |
| 123 | EXPORT_SYMBOL(gen_split_key); | ||
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 3934fcc4e00b..17d6958342e7 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c | |||
| @@ -168,9 +168,9 @@ static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc) | |||
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | /** | 170 | /** |
| 171 | * atc_desc_chain - build chain adding a descripor | 171 | * atc_desc_chain - build chain adding a descriptor |
| 172 | * @first: address of first descripor of the chain | 172 | * @first: address of first descriptor of the chain |
| 173 | * @prev: address of previous descripor of the chain | 173 | * @prev: address of previous descriptor of the chain |
| 174 | * @desc: descriptor to queue | 174 | * @desc: descriptor to queue |
| 175 | * | 175 | * |
| 176 | * Called from prep_* functions | 176 | * Called from prep_* functions |
| @@ -661,7 +661,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
| 661 | flags); | 661 | flags); |
| 662 | 662 | ||
| 663 | if (unlikely(!atslave || !sg_len)) { | 663 | if (unlikely(!atslave || !sg_len)) { |
| 664 | dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n"); | 664 | dev_dbg(chan2dev(chan), "prep_slave_sg: sg length is zero!\n"); |
| 665 | return NULL; | 665 | return NULL; |
| 666 | } | 666 | } |
| 667 | 667 | ||
| @@ -689,6 +689,11 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
| 689 | 689 | ||
| 690 | mem = sg_dma_address(sg); | 690 | mem = sg_dma_address(sg); |
| 691 | len = sg_dma_len(sg); | 691 | len = sg_dma_len(sg); |
| 692 | if (unlikely(!len)) { | ||
| 693 | dev_dbg(chan2dev(chan), | ||
| 694 | "prep_slave_sg: sg(%d) data length is zero\n", i); | ||
| 695 | goto err; | ||
| 696 | } | ||
| 692 | mem_width = 2; | 697 | mem_width = 2; |
| 693 | if (unlikely(mem & 3 || len & 3)) | 698 | if (unlikely(mem & 3 || len & 3)) |
| 694 | mem_width = 0; | 699 | mem_width = 0; |
| @@ -724,6 +729,11 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
| 724 | 729 | ||
| 725 | mem = sg_dma_address(sg); | 730 | mem = sg_dma_address(sg); |
| 726 | len = sg_dma_len(sg); | 731 | len = sg_dma_len(sg); |
| 732 | if (unlikely(!len)) { | ||
| 733 | dev_dbg(chan2dev(chan), | ||
| 734 | "prep_slave_sg: sg(%d) data length is zero\n", i); | ||
| 735 | goto err; | ||
| 736 | } | ||
| 727 | mem_width = 2; | 737 | mem_width = 2; |
| 728 | if (unlikely(mem & 3 || len & 3)) | 738 | if (unlikely(mem & 3 || len & 3)) |
| 729 | mem_width = 0; | 739 | mem_width = 0; |
| @@ -757,6 +767,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
| 757 | 767 | ||
| 758 | err_desc_get: | 768 | err_desc_get: |
| 759 | dev_err(chan2dev(chan), "not enough descriptors available\n"); | 769 | dev_err(chan2dev(chan), "not enough descriptors available\n"); |
| 770 | err: | ||
| 760 | atc_desc_put(atchan, first); | 771 | atc_desc_put(atchan, first); |
| 761 | return NULL; | 772 | return NULL; |
| 762 | } | 773 | } |
| @@ -785,7 +796,7 @@ err_out: | |||
| 785 | } | 796 | } |
| 786 | 797 | ||
| 787 | /** | 798 | /** |
| 788 | * atc_dma_cyclic_fill_desc - Fill one period decriptor | 799 | * atc_dma_cyclic_fill_desc - Fill one period descriptor |
| 789 | */ | 800 | */ |
| 790 | static int | 801 | static int |
| 791 | atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc, | 802 | atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc, |
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index c64917ec313d..bb02fd981afb 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c | |||
| @@ -1118,7 +1118,7 @@ fail: | |||
| 1118 | * @chan: channel | 1118 | * @chan: channel |
| 1119 | * @dma_addr: DMA mapped address of the buffer | 1119 | * @dma_addr: DMA mapped address of the buffer |
| 1120 | * @buf_len: length of the buffer (in bytes) | 1120 | * @buf_len: length of the buffer (in bytes) |
| 1121 | * @period_len: lenght of a single period | 1121 | * @period_len: length of a single period |
| 1122 | * @dir: direction of the operation | 1122 | * @dir: direction of the operation |
| 1123 | * @context: operation context (ignored) | 1123 | * @context: operation context (ignored) |
| 1124 | * | 1124 | * |
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 8f84761f98ba..094437b9d823 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c | |||
| @@ -1015,7 +1015,7 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) | |||
| 1015 | /* | 1015 | /* |
| 1016 | * Programming Error | 1016 | * Programming Error |
| 1017 | * The DMA_INTERRUPT async_tx is a NULL transfer, which will | 1017 | * The DMA_INTERRUPT async_tx is a NULL transfer, which will |
| 1018 | * triger a PE interrupt. | 1018 | * trigger a PE interrupt. |
| 1019 | */ | 1019 | */ |
| 1020 | if (stat & FSL_DMA_SR_PE) { | 1020 | if (stat & FSL_DMA_SR_PE) { |
| 1021 | chan_dbg(chan, "irq: Programming Error INT\n"); | 1021 | chan_dbg(chan, "irq: Programming Error INT\n"); |
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 5084975d793c..54f580bb993c 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c | |||
| @@ -572,8 +572,8 @@ static void imxdma_tasklet(unsigned long data) | |||
| 572 | if (desc->desc.callback) | 572 | if (desc->desc.callback) |
| 573 | desc->desc.callback(desc->desc.callback_param); | 573 | desc->desc.callback(desc->desc.callback_param); |
| 574 | 574 | ||
| 575 | /* If we are dealing with a cyclic descriptor keep it on ld_active | 575 | /* If we are dealing with a cyclic descriptor, keep it on ld_active |
| 576 | * and dont mark the descripor as complete. | 576 | * and dont mark the descriptor as complete. |
| 577 | * Only in non-cyclic cases it would be marked as complete | 577 | * Only in non-cyclic cases it would be marked as complete |
| 578 | */ | 578 | */ |
| 579 | if (imxdma_chan_is_doing_cyclic(imxdmac)) | 579 | if (imxdma_chan_is_doing_cyclic(imxdmac)) |
diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index 222e907bfaaa..02b21d7d38e5 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c | |||
| @@ -427,7 +427,7 @@ DMA engine callback Functions*/ | |||
| 427 | * intel_mid_dma_tx_submit - callback to submit DMA transaction | 427 | * intel_mid_dma_tx_submit - callback to submit DMA transaction |
| 428 | * @tx: dma engine descriptor | 428 | * @tx: dma engine descriptor |
| 429 | * | 429 | * |
| 430 | * Submit the DMA trasaction for this descriptor, start if ch idle | 430 | * Submit the DMA transaction for this descriptor, start if ch idle |
| 431 | */ | 431 | */ |
| 432 | static dma_cookie_t intel_mid_dma_tx_submit(struct dma_async_tx_descriptor *tx) | 432 | static dma_cookie_t intel_mid_dma_tx_submit(struct dma_async_tx_descriptor *tx) |
| 433 | { | 433 | { |
diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h index 1bfa9268feaf..17b42192ea58 100644 --- a/drivers/dma/intel_mid_dma_regs.h +++ b/drivers/dma/intel_mid_dma_regs.h | |||
| @@ -168,9 +168,9 @@ union intel_mid_dma_cfg_hi { | |||
| 168 | * @active_list: current active descriptors | 168 | * @active_list: current active descriptors |
| 169 | * @queue: current queued up descriptors | 169 | * @queue: current queued up descriptors |
| 170 | * @free_list: current free descriptors | 170 | * @free_list: current free descriptors |
| 171 | * @slave: dma slave struture | 171 | * @slave: dma slave structure |
| 172 | * @descs_allocated: total number of decsiptors allocated | 172 | * @descs_allocated: total number of descriptors allocated |
| 173 | * @dma: dma device struture pointer | 173 | * @dma: dma device structure pointer |
| 174 | * @busy: bool representing if ch is busy (active txn) or not | 174 | * @busy: bool representing if ch is busy (active txn) or not |
| 175 | * @in_use: bool representing if ch is in use or not | 175 | * @in_use: bool representing if ch is in use or not |
| 176 | * @raw_tfr: raw trf interrupt received | 176 | * @raw_tfr: raw trf interrupt received |
diff --git a/drivers/dma/ioat/hw.h b/drivers/dma/ioat/hw.h index 60e675455b6a..d2ff3fda0b18 100644 --- a/drivers/dma/ioat/hw.h +++ b/drivers/dma/ioat/hw.h | |||
| @@ -22,7 +22,6 @@ | |||
| 22 | #define _IOAT_HW_H_ | 22 | #define _IOAT_HW_H_ |
| 23 | 23 | ||
| 24 | /* PCI Configuration Space Values */ | 24 | /* PCI Configuration Space Values */ |
| 25 | #define IOAT_PCI_VID 0x8086 | ||
| 26 | #define IOAT_MMIO_BAR 0 | 25 | #define IOAT_MMIO_BAR 0 |
| 27 | 26 | ||
| 28 | /* CB device ID's */ | 27 | /* CB device ID's */ |
| @@ -31,9 +30,6 @@ | |||
| 31 | #define IOAT_PCI_DID_SCNB 0x65FF | 30 | #define IOAT_PCI_DID_SCNB 0x65FF |
| 32 | #define IOAT_PCI_DID_SNB 0x402F | 31 | #define IOAT_PCI_DID_SNB 0x402F |
| 33 | 32 | ||
| 34 | #define IOAT_PCI_RID 0x00 | ||
| 35 | #define IOAT_PCI_SVID 0x8086 | ||
| 36 | #define IOAT_PCI_SID 0x8086 | ||
| 37 | #define IOAT_VER_1_2 0x12 /* Version 1.2 */ | 33 | #define IOAT_VER_1_2 0x12 /* Version 1.2 */ |
| 38 | #define IOAT_VER_2_0 0x20 /* Version 2.0 */ | 34 | #define IOAT_VER_2_0 0x20 /* Version 2.0 */ |
| 39 | #define IOAT_VER_3_0 0x30 /* Version 3.0 */ | 35 | #define IOAT_VER_3_0 0x30 /* Version 3.0 */ |
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index e4feba6b03c0..5d3bbcd279b4 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c | |||
| @@ -522,7 +522,7 @@ enum desc_status { | |||
| 522 | /* In the DMAC pool */ | 522 | /* In the DMAC pool */ |
| 523 | FREE, | 523 | FREE, |
| 524 | /* | 524 | /* |
| 525 | * Allocted to some channel during prep_xxx | 525 | * Allocated to some channel during prep_xxx |
| 526 | * Also may be sitting on the work_list. | 526 | * Also may be sitting on the work_list. |
| 527 | */ | 527 | */ |
| 528 | PREP, | 528 | PREP, |
| @@ -1567,17 +1567,19 @@ static int pl330_submit_req(void *ch_id, struct pl330_req *r) | |||
| 1567 | goto xfer_exit; | 1567 | goto xfer_exit; |
| 1568 | } | 1568 | } |
| 1569 | 1569 | ||
| 1570 | /* Prefer Secure Channel */ | ||
| 1571 | if (!_manager_ns(thrd)) | ||
| 1572 | r->cfg->nonsecure = 0; | ||
| 1573 | else | ||
| 1574 | r->cfg->nonsecure = 1; | ||
| 1575 | 1570 | ||
| 1576 | /* Use last settings, if not provided */ | 1571 | /* Use last settings, if not provided */ |
| 1577 | if (r->cfg) | 1572 | if (r->cfg) { |
| 1573 | /* Prefer Secure Channel */ | ||
| 1574 | if (!_manager_ns(thrd)) | ||
| 1575 | r->cfg->nonsecure = 0; | ||
| 1576 | else | ||
| 1577 | r->cfg->nonsecure = 1; | ||
| 1578 | |||
| 1578 | ccr = _prepare_ccr(r->cfg); | 1579 | ccr = _prepare_ccr(r->cfg); |
| 1579 | else | 1580 | } else { |
| 1580 | ccr = readl(regs + CC(thrd->id)); | 1581 | ccr = readl(regs + CC(thrd->id)); |
| 1582 | } | ||
| 1581 | 1583 | ||
| 1582 | /* If this req doesn't have valid xfer settings */ | 1584 | /* If this req doesn't have valid xfer settings */ |
| 1583 | if (!_is_valid(ccr)) { | 1585 | if (!_is_valid(ccr)) { |
| @@ -2928,6 +2930,11 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) | |||
| 2928 | num_chan = max_t(int, pi->pcfg.num_peri, pi->pcfg.num_chan); | 2930 | num_chan = max_t(int, pi->pcfg.num_peri, pi->pcfg.num_chan); |
| 2929 | 2931 | ||
| 2930 | pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL); | 2932 | pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL); |
| 2933 | if (!pdmac->peripherals) { | ||
| 2934 | ret = -ENOMEM; | ||
| 2935 | dev_err(&adev->dev, "unable to allocate pdmac->peripherals\n"); | ||
| 2936 | goto probe_err5; | ||
| 2937 | } | ||
| 2931 | 2938 | ||
| 2932 | for (i = 0; i < num_chan; i++) { | 2939 | for (i = 0; i < num_chan; i++) { |
| 2933 | pch = &pdmac->peripherals[i]; | 2940 | pch = &pdmac->peripherals[i]; |
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c index ced98826684a..f72348d0bc41 100644 --- a/drivers/dma/ppc4xx/adma.c +++ b/drivers/dma/ppc4xx/adma.c | |||
| @@ -4446,7 +4446,7 @@ static int __devinit ppc440spe_adma_probe(struct platform_device *ofdev) | |||
| 4446 | ret = -ENOMEM; | 4446 | ret = -ENOMEM; |
| 4447 | goto err_dma_alloc; | 4447 | goto err_dma_alloc; |
| 4448 | } | 4448 | } |
| 4449 | dev_dbg(&ofdev->dev, "allocted descriptor pool virt 0x%p phys 0x%llx\n", | 4449 | dev_dbg(&ofdev->dev, "allocated descriptor pool virt 0x%p phys 0x%llx\n", |
| 4450 | adev->dma_desc_pool_virt, (u64)adev->dma_desc_pool); | 4450 | adev->dma_desc_pool_virt, (u64)adev->dma_desc_pool); |
| 4451 | 4451 | ||
| 4452 | regs = ioremap(res.start, resource_size(&res)); | 4452 | regs = ioremap(res.start, resource_size(&res)); |
diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h index 51e8e5396e9b..6d47373f3f58 100644 --- a/drivers/dma/ste_dma40_ll.h +++ b/drivers/dma/ste_dma40_ll.h | |||
| @@ -202,7 +202,7 @@ | |||
| 202 | /* LLI related structures */ | 202 | /* LLI related structures */ |
| 203 | 203 | ||
| 204 | /** | 204 | /** |
| 205 | * struct d40_phy_lli - The basic configration register for each physical | 205 | * struct d40_phy_lli - The basic configuration register for each physical |
| 206 | * channel. | 206 | * channel. |
| 207 | * | 207 | * |
| 208 | * @reg_cfg: The configuration register. | 208 | * @reg_cfg: The configuration register. |
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 616d90bcb3a4..d5dc9da7f99f 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
| @@ -199,6 +199,36 @@ void *edac_align_ptr(void **p, unsigned size, int n_elems) | |||
| 199 | return (void *)(((unsigned long)ptr) + align - r); | 199 | return (void *)(((unsigned long)ptr) + align - r); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | static void _edac_mc_free(struct mem_ctl_info *mci) | ||
| 203 | { | ||
| 204 | int i, chn, row; | ||
| 205 | struct csrow_info *csr; | ||
| 206 | const unsigned int tot_dimms = mci->tot_dimms; | ||
| 207 | const unsigned int tot_channels = mci->num_cschannel; | ||
| 208 | const unsigned int tot_csrows = mci->nr_csrows; | ||
| 209 | |||
| 210 | if (mci->dimms) { | ||
| 211 | for (i = 0; i < tot_dimms; i++) | ||
| 212 | kfree(mci->dimms[i]); | ||
| 213 | kfree(mci->dimms); | ||
| 214 | } | ||
| 215 | if (mci->csrows) { | ||
| 216 | for (row = 0; row < tot_csrows; row++) { | ||
| 217 | csr = mci->csrows[row]; | ||
| 218 | if (csr) { | ||
| 219 | if (csr->channels) { | ||
| 220 | for (chn = 0; chn < tot_channels; chn++) | ||
| 221 | kfree(csr->channels[chn]); | ||
| 222 | kfree(csr->channels); | ||
| 223 | } | ||
| 224 | kfree(csr); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | kfree(mci->csrows); | ||
| 228 | } | ||
| 229 | kfree(mci); | ||
| 230 | } | ||
| 231 | |||
| 202 | /** | 232 | /** |
| 203 | * edac_mc_alloc: Allocate and partially fill a struct mem_ctl_info structure | 233 | * edac_mc_alloc: Allocate and partially fill a struct mem_ctl_info structure |
| 204 | * @mc_num: Memory controller number | 234 | * @mc_num: Memory controller number |
| @@ -413,24 +443,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
| 413 | return mci; | 443 | return mci; |
| 414 | 444 | ||
| 415 | error: | 445 | error: |
| 416 | if (mci->dimms) { | 446 | _edac_mc_free(mci); |
| 417 | for (i = 0; i < tot_dimms; i++) | ||
| 418 | kfree(mci->dimms[i]); | ||
| 419 | kfree(mci->dimms); | ||
| 420 | } | ||
| 421 | if (mci->csrows) { | ||
| 422 | for (chn = 0; chn < tot_channels; chn++) { | ||
| 423 | csr = mci->csrows[chn]; | ||
| 424 | if (csr) { | ||
| 425 | for (chn = 0; chn < tot_channels; chn++) | ||
| 426 | kfree(csr->channels[chn]); | ||
| 427 | kfree(csr); | ||
| 428 | } | ||
| 429 | kfree(mci->csrows[i]); | ||
| 430 | } | ||
| 431 | kfree(mci->csrows); | ||
| 432 | } | ||
| 433 | kfree(mci); | ||
| 434 | 447 | ||
| 435 | return NULL; | 448 | return NULL; |
| 436 | } | 449 | } |
| @@ -445,6 +458,14 @@ void edac_mc_free(struct mem_ctl_info *mci) | |||
| 445 | { | 458 | { |
| 446 | edac_dbg(1, "\n"); | 459 | edac_dbg(1, "\n"); |
| 447 | 460 | ||
| 461 | /* If we're not yet registered with sysfs free only what was allocated | ||
| 462 | * in edac_mc_alloc(). | ||
| 463 | */ | ||
| 464 | if (!device_is_registered(&mci->dev)) { | ||
| 465 | _edac_mc_free(mci); | ||
| 466 | return; | ||
| 467 | } | ||
| 468 | |||
| 448 | /* the mci instance is freed here, when the sysfs object is dropped */ | 469 | /* the mci instance is freed here, when the sysfs object is dropped */ |
| 449 | edac_unregister_sysfs(mci); | 470 | edac_unregister_sysfs(mci); |
| 450 | } | 471 | } |
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c index 47180a08edad..b6653a6fc5d5 100644 --- a/drivers/edac/i3200_edac.c +++ b/drivers/edac/i3200_edac.c | |||
| @@ -391,7 +391,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx) | |||
| 391 | for (j = 0; j < nr_channels; j++) { | 391 | for (j = 0; j < nr_channels; j++) { |
| 392 | struct dimm_info *dimm = csrow->channels[j]->dimm; | 392 | struct dimm_info *dimm = csrow->channels[j]->dimm; |
| 393 | 393 | ||
| 394 | dimm->nr_pages = nr_pages / nr_channels; | 394 | dimm->nr_pages = nr_pages; |
| 395 | dimm->grain = nr_pages << PAGE_SHIFT; | 395 | dimm->grain = nr_pages << PAGE_SHIFT; |
| 396 | dimm->mtype = MEM_DDR2; | 396 | dimm->mtype = MEM_DDR2; |
| 397 | dimm->dtype = DEV_UNKNOWN; | 397 | dimm->dtype = DEV_UNKNOWN; |
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c index 39c63757c2a1..6a49dd00b81b 100644 --- a/drivers/edac/i5000_edac.c +++ b/drivers/edac/i5000_edac.c | |||
| @@ -1012,6 +1012,10 @@ static void handle_channel(struct i5000_pvt *pvt, int slot, int channel, | |||
| 1012 | /* add the number of COLUMN bits */ | 1012 | /* add the number of COLUMN bits */ |
| 1013 | addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr); | 1013 | addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr); |
| 1014 | 1014 | ||
| 1015 | /* Dual-rank memories have twice the size */ | ||
| 1016 | if (dinfo->dual_rank) | ||
| 1017 | addrBits++; | ||
| 1018 | |||
| 1015 | addrBits += 6; /* add 64 bits per DIMM */ | 1019 | addrBits += 6; /* add 64 bits per DIMM */ |
| 1016 | addrBits -= 20; /* divide by 2^^20 */ | 1020 | addrBits -= 20; /* divide by 2^^20 */ |
| 1017 | addrBits -= 3; /* 8 bits per bytes */ | 1021 | addrBits -= 3; /* 8 bits per bytes */ |
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index f3b1f9fafa4b..5715b7c2c517 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c | |||
| @@ -513,7 +513,8 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
| 513 | { | 513 | { |
| 514 | struct sbridge_pvt *pvt = mci->pvt_info; | 514 | struct sbridge_pvt *pvt = mci->pvt_info; |
| 515 | struct dimm_info *dimm; | 515 | struct dimm_info *dimm; |
| 516 | int i, j, banks, ranks, rows, cols, size, npages; | 516 | unsigned i, j, banks, ranks, rows, cols, npages; |
| 517 | u64 size; | ||
| 517 | u32 reg; | 518 | u32 reg; |
| 518 | enum edac_type mode; | 519 | enum edac_type mode; |
| 519 | enum mem_type mtype; | 520 | enum mem_type mtype; |
| @@ -585,10 +586,10 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
| 585 | cols = numcol(mtr); | 586 | cols = numcol(mtr); |
| 586 | 587 | ||
| 587 | /* DDR3 has 8 I/O banks */ | 588 | /* DDR3 has 8 I/O banks */ |
| 588 | size = (rows * cols * banks * ranks) >> (20 - 3); | 589 | size = ((u64)rows * cols * banks * ranks) >> (20 - 3); |
| 589 | npages = MiB_TO_PAGES(size); | 590 | npages = MiB_TO_PAGES(size); |
| 590 | 591 | ||
| 591 | edac_dbg(0, "mc#%d: channel %d, dimm %d, %d Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n", | 592 | edac_dbg(0, "mc#%d: channel %d, dimm %d, %Ld Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n", |
| 592 | pvt->sbridge_dev->mc, i, j, | 593 | pvt->sbridge_dev->mc, i, j, |
| 593 | size, npages, | 594 | size, npages, |
| 594 | banks, ranks, rows, cols); | 595 | banks, ranks, rows, cols); |
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 427a289f32a5..6c19833ed2d0 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c | |||
| @@ -434,6 +434,11 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev) | |||
| 434 | regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, | 434 | regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, |
| 435 | ARIZONA_JD1_ENA, ARIZONA_JD1_ENA); | 435 | ARIZONA_JD1_ENA, ARIZONA_JD1_ENA); |
| 436 | 436 | ||
| 437 | ret = regulator_allow_bypass(info->micvdd, true); | ||
| 438 | if (ret != 0) | ||
| 439 | dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n", | ||
| 440 | ret); | ||
| 441 | |||
| 437 | pm_runtime_put(&pdev->dev); | 442 | pm_runtime_put(&pdev->dev); |
| 438 | 443 | ||
| 439 | return 0; | 444 | return 0; |
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index 920a609b2c35..38f9e52f358b 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c | |||
| @@ -669,13 +669,18 @@ static int __devinit max77693_muic_probe(struct platform_device *pdev) | |||
| 669 | } | 669 | } |
| 670 | info->dev = &pdev->dev; | 670 | info->dev = &pdev->dev; |
| 671 | info->max77693 = max77693; | 671 | info->max77693 = max77693; |
| 672 | info->max77693->regmap_muic = regmap_init_i2c(info->max77693->muic, | 672 | if (info->max77693->regmap_muic) |
| 673 | &max77693_muic_regmap_config); | 673 | dev_dbg(&pdev->dev, "allocate register map\n"); |
| 674 | if (IS_ERR(info->max77693->regmap_muic)) { | 674 | else { |
| 675 | ret = PTR_ERR(info->max77693->regmap_muic); | 675 | info->max77693->regmap_muic = devm_regmap_init_i2c( |
| 676 | dev_err(max77693->dev, | 676 | info->max77693->muic, |
| 677 | "failed to allocate register map: %d\n", ret); | 677 | &max77693_muic_regmap_config); |
| 678 | goto err_regmap; | 678 | if (IS_ERR(info->max77693->regmap_muic)) { |
| 679 | ret = PTR_ERR(info->max77693->regmap_muic); | ||
| 680 | dev_err(max77693->dev, | ||
| 681 | "failed to allocate register map: %d\n", ret); | ||
| 682 | goto err_regmap; | ||
| 683 | } | ||
| 679 | } | 684 | } |
| 680 | platform_set_drvdata(pdev, info); | 685 | platform_set_drvdata(pdev, info); |
| 681 | mutex_init(&info->mutex); | 686 | mutex_init(&info->mutex); |
diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 8a420f13905e..ed94b4ea72e9 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c | |||
| @@ -308,6 +308,7 @@ static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin, | |||
| 308 | { | 308 | { |
| 309 | struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); | 309 | struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); |
| 310 | 310 | ||
| 311 | __set_gpio_level_p012(group, pin, value); | ||
| 311 | __set_gpio_dir_p012(group, pin, 0); | 312 | __set_gpio_dir_p012(group, pin, 0); |
| 312 | 313 | ||
| 313 | return 0; | 314 | return 0; |
| @@ -318,6 +319,7 @@ static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin, | |||
| 318 | { | 319 | { |
| 319 | struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); | 320 | struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); |
| 320 | 321 | ||
| 322 | __set_gpio_level_p3(group, pin, value); | ||
| 321 | __set_gpio_dir_p3(group, pin, 0); | 323 | __set_gpio_dir_p3(group, pin, 0); |
| 322 | 324 | ||
| 323 | return 0; | 325 | return 0; |
| @@ -326,6 +328,9 @@ static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin, | |||
| 326 | static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin, | 328 | static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin, |
| 327 | int value) | 329 | int value) |
| 328 | { | 330 | { |
| 331 | struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); | ||
| 332 | |||
| 333 | __set_gpo_level_p3(group, pin, value); | ||
| 329 | return 0; | 334 | return 0; |
| 330 | } | 335 | } |
| 331 | 336 | ||
diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index d0c4574ef49c..36164806b9d4 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c | |||
| @@ -193,6 +193,9 @@ static const struct file_operations ast_fops = { | |||
| 193 | .mmap = ast_mmap, | 193 | .mmap = ast_mmap, |
| 194 | .poll = drm_poll, | 194 | .poll = drm_poll, |
| 195 | .fasync = drm_fasync, | 195 | .fasync = drm_fasync, |
| 196 | #ifdef CONFIG_COMPAT | ||
| 197 | .compat_ioctl = drm_compat_ioctl, | ||
| 198 | #endif | ||
| 196 | .read = drm_read, | 199 | .read = drm_read, |
| 197 | }; | 200 | }; |
| 198 | 201 | ||
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 7282c081fb53..a712cafcfa1d 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c | |||
| @@ -841,7 +841,7 @@ int ast_cursor_init(struct drm_device *dev) | |||
| 841 | 841 | ||
| 842 | ast->cursor_cache = obj; | 842 | ast->cursor_cache = obj; |
| 843 | ast->cursor_cache_gpu_addr = gpu_addr; | 843 | ast->cursor_cache_gpu_addr = gpu_addr; |
| 844 | DRM_ERROR("pinned cursor cache at %llx\n", ast->cursor_cache_gpu_addr); | 844 | DRM_DEBUG_KMS("pinned cursor cache at %llx\n", ast->cursor_cache_gpu_addr); |
| 845 | return 0; | 845 | return 0; |
| 846 | fail: | 846 | fail: |
| 847 | return ret; | 847 | return ret; |
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c index 7053140c6596..b83a2d7ddd1a 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.c +++ b/drivers/gpu/drm/cirrus/cirrus_drv.c | |||
| @@ -74,6 +74,9 @@ static const struct file_operations cirrus_driver_fops = { | |||
| 74 | .unlocked_ioctl = drm_ioctl, | 74 | .unlocked_ioctl = drm_ioctl, |
| 75 | .mmap = cirrus_mmap, | 75 | .mmap = cirrus_mmap, |
| 76 | .poll = drm_poll, | 76 | .poll = drm_poll, |
| 77 | #ifdef CONFIG_COMPAT | ||
| 78 | .compat_ioctl = drm_compat_ioctl, | ||
| 79 | #endif | ||
| 77 | .fasync = drm_fasync, | 80 | .fasync = drm_fasync, |
| 78 | }; | 81 | }; |
| 79 | static struct drm_driver driver = { | 82 | static struct drm_driver driver = { |
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 7f5096763b7d..59a26e577b57 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig | |||
| @@ -36,6 +36,6 @@ config DRM_EXYNOS_VIDI | |||
| 36 | 36 | ||
| 37 | config DRM_EXYNOS_G2D | 37 | config DRM_EXYNOS_G2D |
| 38 | bool "Exynos DRM G2D" | 38 | bool "Exynos DRM G2D" |
| 39 | depends on DRM_EXYNOS | 39 | depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D |
| 40 | help | 40 | help |
| 41 | Choose this option if you want to use Exynos G2D for DRM. | 41 | Choose this option if you want to use Exynos G2D for DRM. |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c index 613bf8a5d9b2..ae13febe0eaa 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c | |||
| @@ -163,6 +163,12 @@ static void exynos_gem_dmabuf_kunmap(struct dma_buf *dma_buf, | |||
| 163 | /* TODO */ | 163 | /* TODO */ |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | static int exynos_gem_dmabuf_mmap(struct dma_buf *dma_buf, | ||
| 167 | struct vm_area_struct *vma) | ||
| 168 | { | ||
| 169 | return -ENOTTY; | ||
| 170 | } | ||
| 171 | |||
| 166 | static struct dma_buf_ops exynos_dmabuf_ops = { | 172 | static struct dma_buf_ops exynos_dmabuf_ops = { |
| 167 | .map_dma_buf = exynos_gem_map_dma_buf, | 173 | .map_dma_buf = exynos_gem_map_dma_buf, |
| 168 | .unmap_dma_buf = exynos_gem_unmap_dma_buf, | 174 | .unmap_dma_buf = exynos_gem_unmap_dma_buf, |
| @@ -170,6 +176,7 @@ static struct dma_buf_ops exynos_dmabuf_ops = { | |||
| 170 | .kmap_atomic = exynos_gem_dmabuf_kmap_atomic, | 176 | .kmap_atomic = exynos_gem_dmabuf_kmap_atomic, |
| 171 | .kunmap = exynos_gem_dmabuf_kunmap, | 177 | .kunmap = exynos_gem_dmabuf_kunmap, |
| 172 | .kunmap_atomic = exynos_gem_dmabuf_kunmap_atomic, | 178 | .kunmap_atomic = exynos_gem_dmabuf_kunmap_atomic, |
| 179 | .mmap = exynos_gem_dmabuf_mmap, | ||
| 173 | .release = exynos_dmabuf_release, | 180 | .release = exynos_dmabuf_release, |
| 174 | }; | 181 | }; |
| 175 | 182 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index ebacec6f1e48..d07071937453 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c | |||
| @@ -160,7 +160,6 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) | |||
| 160 | if (!file_priv) | 160 | if (!file_priv) |
| 161 | return -ENOMEM; | 161 | return -ENOMEM; |
| 162 | 162 | ||
| 163 | drm_prime_init_file_private(&file->prime); | ||
| 164 | file->driver_priv = file_priv; | 163 | file->driver_priv = file_priv; |
| 165 | 164 | ||
| 166 | return exynos_drm_subdrv_open(dev, file); | 165 | return exynos_drm_subdrv_open(dev, file); |
| @@ -184,7 +183,6 @@ static void exynos_drm_preclose(struct drm_device *dev, | |||
| 184 | e->base.destroy(&e->base); | 183 | e->base.destroy(&e->base); |
| 185 | } | 184 | } |
| 186 | } | 185 | } |
| 187 | drm_prime_destroy_file_private(&file->prime); | ||
| 188 | spin_unlock_irqrestore(&dev->event_lock, flags); | 186 | spin_unlock_irqrestore(&dev->event_lock, flags); |
| 189 | 187 | ||
| 190 | exynos_drm_subdrv_close(dev, file); | 188 | exynos_drm_subdrv_close(dev, file); |
| @@ -241,6 +239,9 @@ static const struct file_operations exynos_drm_driver_fops = { | |||
| 241 | .poll = drm_poll, | 239 | .poll = drm_poll, |
| 242 | .read = drm_read, | 240 | .read = drm_read, |
| 243 | .unlocked_ioctl = drm_ioctl, | 241 | .unlocked_ioctl = drm_ioctl, |
| 242 | #ifdef CONFIG_COMPAT | ||
| 243 | .compat_ioctl = drm_compat_ioctl, | ||
| 244 | #endif | ||
| 244 | .release = drm_release, | 245 | .release = drm_release, |
| 245 | }; | 246 | }; |
| 246 | 247 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index a68d2b313f03..b19cd93e7047 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c | |||
| @@ -831,11 +831,6 @@ static int __devinit fimd_probe(struct platform_device *pdev) | |||
| 831 | } | 831 | } |
| 832 | 832 | ||
| 833 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 833 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 834 | if (!res) { | ||
| 835 | dev_err(dev, "failed to find registers\n"); | ||
| 836 | ret = -ENOENT; | ||
| 837 | goto err_clk; | ||
| 838 | } | ||
| 839 | 834 | ||
| 840 | ctx->regs = devm_request_and_ioremap(&pdev->dev, res); | 835 | ctx->regs = devm_request_and_ioremap(&pdev->dev, res); |
| 841 | if (!ctx->regs) { | 836 | if (!ctx->regs) { |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index d2d88f22a037..1065e90d0919 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c | |||
| @@ -129,7 +129,6 @@ struct g2d_runqueue_node { | |||
| 129 | struct g2d_data { | 129 | struct g2d_data { |
| 130 | struct device *dev; | 130 | struct device *dev; |
| 131 | struct clk *gate_clk; | 131 | struct clk *gate_clk; |
| 132 | struct resource *regs_res; | ||
| 133 | void __iomem *regs; | 132 | void __iomem *regs; |
| 134 | int irq; | 133 | int irq; |
| 135 | struct workqueue_struct *g2d_workq; | 134 | struct workqueue_struct *g2d_workq; |
| @@ -751,7 +750,7 @@ static int __devinit g2d_probe(struct platform_device *pdev) | |||
| 751 | struct exynos_drm_subdrv *subdrv; | 750 | struct exynos_drm_subdrv *subdrv; |
| 752 | int ret; | 751 | int ret; |
| 753 | 752 | ||
| 754 | g2d = kzalloc(sizeof(*g2d), GFP_KERNEL); | 753 | g2d = devm_kzalloc(&pdev->dev, sizeof(*g2d), GFP_KERNEL); |
| 755 | if (!g2d) { | 754 | if (!g2d) { |
| 756 | dev_err(dev, "failed to allocate driver data\n"); | 755 | dev_err(dev, "failed to allocate driver data\n"); |
| 757 | return -ENOMEM; | 756 | return -ENOMEM; |
| @@ -759,10 +758,8 @@ static int __devinit g2d_probe(struct platform_device *pdev) | |||
| 759 | 758 | ||
| 760 | g2d->runqueue_slab = kmem_cache_create("g2d_runqueue_slab", | 759 | g2d->runqueue_slab = kmem_cache_create("g2d_runqueue_slab", |
| 761 | sizeof(struct g2d_runqueue_node), 0, 0, NULL); | 760 | sizeof(struct g2d_runqueue_node), 0, 0, NULL); |
| 762 | if (!g2d->runqueue_slab) { | 761 | if (!g2d->runqueue_slab) |
| 763 | ret = -ENOMEM; | 762 | return -ENOMEM; |
| 764 | goto err_free_mem; | ||
| 765 | } | ||
| 766 | 763 | ||
| 767 | g2d->dev = dev; | 764 | g2d->dev = dev; |
| 768 | 765 | ||
| @@ -794,38 +791,26 @@ static int __devinit g2d_probe(struct platform_device *pdev) | |||
| 794 | pm_runtime_enable(dev); | 791 | pm_runtime_enable(dev); |
| 795 | 792 | ||
| 796 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 793 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 797 | if (!res) { | ||
| 798 | dev_err(dev, "failed to get I/O memory\n"); | ||
| 799 | ret = -ENOENT; | ||
| 800 | goto err_put_clk; | ||
| 801 | } | ||
| 802 | 794 | ||
| 803 | g2d->regs_res = request_mem_region(res->start, resource_size(res), | 795 | g2d->regs = devm_request_and_ioremap(&pdev->dev, res); |
| 804 | dev_name(dev)); | ||
| 805 | if (!g2d->regs_res) { | ||
| 806 | dev_err(dev, "failed to request I/O memory\n"); | ||
| 807 | ret = -ENOENT; | ||
| 808 | goto err_put_clk; | ||
| 809 | } | ||
| 810 | |||
| 811 | g2d->regs = ioremap(res->start, resource_size(res)); | ||
| 812 | if (!g2d->regs) { | 796 | if (!g2d->regs) { |
| 813 | dev_err(dev, "failed to remap I/O memory\n"); | 797 | dev_err(dev, "failed to remap I/O memory\n"); |
| 814 | ret = -ENXIO; | 798 | ret = -ENXIO; |
| 815 | goto err_release_res; | 799 | goto err_put_clk; |
| 816 | } | 800 | } |
| 817 | 801 | ||
| 818 | g2d->irq = platform_get_irq(pdev, 0); | 802 | g2d->irq = platform_get_irq(pdev, 0); |
| 819 | if (g2d->irq < 0) { | 803 | if (g2d->irq < 0) { |
| 820 | dev_err(dev, "failed to get irq\n"); | 804 | dev_err(dev, "failed to get irq\n"); |
| 821 | ret = g2d->irq; | 805 | ret = g2d->irq; |
| 822 | goto err_unmap_base; | 806 | goto err_put_clk; |
| 823 | } | 807 | } |
| 824 | 808 | ||
| 825 | ret = request_irq(g2d->irq, g2d_irq_handler, 0, "drm_g2d", g2d); | 809 | ret = devm_request_irq(&pdev->dev, g2d->irq, g2d_irq_handler, 0, |
| 810 | "drm_g2d", g2d); | ||
| 826 | if (ret < 0) { | 811 | if (ret < 0) { |
| 827 | dev_err(dev, "irq request failed\n"); | 812 | dev_err(dev, "irq request failed\n"); |
| 828 | goto err_unmap_base; | 813 | goto err_put_clk; |
| 829 | } | 814 | } |
| 830 | 815 | ||
| 831 | platform_set_drvdata(pdev, g2d); | 816 | platform_set_drvdata(pdev, g2d); |
| @@ -838,7 +823,7 @@ static int __devinit g2d_probe(struct platform_device *pdev) | |||
| 838 | ret = exynos_drm_subdrv_register(subdrv); | 823 | ret = exynos_drm_subdrv_register(subdrv); |
| 839 | if (ret < 0) { | 824 | if (ret < 0) { |
| 840 | dev_err(dev, "failed to register drm g2d device\n"); | 825 | dev_err(dev, "failed to register drm g2d device\n"); |
| 841 | goto err_free_irq; | 826 | goto err_put_clk; |
| 842 | } | 827 | } |
| 843 | 828 | ||
| 844 | dev_info(dev, "The exynos g2d(ver %d.%d) successfully probed\n", | 829 | dev_info(dev, "The exynos g2d(ver %d.%d) successfully probed\n", |
| @@ -846,13 +831,6 @@ static int __devinit g2d_probe(struct platform_device *pdev) | |||
| 846 | 831 | ||
| 847 | return 0; | 832 | return 0; |
| 848 | 833 | ||
| 849 | err_free_irq: | ||
| 850 | free_irq(g2d->irq, g2d); | ||
| 851 | err_unmap_base: | ||
| 852 | iounmap(g2d->regs); | ||
| 853 | err_release_res: | ||
| 854 | release_resource(g2d->regs_res); | ||
| 855 | kfree(g2d->regs_res); | ||
| 856 | err_put_clk: | 834 | err_put_clk: |
| 857 | pm_runtime_disable(dev); | 835 | pm_runtime_disable(dev); |
| 858 | clk_put(g2d->gate_clk); | 836 | clk_put(g2d->gate_clk); |
| @@ -862,8 +840,6 @@ err_destroy_workqueue: | |||
| 862 | destroy_workqueue(g2d->g2d_workq); | 840 | destroy_workqueue(g2d->g2d_workq); |
| 863 | err_destroy_slab: | 841 | err_destroy_slab: |
| 864 | kmem_cache_destroy(g2d->runqueue_slab); | 842 | kmem_cache_destroy(g2d->runqueue_slab); |
| 865 | err_free_mem: | ||
| 866 | kfree(g2d); | ||
| 867 | return ret; | 843 | return ret; |
| 868 | } | 844 | } |
| 869 | 845 | ||
| @@ -873,24 +849,18 @@ static int __devexit g2d_remove(struct platform_device *pdev) | |||
| 873 | 849 | ||
| 874 | cancel_work_sync(&g2d->runqueue_work); | 850 | cancel_work_sync(&g2d->runqueue_work); |
| 875 | exynos_drm_subdrv_unregister(&g2d->subdrv); | 851 | exynos_drm_subdrv_unregister(&g2d->subdrv); |
| 876 | free_irq(g2d->irq, g2d); | ||
| 877 | 852 | ||
| 878 | while (g2d->runqueue_node) { | 853 | while (g2d->runqueue_node) { |
| 879 | g2d_free_runqueue_node(g2d, g2d->runqueue_node); | 854 | g2d_free_runqueue_node(g2d, g2d->runqueue_node); |
| 880 | g2d->runqueue_node = g2d_get_runqueue_node(g2d); | 855 | g2d->runqueue_node = g2d_get_runqueue_node(g2d); |
| 881 | } | 856 | } |
| 882 | 857 | ||
| 883 | iounmap(g2d->regs); | ||
| 884 | release_resource(g2d->regs_res); | ||
| 885 | kfree(g2d->regs_res); | ||
| 886 | |||
| 887 | pm_runtime_disable(&pdev->dev); | 858 | pm_runtime_disable(&pdev->dev); |
| 888 | clk_put(g2d->gate_clk); | 859 | clk_put(g2d->gate_clk); |
| 889 | 860 | ||
| 890 | g2d_fini_cmdlist(g2d); | 861 | g2d_fini_cmdlist(g2d); |
| 891 | destroy_workqueue(g2d->g2d_workq); | 862 | destroy_workqueue(g2d->g2d_workq); |
| 892 | kmem_cache_destroy(g2d->runqueue_slab); | 863 | kmem_cache_destroy(g2d->runqueue_slab); |
| 893 | kfree(g2d); | ||
| 894 | 864 | ||
| 895 | return 0; | 865 | return 0; |
| 896 | } | 866 | } |
| @@ -924,7 +894,7 @@ static int g2d_resume(struct device *dev) | |||
| 924 | } | 894 | } |
| 925 | #endif | 895 | #endif |
| 926 | 896 | ||
| 927 | SIMPLE_DEV_PM_OPS(g2d_pm_ops, g2d_suspend, g2d_resume); | 897 | static SIMPLE_DEV_PM_OPS(g2d_pm_ops, g2d_suspend, g2d_resume); |
| 928 | 898 | ||
| 929 | struct platform_driver g2d_driver = { | 899 | struct platform_driver g2d_driver = { |
| 930 | .probe = g2d_probe, | 900 | .probe = g2d_probe, |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index f9efde40c097..a38051c95ec4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c | |||
| @@ -122,7 +122,7 @@ fail: | |||
| 122 | __free_page(pages[i]); | 122 | __free_page(pages[i]); |
| 123 | 123 | ||
| 124 | drm_free_large(pages); | 124 | drm_free_large(pages); |
| 125 | return ERR_PTR(PTR_ERR(p)); | 125 | return ERR_CAST(p); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | static void exynos_gem_put_pages(struct drm_gem_object *obj, | 128 | static void exynos_gem_put_pages(struct drm_gem_object *obj, |
| @@ -662,7 +662,7 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, | |||
| 662 | */ | 662 | */ |
| 663 | 663 | ||
| 664 | args->pitch = args->width * ((args->bpp + 7) / 8); | 664 | args->pitch = args->width * ((args->bpp + 7) / 8); |
| 665 | args->size = PAGE_ALIGN(args->pitch * args->height); | 665 | args->size = args->pitch * args->height; |
| 666 | 666 | ||
| 667 | exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size); | 667 | exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size); |
| 668 | if (IS_ERR(exynos_gem_obj)) | 668 | if (IS_ERR(exynos_gem_obj)) |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c index 8ffcdf8b9e22..3fdf0b65f47e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c | |||
| @@ -345,7 +345,7 @@ static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev) | |||
| 345 | 345 | ||
| 346 | DRM_DEBUG_KMS("%s\n", __FILE__); | 346 | DRM_DEBUG_KMS("%s\n", __FILE__); |
| 347 | 347 | ||
| 348 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | 348 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); |
| 349 | if (!ctx) { | 349 | if (!ctx) { |
| 350 | DRM_LOG_KMS("failed to alloc common hdmi context.\n"); | 350 | DRM_LOG_KMS("failed to alloc common hdmi context.\n"); |
| 351 | return -ENOMEM; | 351 | return -ENOMEM; |
| @@ -371,7 +371,6 @@ static int __devexit exynos_drm_hdmi_remove(struct platform_device *pdev) | |||
| 371 | DRM_DEBUG_KMS("%s\n", __FILE__); | 371 | DRM_DEBUG_KMS("%s\n", __FILE__); |
| 372 | 372 | ||
| 373 | exynos_drm_subdrv_unregister(&ctx->subdrv); | 373 | exynos_drm_subdrv_unregister(&ctx->subdrv); |
| 374 | kfree(ctx); | ||
| 375 | 374 | ||
| 376 | return 0; | 375 | return 0; |
| 377 | } | 376 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index b89829e5043a..e1f94b746bd7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c | |||
| @@ -29,7 +29,6 @@ static const uint32_t formats[] = { | |||
| 29 | DRM_FORMAT_XRGB8888, | 29 | DRM_FORMAT_XRGB8888, |
| 30 | DRM_FORMAT_ARGB8888, | 30 | DRM_FORMAT_ARGB8888, |
| 31 | DRM_FORMAT_NV12, | 31 | DRM_FORMAT_NV12, |
| 32 | DRM_FORMAT_NV12M, | ||
| 33 | DRM_FORMAT_NV12MT, | 32 | DRM_FORMAT_NV12MT, |
| 34 | }; | 33 | }; |
| 35 | 34 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index bb1550c4dd57..537027a74fd5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c | |||
| @@ -633,7 +633,7 @@ static int __devinit vidi_probe(struct platform_device *pdev) | |||
| 633 | 633 | ||
| 634 | DRM_DEBUG_KMS("%s\n", __FILE__); | 634 | DRM_DEBUG_KMS("%s\n", __FILE__); |
| 635 | 635 | ||
| 636 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | 636 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); |
| 637 | if (!ctx) | 637 | if (!ctx) |
| 638 | return -ENOMEM; | 638 | return -ENOMEM; |
| 639 | 639 | ||
| @@ -673,8 +673,6 @@ static int __devexit vidi_remove(struct platform_device *pdev) | |||
| 673 | ctx->raw_edid = NULL; | 673 | ctx->raw_edid = NULL; |
| 674 | } | 674 | } |
| 675 | 675 | ||
| 676 | kfree(ctx); | ||
| 677 | |||
| 678 | return 0; | 676 | return 0; |
| 679 | } | 677 | } |
| 680 | 678 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 409e2ec1207c..a6aea6f3ea1a 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c | |||
| @@ -2172,7 +2172,7 @@ static int __devinit hdmi_resources_init(struct hdmi_context *hdata) | |||
| 2172 | 2172 | ||
| 2173 | DRM_DEBUG_KMS("HDMI resource init\n"); | 2173 | DRM_DEBUG_KMS("HDMI resource init\n"); |
| 2174 | 2174 | ||
| 2175 | memset(res, 0, sizeof *res); | 2175 | memset(res, 0, sizeof(*res)); |
| 2176 | 2176 | ||
| 2177 | /* get clocks, power */ | 2177 | /* get clocks, power */ |
| 2178 | res->hdmi = clk_get(dev, "hdmi"); | 2178 | res->hdmi = clk_get(dev, "hdmi"); |
| @@ -2204,7 +2204,7 @@ static int __devinit hdmi_resources_init(struct hdmi_context *hdata) | |||
| 2204 | clk_set_parent(res->sclk_hdmi, res->sclk_pixel); | 2204 | clk_set_parent(res->sclk_hdmi, res->sclk_pixel); |
| 2205 | 2205 | ||
| 2206 | res->regul_bulk = kzalloc(ARRAY_SIZE(supply) * | 2206 | res->regul_bulk = kzalloc(ARRAY_SIZE(supply) * |
| 2207 | sizeof res->regul_bulk[0], GFP_KERNEL); | 2207 | sizeof(res->regul_bulk[0]), GFP_KERNEL); |
| 2208 | if (!res->regul_bulk) { | 2208 | if (!res->regul_bulk) { |
| 2209 | DRM_ERROR("failed to get memory for regulators\n"); | 2209 | DRM_ERROR("failed to get memory for regulators\n"); |
| 2210 | goto fail; | 2210 | goto fail; |
| @@ -2243,7 +2243,7 @@ static int hdmi_resources_cleanup(struct hdmi_context *hdata) | |||
| 2243 | clk_put(res->sclk_hdmi); | 2243 | clk_put(res->sclk_hdmi); |
| 2244 | if (!IS_ERR_OR_NULL(res->hdmi)) | 2244 | if (!IS_ERR_OR_NULL(res->hdmi)) |
| 2245 | clk_put(res->hdmi); | 2245 | clk_put(res->hdmi); |
| 2246 | memset(res, 0, sizeof *res); | 2246 | memset(res, 0, sizeof(*res)); |
| 2247 | 2247 | ||
| 2248 | return 0; | 2248 | return 0; |
| 2249 | } | 2249 | } |
| @@ -2312,11 +2312,6 @@ static int __devinit hdmi_probe(struct platform_device *pdev) | |||
| 2312 | } | 2312 | } |
| 2313 | 2313 | ||
| 2314 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 2314 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 2315 | if (!res) { | ||
| 2316 | DRM_ERROR("failed to find registers\n"); | ||
| 2317 | ret = -ENOENT; | ||
| 2318 | goto err_resource; | ||
| 2319 | } | ||
| 2320 | 2315 | ||
| 2321 | hdata->regs = devm_request_and_ioremap(&pdev->dev, res); | 2316 | hdata->regs = devm_request_and_ioremap(&pdev->dev, res); |
| 2322 | if (!hdata->regs) { | 2317 | if (!hdata->regs) { |
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 30fcc12f81dd..25b97d5e5fcb 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c | |||
| @@ -236,11 +236,11 @@ static inline void vp_filter_set(struct mixer_resources *res, | |||
| 236 | static void vp_default_filter(struct mixer_resources *res) | 236 | static void vp_default_filter(struct mixer_resources *res) |
| 237 | { | 237 | { |
| 238 | vp_filter_set(res, VP_POLY8_Y0_LL, | 238 | vp_filter_set(res, VP_POLY8_Y0_LL, |
| 239 | filter_y_horiz_tap8, sizeof filter_y_horiz_tap8); | 239 | filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8)); |
| 240 | vp_filter_set(res, VP_POLY4_Y0_LL, | 240 | vp_filter_set(res, VP_POLY4_Y0_LL, |
| 241 | filter_y_vert_tap4, sizeof filter_y_vert_tap4); | 241 | filter_y_vert_tap4, sizeof(filter_y_vert_tap4)); |
| 242 | vp_filter_set(res, VP_POLY4_C0_LL, | 242 | vp_filter_set(res, VP_POLY4_C0_LL, |
| 243 | filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4); | 243 | filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4)); |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable) | 246 | static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable) |
diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c index 0f9b7db80f6b..cf49ba5a54bf 100644 --- a/drivers/gpu/drm/gma500/oaktrail_device.c +++ b/drivers/gpu/drm/gma500/oaktrail_device.c | |||
| @@ -476,6 +476,7 @@ static const struct psb_offset oaktrail_regmap[2] = { | |||
| 476 | .pos = DSPAPOS, | 476 | .pos = DSPAPOS, |
| 477 | .surf = DSPASURF, | 477 | .surf = DSPASURF, |
| 478 | .addr = MRST_DSPABASE, | 478 | .addr = MRST_DSPABASE, |
| 479 | .base = MRST_DSPABASE, | ||
| 479 | .status = PIPEASTAT, | 480 | .status = PIPEASTAT, |
| 480 | .linoff = DSPALINOFF, | 481 | .linoff = DSPALINOFF, |
| 481 | .tileoff = DSPATILEOFF, | 482 | .tileoff = DSPATILEOFF, |
| @@ -499,6 +500,7 @@ static const struct psb_offset oaktrail_regmap[2] = { | |||
| 499 | .pos = DSPBPOS, | 500 | .pos = DSPBPOS, |
| 500 | .surf = DSPBSURF, | 501 | .surf = DSPBSURF, |
| 501 | .addr = DSPBBASE, | 502 | .addr = DSPBBASE, |
| 503 | .base = DSPBBASE, | ||
| 502 | .status = PIPEBSTAT, | 504 | .status = PIPEBSTAT, |
| 503 | .linoff = DSPBLINOFF, | 505 | .linoff = DSPBLINOFF, |
| 504 | .tileoff = DSPBTILEOFF, | 506 | .tileoff = DSPBTILEOFF, |
diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c index 57d892eaaa6e..463ec6871fe9 100644 --- a/drivers/gpu/drm/i810/i810_dma.c +++ b/drivers/gpu/drm/i810/i810_dma.c | |||
| @@ -115,6 +115,9 @@ static const struct file_operations i810_buffer_fops = { | |||
| 115 | .unlocked_ioctl = drm_ioctl, | 115 | .unlocked_ioctl = drm_ioctl, |
| 116 | .mmap = i810_mmap_buffers, | 116 | .mmap = i810_mmap_buffers, |
| 117 | .fasync = drm_fasync, | 117 | .fasync = drm_fasync, |
| 118 | #ifdef CONFIG_COMPAT | ||
| 119 | .compat_ioctl = drm_compat_ioctl, | ||
| 120 | #endif | ||
| 118 | .llseek = noop_llseek, | 121 | .llseek = noop_llseek, |
| 119 | }; | 122 | }; |
| 120 | 123 | ||
diff --git a/drivers/gpu/drm/i810/i810_drv.c b/drivers/gpu/drm/i810/i810_drv.c index f9924ad04d09..48cfcca2b350 100644 --- a/drivers/gpu/drm/i810/i810_drv.c +++ b/drivers/gpu/drm/i810/i810_drv.c | |||
| @@ -51,6 +51,9 @@ static const struct file_operations i810_driver_fops = { | |||
| 51 | .mmap = drm_mmap, | 51 | .mmap = drm_mmap, |
| 52 | .poll = drm_poll, | 52 | .poll = drm_poll, |
| 53 | .fasync = drm_fasync, | 53 | .fasync = drm_fasync, |
| 54 | #ifdef CONFIG_COMPAT | ||
| 55 | .compat_ioctl = drm_compat_ioctl, | ||
| 56 | #endif | ||
| 54 | .llseek = noop_llseek, | 57 | .llseek = noop_llseek, |
| 55 | }; | 58 | }; |
| 56 | 59 | ||
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 9cf7dfe022b9..914c0dfabe60 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
| @@ -1587,6 +1587,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
| 1587 | spin_lock_init(&dev_priv->irq_lock); | 1587 | spin_lock_init(&dev_priv->irq_lock); |
| 1588 | spin_lock_init(&dev_priv->error_lock); | 1588 | spin_lock_init(&dev_priv->error_lock); |
| 1589 | spin_lock_init(&dev_priv->rps_lock); | 1589 | spin_lock_init(&dev_priv->rps_lock); |
| 1590 | spin_lock_init(&dev_priv->dpio_lock); | ||
| 1590 | 1591 | ||
| 1591 | if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) | 1592 | if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) |
| 1592 | dev_priv->num_pipe = 3; | 1593 | dev_priv->num_pipe = 3; |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 489e2b162b27..274d25de521e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
| @@ -3242,7 +3242,8 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, | |||
| 3242 | { | 3242 | { |
| 3243 | int ret; | 3243 | int ret; |
| 3244 | 3244 | ||
| 3245 | BUG_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT); | 3245 | if (WARN_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT)) |
| 3246 | return -EBUSY; | ||
| 3246 | 3247 | ||
| 3247 | if (obj->gtt_space != NULL) { | 3248 | if (obj->gtt_space != NULL) { |
| 3248 | if ((alignment && obj->gtt_offset & (alignment - 1)) || | 3249 | if ((alignment && obj->gtt_offset & (alignment - 1)) || |
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8a3828528b9d..5249640cce13 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
| @@ -2700,9 +2700,6 @@ void intel_irq_init(struct drm_device *dev) | |||
| 2700 | dev->driver->irq_handler = i8xx_irq_handler; | 2700 | dev->driver->irq_handler = i8xx_irq_handler; |
| 2701 | dev->driver->irq_uninstall = i8xx_irq_uninstall; | 2701 | dev->driver->irq_uninstall = i8xx_irq_uninstall; |
| 2702 | } else if (INTEL_INFO(dev)->gen == 3) { | 2702 | } else if (INTEL_INFO(dev)->gen == 3) { |
| 2703 | /* IIR "flip pending" means done if this bit is set */ | ||
| 2704 | I915_WRITE(ECOSKPD, _MASKED_BIT_DISABLE(ECO_FLIP_DONE)); | ||
| 2705 | |||
| 2706 | dev->driver->irq_preinstall = i915_irq_preinstall; | 2703 | dev->driver->irq_preinstall = i915_irq_preinstall; |
| 2707 | dev->driver->irq_postinstall = i915_irq_postinstall; | 2704 | dev->driver->irq_postinstall = i915_irq_postinstall; |
| 2708 | dev->driver->irq_uninstall = i915_irq_uninstall; | 2705 | dev->driver->irq_uninstall = i915_irq_uninstall; |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2dfa6cf4886b..c040aee1341c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
| @@ -1376,7 +1376,8 @@ static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, | |||
| 1376 | "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n", | 1376 | "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n", |
| 1377 | reg, pipe_name(pipe)); | 1377 | reg, pipe_name(pipe)); |
| 1378 | 1378 | ||
| 1379 | WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_PIPE_B_SELECT), | 1379 | WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0 |
| 1380 | && (val & DP_PIPEB_SELECT), | ||
| 1380 | "IBX PCH dp port still using transcoder B\n"); | 1381 | "IBX PCH dp port still using transcoder B\n"); |
| 1381 | } | 1382 | } |
| 1382 | 1383 | ||
| @@ -1388,7 +1389,8 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, | |||
| 1388 | "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n", | 1389 | "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n", |
| 1389 | reg, pipe_name(pipe)); | 1390 | reg, pipe_name(pipe)); |
| 1390 | 1391 | ||
| 1391 | WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_PIPE_B_SELECT), | 1392 | WARN(HAS_PCH_IBX(dev_priv->dev) && (val & PORT_ENABLE) == 0 |
| 1393 | && (val & SDVO_PIPE_B_SELECT), | ||
| 1392 | "IBX PCH hdmi port still using transcoder B\n"); | 1394 | "IBX PCH hdmi port still using transcoder B\n"); |
| 1393 | } | 1395 | } |
| 1394 | 1396 | ||
| @@ -4189,12 +4191,6 @@ static void i8xx_update_pll(struct drm_crtc *crtc, | |||
| 4189 | POSTING_READ(DPLL(pipe)); | 4191 | POSTING_READ(DPLL(pipe)); |
| 4190 | udelay(150); | 4192 | udelay(150); |
| 4191 | 4193 | ||
| 4192 | I915_WRITE(DPLL(pipe), dpll); | ||
| 4193 | |||
| 4194 | /* Wait for the clocks to stabilize. */ | ||
| 4195 | POSTING_READ(DPLL(pipe)); | ||
| 4196 | udelay(150); | ||
| 4197 | |||
| 4198 | /* The LVDS pin pair needs to be on before the DPLLs are enabled. | 4194 | /* The LVDS pin pair needs to be on before the DPLLs are enabled. |
| 4199 | * This is an exception to the general rule that mode_set doesn't turn | 4195 | * This is an exception to the general rule that mode_set doesn't turn |
| 4200 | * things on. | 4196 | * things on. |
| @@ -4202,6 +4198,12 @@ static void i8xx_update_pll(struct drm_crtc *crtc, | |||
| 4202 | if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) | 4198 | if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) |
| 4203 | intel_update_lvds(crtc, clock, adjusted_mode); | 4199 | intel_update_lvds(crtc, clock, adjusted_mode); |
| 4204 | 4200 | ||
| 4201 | I915_WRITE(DPLL(pipe), dpll); | ||
| 4202 | |||
| 4203 | /* Wait for the clocks to stabilize. */ | ||
| 4204 | POSTING_READ(DPLL(pipe)); | ||
| 4205 | udelay(150); | ||
| 4206 | |||
| 4205 | /* The pixel multiplier can only be updated once the | 4207 | /* The pixel multiplier can only be updated once the |
| 4206 | * DPLL is enabled and the clocks are stable. | 4208 | * DPLL is enabled and the clocks are stable. |
| 4207 | * | 4209 | * |
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a6c426afaa7a..ace757af9133 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
| @@ -2533,14 +2533,10 @@ intel_dp_init(struct drm_device *dev, int output_reg) | |||
| 2533 | break; | 2533 | break; |
| 2534 | } | 2534 | } |
| 2535 | 2535 | ||
| 2536 | intel_dp_i2c_init(intel_dp, intel_connector, name); | ||
| 2537 | |||
| 2538 | /* Cache some DPCD data in the eDP case */ | 2536 | /* Cache some DPCD data in the eDP case */ |
| 2539 | if (is_edp(intel_dp)) { | 2537 | if (is_edp(intel_dp)) { |
| 2540 | bool ret; | ||
| 2541 | struct edp_power_seq cur, vbt; | 2538 | struct edp_power_seq cur, vbt; |
| 2542 | u32 pp_on, pp_off, pp_div; | 2539 | u32 pp_on, pp_off, pp_div; |
| 2543 | struct edid *edid; | ||
| 2544 | 2540 | ||
| 2545 | pp_on = I915_READ(PCH_PP_ON_DELAYS); | 2541 | pp_on = I915_READ(PCH_PP_ON_DELAYS); |
| 2546 | pp_off = I915_READ(PCH_PP_OFF_DELAYS); | 2542 | pp_off = I915_READ(PCH_PP_OFF_DELAYS); |
| @@ -2591,6 +2587,13 @@ intel_dp_init(struct drm_device *dev, int output_reg) | |||
| 2591 | 2587 | ||
| 2592 | DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n", | 2588 | DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n", |
| 2593 | intel_dp->backlight_on_delay, intel_dp->backlight_off_delay); | 2589 | intel_dp->backlight_on_delay, intel_dp->backlight_off_delay); |
| 2590 | } | ||
| 2591 | |||
| 2592 | intel_dp_i2c_init(intel_dp, intel_connector, name); | ||
| 2593 | |||
| 2594 | if (is_edp(intel_dp)) { | ||
| 2595 | bool ret; | ||
| 2596 | struct edid *edid; | ||
| 2594 | 2597 | ||
| 2595 | ironlake_edp_panel_vdd_on(intel_dp); | 2598 | ironlake_edp_panel_vdd_on(intel_dp); |
| 2596 | ret = intel_dp_get_dpcd(intel_dp); | 2599 | ret = intel_dp_get_dpcd(intel_dp); |
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 98f602427eb8..12dc3308ab8c 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c | |||
| @@ -609,7 +609,7 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) | |||
| 609 | u32 temp; | 609 | u32 temp; |
| 610 | u32 enable_bits = SDVO_ENABLE; | 610 | u32 enable_bits = SDVO_ENABLE; |
| 611 | 611 | ||
| 612 | if (intel_hdmi->has_audio) | 612 | if (intel_hdmi->has_audio || mode != DRM_MODE_DPMS_ON) |
| 613 | enable_bits |= SDVO_AUDIO_ENABLE; | 613 | enable_bits |= SDVO_AUDIO_ENABLE; |
| 614 | 614 | ||
| 615 | temp = I915_READ(intel_hdmi->sdvox_reg); | 615 | temp = I915_READ(intel_hdmi->sdvox_reg); |
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 3df4f5fa892a..e019b2369861 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c | |||
| @@ -162,19 +162,12 @@ static u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv) | |||
| 162 | return val; | 162 | return val; |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | u32 intel_panel_get_max_backlight(struct drm_device *dev) | 165 | static u32 _intel_panel_get_max_backlight(struct drm_device *dev) |
| 166 | { | 166 | { |
| 167 | struct drm_i915_private *dev_priv = dev->dev_private; | 167 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 168 | u32 max; | 168 | u32 max; |
| 169 | 169 | ||
| 170 | max = i915_read_blc_pwm_ctl(dev_priv); | 170 | max = i915_read_blc_pwm_ctl(dev_priv); |
| 171 | if (max == 0) { | ||
| 172 | /* XXX add code here to query mode clock or hardware clock | ||
| 173 | * and program max PWM appropriately. | ||
| 174 | */ | ||
| 175 | pr_warn_once("fixme: max PWM is zero\n"); | ||
| 176 | return 1; | ||
| 177 | } | ||
| 178 | 171 | ||
| 179 | if (HAS_PCH_SPLIT(dev)) { | 172 | if (HAS_PCH_SPLIT(dev)) { |
| 180 | max >>= 16; | 173 | max >>= 16; |
| @@ -188,6 +181,22 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev) | |||
| 188 | max *= 0xff; | 181 | max *= 0xff; |
| 189 | } | 182 | } |
| 190 | 183 | ||
| 184 | return max; | ||
| 185 | } | ||
| 186 | |||
| 187 | u32 intel_panel_get_max_backlight(struct drm_device *dev) | ||
| 188 | { | ||
| 189 | u32 max; | ||
| 190 | |||
| 191 | max = _intel_panel_get_max_backlight(dev); | ||
| 192 | if (max == 0) { | ||
| 193 | /* XXX add code here to query mode clock or hardware clock | ||
| 194 | * and program max PWM appropriately. | ||
| 195 | */ | ||
| 196 | pr_warn_once("fixme: max PWM is zero\n"); | ||
| 197 | return 1; | ||
| 198 | } | ||
| 199 | |||
| 191 | DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); | 200 | DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); |
| 192 | return max; | 201 | return max; |
| 193 | } | 202 | } |
| @@ -424,7 +433,11 @@ int intel_panel_setup_backlight(struct drm_device *dev) | |||
| 424 | 433 | ||
| 425 | memset(&props, 0, sizeof(props)); | 434 | memset(&props, 0, sizeof(props)); |
| 426 | props.type = BACKLIGHT_RAW; | 435 | props.type = BACKLIGHT_RAW; |
| 427 | props.max_brightness = intel_panel_get_max_backlight(dev); | 436 | props.max_brightness = _intel_panel_get_max_backlight(dev); |
| 437 | if (props.max_brightness == 0) { | ||
| 438 | DRM_ERROR("Failed to get maximum backlight value\n"); | ||
| 439 | return -ENODEV; | ||
| 440 | } | ||
| 428 | dev_priv->backlight = | 441 | dev_priv->backlight = |
| 429 | backlight_device_register("intel_backlight", | 442 | backlight_device_register("intel_backlight", |
| 430 | &connector->kdev, dev, | 443 | &connector->kdev, dev, |
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 1881c8c83f0e..ba8a27b1757a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c | |||
| @@ -3672,6 +3672,9 @@ static void gen3_init_clock_gating(struct drm_device *dev) | |||
| 3672 | 3672 | ||
| 3673 | if (IS_PINEVIEW(dev)) | 3673 | if (IS_PINEVIEW(dev)) |
| 3674 | I915_WRITE(ECOSKPD, _MASKED_BIT_ENABLE(ECO_GATING_CX_ONLY)); | 3674 | I915_WRITE(ECOSKPD, _MASKED_BIT_ENABLE(ECO_GATING_CX_ONLY)); |
| 3675 | |||
| 3676 | /* IIR "flip pending" means done if this bit is set */ | ||
| 3677 | I915_WRITE(ECOSKPD, _MASKED_BIT_DISABLE(ECO_FLIP_DONE)); | ||
| 3675 | } | 3678 | } |
| 3676 | 3679 | ||
| 3677 | static void i85x_init_clock_gating(struct drm_device *dev) | 3680 | static void i85x_init_clock_gating(struct drm_device *dev) |
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index d81bb0bf2885..123afd357611 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |||
| @@ -2573,7 +2573,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) | |||
| 2573 | hotplug_mask = intel_sdvo->is_sdvob ? | 2573 | hotplug_mask = intel_sdvo->is_sdvob ? |
| 2574 | SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915; | 2574 | SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915; |
| 2575 | } | 2575 | } |
| 2576 | dev_priv->hotplug_supported_mask |= hotplug_mask; | ||
| 2577 | 2576 | ||
| 2578 | drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs); | 2577 | drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs); |
| 2579 | 2578 | ||
| @@ -2581,14 +2580,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) | |||
| 2581 | if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) | 2580 | if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) |
| 2582 | goto err; | 2581 | goto err; |
| 2583 | 2582 | ||
| 2584 | /* Set up hotplug command - note paranoia about contents of reply. | ||
| 2585 | * We assume that the hardware is in a sane state, and only touch | ||
| 2586 | * the bits we think we understand. | ||
| 2587 | */ | ||
| 2588 | intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, | ||
| 2589 | &intel_sdvo->hotplug_active, 2); | ||
| 2590 | intel_sdvo->hotplug_active[0] &= ~0x3; | ||
| 2591 | |||
| 2592 | if (intel_sdvo_output_setup(intel_sdvo, | 2583 | if (intel_sdvo_output_setup(intel_sdvo, |
| 2593 | intel_sdvo->caps.output_flags) != true) { | 2584 | intel_sdvo->caps.output_flags) != true) { |
| 2594 | DRM_DEBUG_KMS("SDVO output failed to setup on %s\n", | 2585 | DRM_DEBUG_KMS("SDVO output failed to setup on %s\n", |
| @@ -2596,6 +2587,12 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) | |||
| 2596 | goto err; | 2587 | goto err; |
| 2597 | } | 2588 | } |
| 2598 | 2589 | ||
| 2590 | /* Only enable the hotplug irq if we need it, to work around noisy | ||
| 2591 | * hotplug lines. | ||
| 2592 | */ | ||
| 2593 | if (intel_sdvo->hotplug_active[0]) | ||
| 2594 | dev_priv->hotplug_supported_mask |= hotplug_mask; | ||
| 2595 | |||
| 2599 | intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); | 2596 | intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); |
| 2600 | 2597 | ||
| 2601 | /* Set the input timing to the screen. Assume always input 0. */ | 2598 | /* Set the input timing to the screen. Assume always input 0. */ |
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index ea1024d79974..e5f145d2cb3b 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c | |||
| @@ -84,6 +84,9 @@ static const struct file_operations mgag200_driver_fops = { | |||
| 84 | .mmap = mgag200_mmap, | 84 | .mmap = mgag200_mmap, |
| 85 | .poll = drm_poll, | 85 | .poll = drm_poll, |
| 86 | .fasync = drm_fasync, | 86 | .fasync = drm_fasync, |
| 87 | #ifdef CONFIG_COMPAT | ||
| 88 | .compat_ioctl = drm_compat_ioctl, | ||
| 89 | #endif | ||
| 87 | .read = drm_read, | 90 | .read = drm_read, |
| 88 | }; | 91 | }; |
| 89 | 92 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index ff23d88880e5..3ca240b4413d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c | |||
| @@ -179,7 +179,7 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) | |||
| 179 | return 0; | 179 | return 0; |
| 180 | } else | 180 | } else |
| 181 | if (init->class == 0x906e) { | 181 | if (init->class == 0x906e) { |
| 182 | NV_ERROR(dev, "906e not supported yet\n"); | 182 | NV_DEBUG(dev, "906e not supported yet\n"); |
| 183 | return -EINVAL; | 183 | return -EINVAL; |
| 184 | } | 184 | } |
| 185 | 185 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 69688ef5cf46..7e16dc5e6467 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
| @@ -598,7 +598,7 @@ nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev, | |||
| 598 | args->size = args->pitch * args->height; | 598 | args->size = args->pitch * args->height; |
| 599 | args->size = roundup(args->size, PAGE_SIZE); | 599 | args->size = roundup(args->size, PAGE_SIZE); |
| 600 | 600 | ||
| 601 | ret = nouveau_gem_new(dev, args->size, 0, TTM_PL_FLAG_VRAM, 0, 0, &bo); | 601 | ret = nouveau_gem_new(dev, args->size, 0, NOUVEAU_GEM_DOMAIN_VRAM, 0, 0, &bo); |
| 602 | if (ret) | 602 | if (ret) |
| 603 | return ret; | 603 | return ret; |
| 604 | 604 | ||
diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c index f429e6a8ca7a..c399d510b27a 100644 --- a/drivers/gpu/drm/nouveau/nv50_gpio.c +++ b/drivers/gpu/drm/nouveau/nv50_gpio.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | * Authors: Ben Skeggs | 22 | * Authors: Ben Skeggs |
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #include <linux/dmi.h> | ||
| 25 | #include "drmP.h" | 26 | #include "drmP.h" |
| 26 | #include "nouveau_drv.h" | 27 | #include "nouveau_drv.h" |
| 27 | #include "nouveau_hw.h" | 28 | #include "nouveau_hw.h" |
| @@ -110,11 +111,26 @@ nv50_gpio_isr(struct drm_device *dev) | |||
| 110 | nv_wr32(dev, 0xe074, intr1); | 111 | nv_wr32(dev, 0xe074, intr1); |
| 111 | } | 112 | } |
| 112 | 113 | ||
| 114 | static struct dmi_system_id gpio_reset_ids[] = { | ||
| 115 | { | ||
| 116 | .ident = "Apple Macbook 10,1", | ||
| 117 | .matches = { | ||
| 118 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
| 119 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"), | ||
| 120 | } | ||
| 121 | }, | ||
| 122 | { } | ||
| 123 | }; | ||
| 124 | |||
| 113 | int | 125 | int |
| 114 | nv50_gpio_init(struct drm_device *dev) | 126 | nv50_gpio_init(struct drm_device *dev) |
| 115 | { | 127 | { |
| 116 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 128 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
| 117 | 129 | ||
| 130 | /* initialise gpios and routing to vbios defaults */ | ||
| 131 | if (dmi_check_system(gpio_reset_ids)) | ||
| 132 | nouveau_gpio_reset(dev); | ||
| 133 | |||
| 118 | /* disable, and ack any pending gpio interrupts */ | 134 | /* disable, and ack any pending gpio interrupts */ |
| 119 | nv_wr32(dev, 0xe050, 0x00000000); | 135 | nv_wr32(dev, 0xe050, 0x00000000); |
| 120 | nv_wr32(dev, 0xe054, 0xffffffff); | 136 | nv_wr32(dev, 0xe054, 0xffffffff); |
diff --git a/drivers/gpu/drm/nouveau/nvc0_fb.c b/drivers/gpu/drm/nouveau/nvc0_fb.c index f704e942372e..f376c39310df 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fb.c +++ b/drivers/gpu/drm/nouveau/nvc0_fb.c | |||
| @@ -124,6 +124,7 @@ nvc0_fb_init(struct drm_device *dev) | |||
| 124 | priv = dev_priv->engine.fb.priv; | 124 | priv = dev_priv->engine.fb.priv; |
| 125 | 125 | ||
| 126 | nv_wr32(dev, 0x100c10, priv->r100c10 >> 8); | 126 | nv_wr32(dev, 0x100c10, priv->r100c10 >> 8); |
| 127 | nv_mask(dev, 0x17e820, 0x00100000, 0x00000000); /* NV_PLTCG_INTR_EN */ | ||
| 127 | return 0; | 128 | return 0; |
| 128 | } | 129 | } |
| 129 | 130 | ||
diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c index 7d85553d518c..cd39eb99f5b1 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fifo.c +++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c | |||
| @@ -373,7 +373,8 @@ nvc0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit) | |||
| 373 | static void | 373 | static void |
| 374 | nvc0_fifo_isr(struct drm_device *dev) | 374 | nvc0_fifo_isr(struct drm_device *dev) |
| 375 | { | 375 | { |
| 376 | u32 stat = nv_rd32(dev, 0x002100); | 376 | u32 mask = nv_rd32(dev, 0x002140); |
| 377 | u32 stat = nv_rd32(dev, 0x002100) & mask; | ||
| 377 | 378 | ||
| 378 | if (stat & 0x00000100) { | 379 | if (stat & 0x00000100) { |
| 379 | NV_INFO(dev, "PFIFO: unknown status 0x00000100\n"); | 380 | NV_INFO(dev, "PFIFO: unknown status 0x00000100\n"); |
diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c index dac525b2994e..8a2fc89b7763 100644 --- a/drivers/gpu/drm/nouveau/nvd0_display.c +++ b/drivers/gpu/drm/nouveau/nvd0_display.c | |||
| @@ -1510,10 +1510,10 @@ nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, | |||
| 1510 | case OUTPUT_DP: | 1510 | case OUTPUT_DP: |
| 1511 | if (nv_connector->base.display_info.bpc == 6) { | 1511 | if (nv_connector->base.display_info.bpc == 6) { |
| 1512 | nv_encoder->dp.datarate = mode->clock * 18 / 8; | 1512 | nv_encoder->dp.datarate = mode->clock * 18 / 8; |
| 1513 | syncs |= 0x00000140; | 1513 | syncs |= 0x00000002 << 6; |
| 1514 | } else { | 1514 | } else { |
| 1515 | nv_encoder->dp.datarate = mode->clock * 24 / 8; | 1515 | nv_encoder->dp.datarate = mode->clock * 24 / 8; |
| 1516 | syncs |= 0x00000180; | 1516 | syncs |= 0x00000005 << 6; |
| 1517 | } | 1517 | } |
| 1518 | 1518 | ||
| 1519 | if (nv_encoder->dcb->sorconf.link & 1) | 1519 | if (nv_encoder->dcb->sorconf.link & 1) |
diff --git a/drivers/gpu/drm/nouveau/nve0_fifo.c b/drivers/gpu/drm/nouveau/nve0_fifo.c index e98d144e6eb9..281bece751b6 100644 --- a/drivers/gpu/drm/nouveau/nve0_fifo.c +++ b/drivers/gpu/drm/nouveau/nve0_fifo.c | |||
| @@ -345,7 +345,8 @@ nve0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit) | |||
| 345 | static void | 345 | static void |
| 346 | nve0_fifo_isr(struct drm_device *dev) | 346 | nve0_fifo_isr(struct drm_device *dev) |
| 347 | { | 347 | { |
| 348 | u32 stat = nv_rd32(dev, 0x002100); | 348 | u32 mask = nv_rd32(dev, 0x002140); |
| 349 | u32 stat = nv_rd32(dev, 0x002100) & mask; | ||
| 349 | 350 | ||
| 350 | if (stat & 0x00000100) { | 351 | if (stat & 0x00000100) { |
| 351 | NV_INFO(dev, "PFIFO: unknown status 0x00000100\n"); | 352 | NV_INFO(dev, "PFIFO: unknown status 0x00000100\n"); |
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 8acb34fd3fd5..8d7e33a0b243 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c | |||
| @@ -1182,7 +1182,8 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) | |||
| 1182 | ring->ready = true; | 1182 | ring->ready = true; |
| 1183 | radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size); | 1183 | radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size); |
| 1184 | 1184 | ||
| 1185 | if (radeon_ring_supports_scratch_reg(rdev, ring)) { | 1185 | if (!ring->rptr_save_reg /* not resuming from suspend */ |
| 1186 | && radeon_ring_supports_scratch_reg(rdev, ring)) { | ||
| 1186 | r = radeon_scratch_get(rdev, &ring->rptr_save_reg); | 1187 | r = radeon_scratch_get(rdev, &ring->rptr_save_reg); |
| 1187 | if (r) { | 1188 | if (r) { |
| 1188 | DRM_ERROR("failed to get scratch reg for rptr save (%d).\n", r); | 1189 | DRM_ERROR("failed to get scratch reg for rptr save (%d).\n", r); |
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 7b737b9339ad..2a59375dbe52 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c | |||
| @@ -131,7 +131,7 @@ int radeon_fence_emit(struct radeon_device *rdev, | |||
| 131 | */ | 131 | */ |
| 132 | void radeon_fence_process(struct radeon_device *rdev, int ring) | 132 | void radeon_fence_process(struct radeon_device *rdev, int ring) |
| 133 | { | 133 | { |
| 134 | uint64_t seq, last_seq; | 134 | uint64_t seq, last_seq, last_emitted; |
| 135 | unsigned count_loop = 0; | 135 | unsigned count_loop = 0; |
| 136 | bool wake = false; | 136 | bool wake = false; |
| 137 | 137 | ||
| @@ -158,13 +158,15 @@ void radeon_fence_process(struct radeon_device *rdev, int ring) | |||
| 158 | */ | 158 | */ |
| 159 | last_seq = atomic64_read(&rdev->fence_drv[ring].last_seq); | 159 | last_seq = atomic64_read(&rdev->fence_drv[ring].last_seq); |
| 160 | do { | 160 | do { |
| 161 | last_emitted = rdev->fence_drv[ring].sync_seq[ring]; | ||
| 161 | seq = radeon_fence_read(rdev, ring); | 162 | seq = radeon_fence_read(rdev, ring); |
| 162 | seq |= last_seq & 0xffffffff00000000LL; | 163 | seq |= last_seq & 0xffffffff00000000LL; |
| 163 | if (seq < last_seq) { | 164 | if (seq < last_seq) { |
| 164 | seq += 0x100000000LL; | 165 | seq &= 0xffffffff; |
| 166 | seq |= last_emitted & 0xffffffff00000000LL; | ||
| 165 | } | 167 | } |
| 166 | 168 | ||
| 167 | if (seq == last_seq) { | 169 | if (seq <= last_seq || seq > last_emitted) { |
| 168 | break; | 170 | break; |
| 169 | } | 171 | } |
| 170 | /* If we loop over we don't want to return without | 172 | /* If we loop over we don't want to return without |
diff --git a/drivers/gpu/drm/savage/savage_drv.c b/drivers/gpu/drm/savage/savage_drv.c index d31d4cca9a4c..c5a164337bd5 100644 --- a/drivers/gpu/drm/savage/savage_drv.c +++ b/drivers/gpu/drm/savage/savage_drv.c | |||
| @@ -43,6 +43,9 @@ static const struct file_operations savage_driver_fops = { | |||
| 43 | .mmap = drm_mmap, | 43 | .mmap = drm_mmap, |
| 44 | .poll = drm_poll, | 44 | .poll = drm_poll, |
| 45 | .fasync = drm_fasync, | 45 | .fasync = drm_fasync, |
| 46 | #ifdef CONFIG_COMPAT | ||
| 47 | .compat_ioctl = drm_compat_ioctl, | ||
| 48 | #endif | ||
| 46 | .llseek = noop_llseek, | 49 | .llseek = noop_llseek, |
| 47 | }; | 50 | }; |
| 48 | 51 | ||
diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c index 7f119870147c..867dc03000e6 100644 --- a/drivers/gpu/drm/sis/sis_drv.c +++ b/drivers/gpu/drm/sis/sis_drv.c | |||
| @@ -74,6 +74,9 @@ static const struct file_operations sis_driver_fops = { | |||
| 74 | .mmap = drm_mmap, | 74 | .mmap = drm_mmap, |
| 75 | .poll = drm_poll, | 75 | .poll = drm_poll, |
| 76 | .fasync = drm_fasync, | 76 | .fasync = drm_fasync, |
| 77 | #ifdef CONFIG_COMPAT | ||
| 78 | .compat_ioctl = drm_compat_ioctl, | ||
| 79 | #endif | ||
| 77 | .llseek = noop_llseek, | 80 | .llseek = noop_llseek, |
| 78 | }; | 81 | }; |
| 79 | 82 | ||
diff --git a/drivers/gpu/drm/tdfx/tdfx_drv.c b/drivers/gpu/drm/tdfx/tdfx_drv.c index 90f6b13acfac..a7f4d6bd1330 100644 --- a/drivers/gpu/drm/tdfx/tdfx_drv.c +++ b/drivers/gpu/drm/tdfx/tdfx_drv.c | |||
| @@ -49,6 +49,9 @@ static const struct file_operations tdfx_driver_fops = { | |||
| 49 | .mmap = drm_mmap, | 49 | .mmap = drm_mmap, |
| 50 | .poll = drm_poll, | 50 | .poll = drm_poll, |
| 51 | .fasync = drm_fasync, | 51 | .fasync = drm_fasync, |
| 52 | #ifdef CONFIG_COMPAT | ||
| 53 | .compat_ioctl = drm_compat_ioctl, | ||
| 54 | #endif | ||
| 52 | .llseek = noop_llseek, | 55 | .llseek = noop_llseek, |
| 53 | }; | 56 | }; |
| 54 | 57 | ||
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index ba055e9ca007..8d9dc44f1f94 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c | |||
| @@ -69,6 +69,13 @@ static int udl_get_modes(struct drm_connector *connector) | |||
| 69 | static int udl_mode_valid(struct drm_connector *connector, | 69 | static int udl_mode_valid(struct drm_connector *connector, |
| 70 | struct drm_display_mode *mode) | 70 | struct drm_display_mode *mode) |
| 71 | { | 71 | { |
| 72 | struct udl_device *udl = connector->dev->dev_private; | ||
| 73 | if (!udl->sku_pixel_limit) | ||
| 74 | return 0; | ||
| 75 | |||
| 76 | if (mode->vdisplay * mode->hdisplay > udl->sku_pixel_limit) | ||
| 77 | return MODE_VIRTUAL_Y; | ||
| 78 | |||
| 72 | return 0; | 79 | return 0; |
| 73 | } | 80 | } |
| 74 | 81 | ||
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index 6e52069894b3..9f84128505bb 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c | |||
| @@ -66,6 +66,9 @@ static const struct file_operations udl_driver_fops = { | |||
| 66 | .unlocked_ioctl = drm_ioctl, | 66 | .unlocked_ioctl = drm_ioctl, |
| 67 | .release = drm_release, | 67 | .release = drm_release, |
| 68 | .fasync = drm_fasync, | 68 | .fasync = drm_fasync, |
| 69 | #ifdef CONFIG_COMPAT | ||
| 70 | .compat_ioctl = drm_compat_ioctl, | ||
| 71 | #endif | ||
| 69 | .llseek = noop_llseek, | 72 | .llseek = noop_llseek, |
| 70 | }; | 73 | }; |
| 71 | 74 | ||
diff --git a/drivers/gpu/drm/via/via_drv.c b/drivers/gpu/drm/via/via_drv.c index e927b4c052f5..af1b914b17e3 100644 --- a/drivers/gpu/drm/via/via_drv.c +++ b/drivers/gpu/drm/via/via_drv.c | |||
| @@ -65,6 +65,9 @@ static const struct file_operations via_driver_fops = { | |||
| 65 | .mmap = drm_mmap, | 65 | .mmap = drm_mmap, |
| 66 | .poll = drm_poll, | 66 | .poll = drm_poll, |
| 67 | .fasync = drm_fasync, | 67 | .fasync = drm_fasync, |
| 68 | #ifdef CONFIG_COMPAT | ||
| 69 | .compat_ioctl = drm_compat_ioctl, | ||
| 70 | #endif | ||
| 68 | .llseek = noop_llseek, | 71 | .llseek = noop_llseek, |
| 69 | }; | 72 | }; |
| 70 | 73 | ||
diff --git a/drivers/gpu/drm/vmwgfx/Kconfig b/drivers/gpu/drm/vmwgfx/Kconfig index 794ff67c5701..b71bcd0bfbbf 100644 --- a/drivers/gpu/drm/vmwgfx/Kconfig +++ b/drivers/gpu/drm/vmwgfx/Kconfig | |||
| @@ -12,3 +12,11 @@ config DRM_VMWGFX | |||
| 12 | This is a KMS enabled DRM driver for the VMware SVGA2 | 12 | This is a KMS enabled DRM driver for the VMware SVGA2 |
| 13 | virtual hardware. | 13 | virtual hardware. |
| 14 | The compiled module will be called "vmwgfx.ko". | 14 | The compiled module will be called "vmwgfx.ko". |
| 15 | |||
| 16 | config DRM_VMWGFX_FBCON | ||
| 17 | depends on DRM_VMWGFX | ||
| 18 | bool "Enable framebuffer console under vmwgfx by default" | ||
| 19 | help | ||
| 20 | Choose this option if you are shipping a new vmwgfx | ||
| 21 | userspace driver that supports using the kernel driver. | ||
| 22 | |||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 4d9edead01ac..ba2c35dbf10e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | |||
| @@ -182,8 +182,9 @@ static struct pci_device_id vmw_pci_id_list[] = { | |||
| 182 | {0x15ad, 0x0405, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VMWGFX_CHIP_SVGAII}, | 182 | {0x15ad, 0x0405, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VMWGFX_CHIP_SVGAII}, |
| 183 | {0, 0, 0} | 183 | {0, 0, 0} |
| 184 | }; | 184 | }; |
| 185 | MODULE_DEVICE_TABLE(pci, vmw_pci_id_list); | ||
| 185 | 186 | ||
| 186 | static int enable_fbdev; | 187 | static int enable_fbdev = IS_ENABLED(CONFIG_DRM_VMWGFX_FBCON); |
| 187 | 188 | ||
| 188 | static int vmw_probe(struct pci_dev *, const struct pci_device_id *); | 189 | static int vmw_probe(struct pci_dev *, const struct pci_device_id *); |
| 189 | static void vmw_master_init(struct vmw_master *); | 190 | static void vmw_master_init(struct vmw_master *); |
| @@ -1154,6 +1155,11 @@ static struct drm_driver driver = { | |||
| 1154 | .open = vmw_driver_open, | 1155 | .open = vmw_driver_open, |
| 1155 | .preclose = vmw_preclose, | 1156 | .preclose = vmw_preclose, |
| 1156 | .postclose = vmw_postclose, | 1157 | .postclose = vmw_postclose, |
| 1158 | |||
| 1159 | .dumb_create = vmw_dumb_create, | ||
| 1160 | .dumb_map_offset = vmw_dumb_map_offset, | ||
| 1161 | .dumb_destroy = vmw_dumb_destroy, | ||
| 1162 | |||
| 1157 | .fops = &vmwgfx_driver_fops, | 1163 | .fops = &vmwgfx_driver_fops, |
| 1158 | .name = VMWGFX_DRIVER_NAME, | 1164 | .name = VMWGFX_DRIVER_NAME, |
| 1159 | .desc = VMWGFX_DRIVER_DESC, | 1165 | .desc = VMWGFX_DRIVER_DESC, |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index d0f2c079ee27..29c984ff7f23 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | |||
| @@ -645,6 +645,16 @@ int vmw_kms_readback(struct vmw_private *dev_priv, | |||
| 645 | int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, | 645 | int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, |
| 646 | struct drm_file *file_priv); | 646 | struct drm_file *file_priv); |
| 647 | 647 | ||
| 648 | int vmw_dumb_create(struct drm_file *file_priv, | ||
| 649 | struct drm_device *dev, | ||
| 650 | struct drm_mode_create_dumb *args); | ||
| 651 | |||
| 652 | int vmw_dumb_map_offset(struct drm_file *file_priv, | ||
| 653 | struct drm_device *dev, uint32_t handle, | ||
| 654 | uint64_t *offset); | ||
| 655 | int vmw_dumb_destroy(struct drm_file *file_priv, | ||
| 656 | struct drm_device *dev, | ||
| 657 | uint32_t handle); | ||
| 648 | /** | 658 | /** |
| 649 | * Overlay control - vmwgfx_overlay.c | 659 | * Overlay control - vmwgfx_overlay.c |
| 650 | */ | 660 | */ |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index f2fb8f15e2f1..7e0743358dff 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | |||
| @@ -1018,7 +1018,7 @@ int vmw_event_fence_action_create(struct drm_file *file_priv, | |||
| 1018 | } | 1018 | } |
| 1019 | 1019 | ||
| 1020 | 1020 | ||
| 1021 | event = kzalloc(sizeof(event->event), GFP_KERNEL); | 1021 | event = kzalloc(sizeof(*event), GFP_KERNEL); |
| 1022 | if (unlikely(event == NULL)) { | 1022 | if (unlikely(event == NULL)) { |
| 1023 | DRM_ERROR("Failed to allocate an event.\n"); | 1023 | DRM_ERROR("Failed to allocate an event.\n"); |
| 1024 | ret = -ENOMEM; | 1024 | ret = -ENOMEM; |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 22bf9a21ec71..2c6ffe0e2c07 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | |||
| @@ -1917,3 +1917,76 @@ err_ref: | |||
| 1917 | vmw_resource_unreference(&res); | 1917 | vmw_resource_unreference(&res); |
| 1918 | return ret; | 1918 | return ret; |
| 1919 | } | 1919 | } |
| 1920 | |||
| 1921 | |||
| 1922 | int vmw_dumb_create(struct drm_file *file_priv, | ||
| 1923 | struct drm_device *dev, | ||
| 1924 | struct drm_mode_create_dumb *args) | ||
| 1925 | { | ||
| 1926 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
| 1927 | struct vmw_master *vmaster = vmw_master(file_priv->master); | ||
| 1928 | struct vmw_user_dma_buffer *vmw_user_bo; | ||
| 1929 | struct ttm_buffer_object *tmp; | ||
| 1930 | int ret; | ||
| 1931 | |||
| 1932 | args->pitch = args->width * ((args->bpp + 7) / 8); | ||
| 1933 | args->size = args->pitch * args->height; | ||
| 1934 | |||
| 1935 | vmw_user_bo = kzalloc(sizeof(*vmw_user_bo), GFP_KERNEL); | ||
| 1936 | if (vmw_user_bo == NULL) | ||
| 1937 | return -ENOMEM; | ||
| 1938 | |||
| 1939 | ret = ttm_read_lock(&vmaster->lock, true); | ||
| 1940 | if (ret != 0) { | ||
| 1941 | kfree(vmw_user_bo); | ||
| 1942 | return ret; | ||
| 1943 | } | ||
| 1944 | |||
| 1945 | ret = vmw_dmabuf_init(dev_priv, &vmw_user_bo->dma, args->size, | ||
| 1946 | &vmw_vram_sys_placement, true, | ||
| 1947 | &vmw_user_dmabuf_destroy); | ||
| 1948 | if (ret != 0) | ||
| 1949 | goto out_no_dmabuf; | ||
| 1950 | |||
| 1951 | tmp = ttm_bo_reference(&vmw_user_bo->dma.base); | ||
| 1952 | ret = ttm_base_object_init(vmw_fpriv(file_priv)->tfile, | ||
| 1953 | &vmw_user_bo->base, | ||
| 1954 | false, | ||
| 1955 | ttm_buffer_type, | ||
| 1956 | &vmw_user_dmabuf_release, NULL); | ||
| 1957 | if (unlikely(ret != 0)) | ||
| 1958 | goto out_no_base_object; | ||
| 1959 | |||
| 1960 | args->handle = vmw_user_bo->base.hash.key; | ||
| 1961 | |||
| 1962 | out_no_base_object: | ||
| 1963 | ttm_bo_unref(&tmp); | ||
| 1964 | out_no_dmabuf: | ||
| 1965 | ttm_read_unlock(&vmaster->lock); | ||
| 1966 | return ret; | ||
| 1967 | } | ||
| 1968 | |||
| 1969 | int vmw_dumb_map_offset(struct drm_file *file_priv, | ||
| 1970 | struct drm_device *dev, uint32_t handle, | ||
| 1971 | uint64_t *offset) | ||
| 1972 | { | ||
| 1973 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | ||
| 1974 | struct vmw_dma_buffer *out_buf; | ||
| 1975 | int ret; | ||
| 1976 | |||
| 1977 | ret = vmw_user_dmabuf_lookup(tfile, handle, &out_buf); | ||
| 1978 | if (ret != 0) | ||
| 1979 | return -EINVAL; | ||
| 1980 | |||
| 1981 | *offset = out_buf->base.addr_space_offset; | ||
| 1982 | vmw_dmabuf_unreference(&out_buf); | ||
| 1983 | return 0; | ||
| 1984 | } | ||
| 1985 | |||
| 1986 | int vmw_dumb_destroy(struct drm_file *file_priv, | ||
| 1987 | struct drm_device *dev, | ||
| 1988 | uint32_t handle) | ||
| 1989 | { | ||
| 1990 | return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, | ||
| 1991 | handle, TTM_REF_USAGE); | ||
| 1992 | } | ||
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index fbf49503508d..2af774ad1060 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig | |||
| @@ -307,7 +307,6 @@ config HID_LOGITECH | |||
| 307 | config HID_LOGITECH_DJ | 307 | config HID_LOGITECH_DJ |
| 308 | tristate "Logitech Unifying receivers full support" | 308 | tristate "Logitech Unifying receivers full support" |
| 309 | depends on HID_LOGITECH | 309 | depends on HID_LOGITECH |
| 310 | default m | ||
| 311 | ---help--- | 310 | ---help--- |
| 312 | Say Y if you want support for Logitech Unifying receivers and devices. | 311 | Say Y if you want support for Logitech Unifying receivers and devices. |
| 313 | Unifying receivers are capable of pairing up to 6 Logitech compliant | 312 | Unifying receivers are capable of pairing up to 6 Logitech compliant |
| @@ -527,6 +526,14 @@ config HID_PICOLCD_LEDS | |||
| 527 | ---help--- | 526 | ---help--- |
| 528 | Provide access to PicoLCD's GPO pins via leds class. | 527 | Provide access to PicoLCD's GPO pins via leds class. |
| 529 | 528 | ||
| 529 | config HID_PICOLCD_CIR | ||
| 530 | bool "CIR via RC class" if EXPERT | ||
| 531 | default !EXPERT | ||
| 532 | depends on HID_PICOLCD | ||
| 533 | depends on HID_PICOLCD=RC_CORE || RC_CORE=y | ||
| 534 | ---help--- | ||
| 535 | Provide access to PicoLCD's CIR interface via remote control (LIRC). | ||
| 536 | |||
| 530 | config HID_PRIMAX | 537 | config HID_PRIMAX |
| 531 | tristate "Primax non-fully HID-compliant devices" | 538 | tristate "Primax non-fully HID-compliant devices" |
| 532 | depends on USB_HID | 539 | depends on USB_HID |
| @@ -534,6 +541,15 @@ config HID_PRIMAX | |||
| 534 | Support for Primax devices that are not fully compliant with the | 541 | Support for Primax devices that are not fully compliant with the |
| 535 | HID standard. | 542 | HID standard. |
| 536 | 543 | ||
| 544 | config HID_PS3REMOTE | ||
| 545 | tristate "Sony PS3 BD Remote Control" | ||
| 546 | depends on BT_HIDP | ||
| 547 | ---help--- | ||
| 548 | Support for the Sony PS3 Blue-ray Disk Remote Control and Logitech | ||
| 549 | Harmony Adapter for PS3, which connect over Bluetooth. | ||
| 550 | |||
| 551 | Support for the 6-axis controllers is provided by HID_SONY. | ||
| 552 | |||
| 537 | config HID_ROCCAT | 553 | config HID_ROCCAT |
| 538 | tristate "Roccat device support" | 554 | tristate "Roccat device support" |
| 539 | depends on USB_HID | 555 | depends on USB_HID |
| @@ -561,7 +577,9 @@ config HID_SONY | |||
| 561 | tristate "Sony PS3 controller" | 577 | tristate "Sony PS3 controller" |
| 562 | depends on USB_HID | 578 | depends on USB_HID |
| 563 | ---help--- | 579 | ---help--- |
| 564 | Support for Sony PS3 controller. | 580 | Support for Sony PS3 6-axis controllers. |
| 581 | |||
| 582 | Support for the Sony PS3 BD Remote is provided by HID_PS3REMOTE. | ||
| 565 | 583 | ||
| 566 | config HID_SPEEDLINK | 584 | config HID_SPEEDLINK |
| 567 | tristate "Speedlink VAD Cezanne mouse support" | 585 | tristate "Speedlink VAD Cezanne mouse support" |
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index f975485f88b2..5a3690ff9bf2 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile | |||
| @@ -69,7 +69,28 @@ obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o | |||
| 69 | obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o | 69 | obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o |
| 70 | obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o | 70 | obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o |
| 71 | obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o | 71 | obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o |
| 72 | hid-picolcd-y += hid-picolcd_core.o | ||
| 73 | ifdef CONFIG_HID_PICOLCD_FB | ||
| 74 | hid-picolcd-y += hid-picolcd_fb.o | ||
| 75 | endif | ||
| 76 | ifdef CONFIG_HID_PICOLCD_BACKLIGHT | ||
| 77 | hid-picolcd-y += hid-picolcd_backlight.o | ||
| 78 | endif | ||
| 79 | ifdef CONFIG_HID_PICOLCD_LCD | ||
| 80 | hid-picolcd-y += hid-picolcd_lcd.o | ||
| 81 | endif | ||
| 82 | ifdef CONFIG_HID_PICOLCD_LEDS | ||
| 83 | hid-picolcd-y += hid-picolcd_leds.o | ||
| 84 | endif | ||
| 85 | ifdef CONFIG_HID_PICOLCD_CIR | ||
| 86 | hid-picolcd-y += hid-picolcd_cir.o | ||
| 87 | endif | ||
| 88 | ifdef CONFIG_DEBUG_FS | ||
| 89 | hid-picolcd-y += hid-picolcd_debugfs.o | ||
| 90 | endif | ||
| 91 | |||
| 72 | obj-$(CONFIG_HID_PRIMAX) += hid-primax.o | 92 | obj-$(CONFIG_HID_PRIMAX) += hid-primax.o |
| 93 | obj-$(CONFIG_HID_PS3REMOTE) += hid-ps3remote.o | ||
| 73 | obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \ | 94 | obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \ |
| 74 | hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \ | 95 | hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \ |
| 75 | hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-pyra.o \ | 96 | hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-pyra.o \ |
diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c index 902d1dfeb1b5..0a239885e67c 100644 --- a/drivers/hid/hid-a4tech.c +++ b/drivers/hid/hid-a4tech.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | * Copyright (c) 2008 Jiri Slaby | 8 | * Copyright (c) 2008 Jiri Slaby |
| 10 | */ | 9 | */ |
| 11 | 10 | ||
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 585344b6d338..06ebdbb6ea02 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com> | 8 | * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com> |
| 10 | */ | 9 | */ |
| 11 | 10 | ||
diff --git a/drivers/hid/hid-aureal.c b/drivers/hid/hid-aureal.c index ba64b041b8bf..7968187ddf7b 100644 --- a/drivers/hid/hid-aureal.c +++ b/drivers/hid/hid-aureal.c | |||
| @@ -9,7 +9,6 @@ | |||
| 9 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 9 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 10 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 10 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 11 | * Copyright (c) 2006-2007 Jiri Kosina | 11 | * Copyright (c) 2006-2007 Jiri Kosina |
| 12 | * Copyright (c) 2007 Paul Walmsley | ||
| 13 | * Copyright (c) 2008 Jiri Slaby | 12 | * Copyright (c) 2008 Jiri Slaby |
| 14 | */ | 13 | */ |
| 15 | #include <linux/device.h> | 14 | #include <linux/device.h> |
diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c index a1a765a5b08a..a1a5a12c3a6b 100644 --- a/drivers/hid/hid-belkin.c +++ b/drivers/hid/hid-belkin.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | * Copyright (c) 2008 Jiri Slaby | 8 | * Copyright (c) 2008 Jiri Slaby |
| 10 | */ | 9 | */ |
| 11 | 10 | ||
diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c index 888ece68a47c..af034d3d9256 100644 --- a/drivers/hid/hid-cherry.c +++ b/drivers/hid/hid-cherry.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | * Copyright (c) 2008 Jiri Slaby | 8 | * Copyright (c) 2008 Jiri Slaby |
| 10 | */ | 9 | */ |
| 11 | 10 | ||
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8bcd168fffae..2cd6880b6b17 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
| @@ -126,7 +126,7 @@ static int open_collection(struct hid_parser *parser, unsigned type) | |||
| 126 | 126 | ||
| 127 | if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) { | 127 | if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) { |
| 128 | hid_err(parser->device, "collection stack overflow\n"); | 128 | hid_err(parser->device, "collection stack overflow\n"); |
| 129 | return -1; | 129 | return -EINVAL; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | if (parser->device->maxcollection == parser->device->collection_size) { | 132 | if (parser->device->maxcollection == parser->device->collection_size) { |
| @@ -134,7 +134,7 @@ static int open_collection(struct hid_parser *parser, unsigned type) | |||
| 134 | parser->device->collection_size * 2, GFP_KERNEL); | 134 | parser->device->collection_size * 2, GFP_KERNEL); |
| 135 | if (collection == NULL) { | 135 | if (collection == NULL) { |
| 136 | hid_err(parser->device, "failed to reallocate collection array\n"); | 136 | hid_err(parser->device, "failed to reallocate collection array\n"); |
| 137 | return -1; | 137 | return -ENOMEM; |
| 138 | } | 138 | } |
| 139 | memcpy(collection, parser->device->collection, | 139 | memcpy(collection, parser->device->collection, |
| 140 | sizeof(struct hid_collection) * | 140 | sizeof(struct hid_collection) * |
| @@ -170,7 +170,7 @@ static int close_collection(struct hid_parser *parser) | |||
| 170 | { | 170 | { |
| 171 | if (!parser->collection_stack_ptr) { | 171 | if (!parser->collection_stack_ptr) { |
| 172 | hid_err(parser->device, "collection stack underflow\n"); | 172 | hid_err(parser->device, "collection stack underflow\n"); |
| 173 | return -1; | 173 | return -EINVAL; |
| 174 | } | 174 | } |
| 175 | parser->collection_stack_ptr--; | 175 | parser->collection_stack_ptr--; |
| 176 | return 0; | 176 | return 0; |
| @@ -374,7 +374,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) | |||
| 374 | 374 | ||
| 375 | case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: | 375 | case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: |
| 376 | parser->global.report_size = item_udata(item); | 376 | parser->global.report_size = item_udata(item); |
| 377 | if (parser->global.report_size > 96) { | 377 | if (parser->global.report_size > 128) { |
| 378 | hid_err(parser->device, "invalid report_size %d\n", | 378 | hid_err(parser->device, "invalid report_size %d\n", |
| 379 | parser->global.report_size); | 379 | parser->global.report_size); |
| 380 | return -1; | 380 | return -1; |
| @@ -757,6 +757,7 @@ int hid_open_report(struct hid_device *device) | |||
| 757 | struct hid_item item; | 757 | struct hid_item item; |
| 758 | unsigned int size; | 758 | unsigned int size; |
| 759 | __u8 *start; | 759 | __u8 *start; |
| 760 | __u8 *buf; | ||
| 760 | __u8 *end; | 761 | __u8 *end; |
| 761 | int ret; | 762 | int ret; |
| 762 | static int (*dispatch_type[])(struct hid_parser *parser, | 763 | static int (*dispatch_type[])(struct hid_parser *parser, |
| @@ -775,12 +776,21 @@ int hid_open_report(struct hid_device *device) | |||
| 775 | return -ENODEV; | 776 | return -ENODEV; |
| 776 | size = device->dev_rsize; | 777 | size = device->dev_rsize; |
| 777 | 778 | ||
| 779 | buf = kmemdup(start, size, GFP_KERNEL); | ||
| 780 | if (buf == NULL) | ||
| 781 | return -ENOMEM; | ||
| 782 | |||
| 778 | if (device->driver->report_fixup) | 783 | if (device->driver->report_fixup) |
| 779 | start = device->driver->report_fixup(device, start, &size); | 784 | start = device->driver->report_fixup(device, buf, &size); |
| 785 | else | ||
| 786 | start = buf; | ||
| 780 | 787 | ||
| 781 | device->rdesc = kmemdup(start, size, GFP_KERNEL); | 788 | start = kmemdup(start, size, GFP_KERNEL); |
| 782 | if (device->rdesc == NULL) | 789 | kfree(buf); |
| 790 | if (start == NULL) | ||
| 783 | return -ENOMEM; | 791 | return -ENOMEM; |
| 792 | |||
| 793 | device->rdesc = start; | ||
| 784 | device->rsize = size; | 794 | device->rsize = size; |
| 785 | 795 | ||
| 786 | parser = vzalloc(sizeof(struct hid_parser)); | 796 | parser = vzalloc(sizeof(struct hid_parser)); |
| @@ -1448,7 +1458,14 @@ void hid_disconnect(struct hid_device *hdev) | |||
| 1448 | } | 1458 | } |
| 1449 | EXPORT_SYMBOL_GPL(hid_disconnect); | 1459 | EXPORT_SYMBOL_GPL(hid_disconnect); |
| 1450 | 1460 | ||
| 1451 | /* a list of devices for which there is a specialized driver on HID bus */ | 1461 | /* |
| 1462 | * A list of devices for which there is a specialized driver on HID bus. | ||
| 1463 | * | ||
| 1464 | * Please note that for multitouch devices (driven by hid-multitouch driver), | ||
| 1465 | * there is a proper autodetection and autoloading in place (based on presence | ||
| 1466 | * of HID_DG_CONTACTID), so those devices don't need to be added to this list, | ||
| 1467 | * as we are doing the right thing in hid_scan_usage(). | ||
| 1468 | */ | ||
| 1452 | static const struct hid_device_id hid_have_special_driver[] = { | 1469 | static const struct hid_device_id hid_have_special_driver[] = { |
| 1453 | { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, | 1470 | { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, |
| 1454 | { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, | 1471 | { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, |
| @@ -1566,6 +1583,7 @@ static const struct hid_device_id hid_have_special_driver[] = { | |||
| 1566 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, | 1583 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, |
| 1567 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, | 1584 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, |
| 1568 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) }, | 1585 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) }, |
| 1586 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) }, | ||
| 1569 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) }, | 1587 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) }, |
| 1570 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) }, | 1588 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) }, |
| 1571 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) }, | 1589 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) }, |
| @@ -1627,6 +1645,7 @@ static const struct hid_device_id hid_have_special_driver[] = { | |||
| 1627 | { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, | 1645 | { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, |
| 1628 | { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, | 1646 | { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, |
| 1629 | { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) }, | 1647 | { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) }, |
| 1648 | #if IS_ENABLED(CONFIG_HID_ROCCAT) | ||
| 1630 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, | 1649 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, |
| 1631 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) }, | 1650 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) }, |
| 1632 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) }, | 1651 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) }, |
| @@ -1635,10 +1654,12 @@ static const struct hid_device_id hid_have_special_driver[] = { | |||
| 1635 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, | 1654 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, |
| 1636 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) }, | 1655 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) }, |
| 1637 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) }, | 1656 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) }, |
| 1657 | #endif | ||
| 1638 | { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) }, | 1658 | { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) }, |
| 1639 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, | 1659 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, |
| 1640 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, | 1660 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, |
| 1641 | { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) }, | 1661 | { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) }, |
| 1662 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) }, | ||
| 1642 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, | 1663 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, |
| 1643 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, | 1664 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, |
| 1644 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, | 1665 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, |
| @@ -1663,6 +1684,7 @@ static const struct hid_device_id hid_have_special_driver[] = { | |||
| 1663 | { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, | 1684 | { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, |
| 1664 | { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, | 1685 | { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, |
| 1665 | { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) }, | 1686 | { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) }, |
| 1687 | { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) }, | ||
| 1666 | { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, | 1688 | { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, |
| 1667 | { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) }, | 1689 | { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) }, |
| 1668 | { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) }, | 1690 | { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) }, |
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c index 9e43aaca9774..3e159a50dac7 100644 --- a/drivers/hid/hid-cypress.c +++ b/drivers/hid/hid-cypress.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | * Copyright (c) 2008 Jiri Slaby | 8 | * Copyright (c) 2008 Jiri Slaby |
| 10 | */ | 9 | */ |
| 11 | 10 | ||
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 01dd9a7daf7a..933fff0fff1f 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c | |||
| @@ -911,15 +911,21 @@ static void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f) | |||
| 911 | 911 | ||
| 912 | } | 912 | } |
| 913 | 913 | ||
| 914 | |||
| 915 | static int hid_debug_rdesc_show(struct seq_file *f, void *p) | 914 | static int hid_debug_rdesc_show(struct seq_file *f, void *p) |
| 916 | { | 915 | { |
| 917 | struct hid_device *hdev = f->private; | 916 | struct hid_device *hdev = f->private; |
| 917 | const __u8 *rdesc = hdev->rdesc; | ||
| 918 | unsigned rsize = hdev->rsize; | ||
| 918 | int i; | 919 | int i; |
| 919 | 920 | ||
| 921 | if (!rdesc) { | ||
| 922 | rdesc = hdev->dev_rdesc; | ||
| 923 | rsize = hdev->dev_rsize; | ||
| 924 | } | ||
| 925 | |||
| 920 | /* dump HID report descriptor */ | 926 | /* dump HID report descriptor */ |
| 921 | for (i = 0; i < hdev->rsize; i++) | 927 | for (i = 0; i < rsize; i++) |
| 922 | seq_printf(f, "%02x ", hdev->rdesc[i]); | 928 | seq_printf(f, "%02x ", rdesc[i]); |
| 923 | seq_printf(f, "\n\n"); | 929 | seq_printf(f, "\n\n"); |
| 924 | 930 | ||
| 925 | /* dump parsed data and input mappings */ | 931 | /* dump parsed data and input mappings */ |
diff --git a/drivers/hid/hid-ezkey.c b/drivers/hid/hid-ezkey.c index ca1163e9d42d..6540af2871a7 100644 --- a/drivers/hid/hid-ezkey.c +++ b/drivers/hid/hid-ezkey.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | * Copyright (c) 2008 Jiri Slaby | 8 | * Copyright (c) 2008 Jiri Slaby |
| 10 | */ | 9 | */ |
| 11 | 10 | ||
diff --git a/drivers/hid/hid-gyration.c b/drivers/hid/hid-gyration.c index e88b951cd10d..4442c30ef531 100644 --- a/drivers/hid/hid-gyration.c +++ b/drivers/hid/hid-gyration.c | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | * Copyright (c) 1999 Andreas Gal | 4 | * Copyright (c) 1999 Andreas Gal |
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2007 Paul Walmsley | ||
| 8 | * Copyright (c) 2008 Jiri Slaby | 7 | * Copyright (c) 2008 Jiri Slaby |
| 9 | * Copyright (c) 2006-2008 Jiri Kosina | 8 | * Copyright (c) 2006-2008 Jiri Kosina |
| 10 | */ | 9 | */ |
diff --git a/drivers/hid/hid-holtekff.c b/drivers/hid/hid-holtekff.c index 4e7542151e22..ff295e60059b 100644 --- a/drivers/hid/hid-holtekff.c +++ b/drivers/hid/hid-holtekff.c | |||
| @@ -100,8 +100,7 @@ static void holtekff_send(struct holtekff_device *holtekff, | |||
| 100 | holtekff->field->value[i] = data[i]; | 100 | holtekff->field->value[i] = data[i]; |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | dbg_hid("sending %02x %02x %02x %02x %02x %02x %02x\n", data[0], | 103 | dbg_hid("sending %*ph\n", 7, data); |
| 104 | data[1], data[2], data[3], data[4], data[5], data[6]); | ||
| 105 | 104 | ||
| 106 | usbhid_submit_report(hid, holtekff->field->report, USB_DIR_OUT); | 105 | usbhid_submit_report(hid, holtekff->field->report, USB_DIR_OUT); |
| 107 | } | 106 | } |
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 1dcb76ff51e3..ca4d83e6e387 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | */ | 8 | */ |
| 10 | 9 | ||
| 11 | /* | 10 | /* |
| @@ -269,7 +268,11 @@ | |||
| 269 | #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA 0x72fa | 268 | #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA 0x72fa |
| 270 | #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302 0x7302 | 269 | #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302 0x7302 |
| 271 | #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349 0x7349 | 270 | #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349 0x7349 |
| 271 | #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7 0x73f7 | ||
| 272 | #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001 | 272 | #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001 |
| 273 | #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224 0x7224 | ||
| 274 | #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0 0x72d0 | ||
| 275 | #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4 0x72c4 | ||
| 273 | 276 | ||
| 274 | #define USB_VENDOR_ID_ELECOM 0x056e | 277 | #define USB_VENDOR_ID_ELECOM 0x056e |
| 275 | #define USB_DEVICE_ID_ELECOM_BM084 0x0061 | 278 | #define USB_DEVICE_ID_ELECOM_BM084 0x0061 |
| @@ -283,6 +286,9 @@ | |||
| 283 | #define USB_VENDOR_ID_EMS 0x2006 | 286 | #define USB_VENDOR_ID_EMS 0x2006 |
| 284 | #define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118 | 287 | #define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118 |
| 285 | 288 | ||
| 289 | #define USB_VENDOR_ID_FLATFROG 0x25b5 | ||
| 290 | #define USB_DEVICE_ID_MULTITOUCH_3200 0x0002 | ||
| 291 | |||
| 286 | #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f | 292 | #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f |
| 287 | #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 | 293 | #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 |
| 288 | 294 | ||
| @@ -296,6 +302,9 @@ | |||
| 296 | #define USB_VENDOR_ID_EZKEY 0x0518 | 302 | #define USB_VENDOR_ID_EZKEY 0x0518 |
| 297 | #define USB_DEVICE_ID_BTC_8193 0x0002 | 303 | #define USB_DEVICE_ID_BTC_8193 0x0002 |
| 298 | 304 | ||
| 305 | #define USB_VENDOR_ID_FREESCALE 0x15A2 | ||
| 306 | #define USB_DEVICE_ID_FREESCALE_MX28 0x004F | ||
| 307 | |||
| 299 | #define USB_VENDOR_ID_FRUCTEL 0x25B6 | 308 | #define USB_VENDOR_ID_FRUCTEL 0x25B6 |
| 300 | #define USB_DEVICE_ID_GAMETEL_MT_MODE 0x0002 | 309 | #define USB_DEVICE_ID_GAMETEL_MT_MODE 0x0002 |
| 301 | 310 | ||
| @@ -305,6 +314,7 @@ | |||
| 305 | 314 | ||
| 306 | #define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc | 315 | #define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc |
| 307 | #define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0003 | 316 | #define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0003 |
| 317 | #define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS 0x0100 | ||
| 308 | 318 | ||
| 309 | #define USB_VENDOR_ID_GLAB 0x06c2 | 319 | #define USB_VENDOR_ID_GLAB 0x06c2 |
| 310 | #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 | 320 | #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 |
| @@ -496,6 +506,7 @@ | |||
| 496 | #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 | 506 | #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 |
| 497 | #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110 | 507 | #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110 |
| 498 | #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f | 508 | #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f |
| 509 | #define USB_DEVICE_ID_LOGITECH_HARMONY_PS3 0x0306 | ||
| 499 | #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD 0xc20a | 510 | #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD 0xc20a |
| 500 | #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211 | 511 | #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211 |
| 501 | #define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215 | 512 | #define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215 |
| @@ -652,7 +663,6 @@ | |||
| 652 | #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000 | 663 | #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000 |
| 653 | #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001 | 664 | #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001 |
| 654 | #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008 | 665 | #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008 |
| 655 | #define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001 | ||
| 656 | 666 | ||
| 657 | #define USB_VENDOR_ID_ROCCAT 0x1e7d | 667 | #define USB_VENDOR_ID_ROCCAT 0x1e7d |
| 658 | #define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4 | 668 | #define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4 |
| @@ -683,6 +693,7 @@ | |||
| 683 | 693 | ||
| 684 | #define USB_VENDOR_ID_SONY 0x054c | 694 | #define USB_VENDOR_ID_SONY 0x054c |
| 685 | #define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b | 695 | #define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b |
| 696 | #define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306 | ||
| 686 | #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 | 697 | #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 |
| 687 | #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f | 698 | #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f |
| 688 | 699 | ||
| @@ -758,6 +769,7 @@ | |||
| 758 | #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005 | 769 | #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005 |
| 759 | #define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064 | 770 | #define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064 |
| 760 | #define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522 | 771 | #define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522 |
| 772 | #define USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60 0x0781 | ||
| 761 | 773 | ||
| 762 | #define USB_VENDOR_ID_UNITEC 0x227d | 774 | #define USB_VENDOR_ID_UNITEC 0x227d |
| 763 | #define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709 | 775 | #define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709 |
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 811bfad64609..d917c0d53685 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
| @@ -1154,6 +1154,7 @@ static void report_features(struct hid_device *hid) | |||
| 1154 | 1154 | ||
| 1155 | int hidinput_connect(struct hid_device *hid, unsigned int force) | 1155 | int hidinput_connect(struct hid_device *hid, unsigned int force) |
| 1156 | { | 1156 | { |
| 1157 | struct hid_driver *drv = hid->driver; | ||
| 1157 | struct hid_report *report; | 1158 | struct hid_report *report; |
| 1158 | struct hid_input *hidinput = NULL; | 1159 | struct hid_input *hidinput = NULL; |
| 1159 | struct input_dev *input_dev; | 1160 | struct input_dev *input_dev; |
| @@ -1228,6 +1229,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) | |||
| 1228 | * UGCI) cram a lot of unrelated inputs into the | 1229 | * UGCI) cram a lot of unrelated inputs into the |
| 1229 | * same interface. */ | 1230 | * same interface. */ |
| 1230 | hidinput->report = report; | 1231 | hidinput->report = report; |
| 1232 | if (drv->input_configured) | ||
| 1233 | drv->input_configured(hid, hidinput); | ||
| 1231 | if (input_register_device(hidinput->input)) | 1234 | if (input_register_device(hidinput->input)) |
| 1232 | goto out_cleanup; | 1235 | goto out_cleanup; |
| 1233 | hidinput = NULL; | 1236 | hidinput = NULL; |
| @@ -1235,8 +1238,12 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) | |||
| 1235 | } | 1238 | } |
| 1236 | } | 1239 | } |
| 1237 | 1240 | ||
| 1238 | if (hidinput && input_register_device(hidinput->input)) | 1241 | if (hidinput) { |
| 1239 | goto out_cleanup; | 1242 | if (drv->input_configured) |
| 1243 | drv->input_configured(hid, hidinput); | ||
| 1244 | if (input_register_device(hidinput->input)) | ||
| 1245 | goto out_cleanup; | ||
| 1246 | } | ||
| 1240 | 1247 | ||
| 1241 | return 0; | 1248 | return 0; |
| 1242 | 1249 | ||
diff --git a/drivers/hid/hid-lcpower.c b/drivers/hid/hid-lcpower.c index c4fe9bd095b7..22bc14abdfa3 100644 --- a/drivers/hid/hid-lcpower.c +++ b/drivers/hid/hid-lcpower.c | |||
| @@ -24,7 +24,7 @@ static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 24 | struct hid_field *field, struct hid_usage *usage, | 24 | struct hid_field *field, struct hid_usage *usage, |
| 25 | unsigned long **bit, int *max) | 25 | unsigned long **bit, int *max) |
| 26 | { | 26 | { |
| 27 | if ((usage->hid & HID_USAGE_PAGE) != 0x0ffbc0000) | 27 | if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) |
| 28 | return 0; | 28 | return 0; |
| 29 | 29 | ||
| 30 | switch (usage->hid & HID_USAGE) { | 30 | switch (usage->hid & HID_USAGE) { |
diff --git a/drivers/hid/hid-lenovo-tpkbd.c b/drivers/hid/hid-lenovo-tpkbd.c index 77d2df04c97b..cea016e94f43 100644 --- a/drivers/hid/hid-lenovo-tpkbd.c +++ b/drivers/hid/hid-lenovo-tpkbd.c | |||
| @@ -56,9 +56,8 @@ static int tpkbd_input_mapping(struct hid_device *hdev, | |||
| 56 | static int tpkbd_features_set(struct hid_device *hdev) | 56 | static int tpkbd_features_set(struct hid_device *hdev) |
| 57 | { | 57 | { |
| 58 | struct hid_report *report; | 58 | struct hid_report *report; |
| 59 | struct tpkbd_data_pointer *data_pointer; | 59 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 60 | 60 | ||
| 61 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 62 | report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4]; | 61 | report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4]; |
| 63 | 62 | ||
| 64 | report->field[0]->value[0] = data_pointer->press_to_select ? 0x01 : 0x02; | 63 | report->field[0]->value[0] = data_pointer->press_to_select ? 0x01 : 0x02; |
| @@ -77,14 +76,8 @@ static ssize_t pointer_press_to_select_show(struct device *dev, | |||
| 77 | struct device_attribute *attr, | 76 | struct device_attribute *attr, |
| 78 | char *buf) | 77 | char *buf) |
| 79 | { | 78 | { |
| 80 | struct hid_device *hdev; | 79 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 81 | struct tpkbd_data_pointer *data_pointer; | 80 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 82 | |||
| 83 | hdev = container_of(dev, struct hid_device, dev); | ||
| 84 | if (hdev == NULL) | ||
| 85 | return -ENODEV; | ||
| 86 | |||
| 87 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 88 | 81 | ||
| 89 | return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select); | 82 | return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select); |
| 90 | } | 83 | } |
| @@ -94,16 +87,10 @@ static ssize_t pointer_press_to_select_store(struct device *dev, | |||
| 94 | const char *buf, | 87 | const char *buf, |
| 95 | size_t count) | 88 | size_t count) |
| 96 | { | 89 | { |
| 97 | struct hid_device *hdev; | 90 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 98 | struct tpkbd_data_pointer *data_pointer; | 91 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 99 | int value; | 92 | int value; |
| 100 | 93 | ||
| 101 | hdev = container_of(dev, struct hid_device, dev); | ||
| 102 | if (hdev == NULL) | ||
| 103 | return -ENODEV; | ||
| 104 | |||
| 105 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 106 | |||
| 107 | if (kstrtoint(buf, 10, &value)) | 94 | if (kstrtoint(buf, 10, &value)) |
| 108 | return -EINVAL; | 95 | return -EINVAL; |
| 109 | if (value < 0 || value > 1) | 96 | if (value < 0 || value > 1) |
| @@ -119,14 +106,8 @@ static ssize_t pointer_dragging_show(struct device *dev, | |||
| 119 | struct device_attribute *attr, | 106 | struct device_attribute *attr, |
| 120 | char *buf) | 107 | char *buf) |
| 121 | { | 108 | { |
| 122 | struct hid_device *hdev; | 109 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 123 | struct tpkbd_data_pointer *data_pointer; | 110 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 124 | |||
| 125 | hdev = container_of(dev, struct hid_device, dev); | ||
| 126 | if (hdev == NULL) | ||
| 127 | return -ENODEV; | ||
| 128 | |||
| 129 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 130 | 111 | ||
| 131 | return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging); | 112 | return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging); |
| 132 | } | 113 | } |
| @@ -136,16 +117,10 @@ static ssize_t pointer_dragging_store(struct device *dev, | |||
| 136 | const char *buf, | 117 | const char *buf, |
| 137 | size_t count) | 118 | size_t count) |
| 138 | { | 119 | { |
| 139 | struct hid_device *hdev; | 120 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 140 | struct tpkbd_data_pointer *data_pointer; | 121 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 141 | int value; | 122 | int value; |
| 142 | 123 | ||
| 143 | hdev = container_of(dev, struct hid_device, dev); | ||
| 144 | if (hdev == NULL) | ||
| 145 | return -ENODEV; | ||
| 146 | |||
| 147 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 148 | |||
| 149 | if (kstrtoint(buf, 10, &value)) | 124 | if (kstrtoint(buf, 10, &value)) |
| 150 | return -EINVAL; | 125 | return -EINVAL; |
| 151 | if (value < 0 || value > 1) | 126 | if (value < 0 || value > 1) |
| @@ -161,14 +136,8 @@ static ssize_t pointer_release_to_select_show(struct device *dev, | |||
| 161 | struct device_attribute *attr, | 136 | struct device_attribute *attr, |
| 162 | char *buf) | 137 | char *buf) |
| 163 | { | 138 | { |
| 164 | struct hid_device *hdev; | 139 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 165 | struct tpkbd_data_pointer *data_pointer; | 140 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 166 | |||
| 167 | hdev = container_of(dev, struct hid_device, dev); | ||
| 168 | if (hdev == NULL) | ||
| 169 | return -ENODEV; | ||
| 170 | |||
| 171 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 172 | 141 | ||
| 173 | return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select); | 142 | return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select); |
| 174 | } | 143 | } |
| @@ -178,16 +147,10 @@ static ssize_t pointer_release_to_select_store(struct device *dev, | |||
| 178 | const char *buf, | 147 | const char *buf, |
| 179 | size_t count) | 148 | size_t count) |
| 180 | { | 149 | { |
| 181 | struct hid_device *hdev; | 150 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 182 | struct tpkbd_data_pointer *data_pointer; | 151 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 183 | int value; | 152 | int value; |
| 184 | 153 | ||
| 185 | hdev = container_of(dev, struct hid_device, dev); | ||
| 186 | if (hdev == NULL) | ||
| 187 | return -ENODEV; | ||
| 188 | |||
| 189 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 190 | |||
| 191 | if (kstrtoint(buf, 10, &value)) | 154 | if (kstrtoint(buf, 10, &value)) |
| 192 | return -EINVAL; | 155 | return -EINVAL; |
| 193 | if (value < 0 || value > 1) | 156 | if (value < 0 || value > 1) |
| @@ -203,14 +166,8 @@ static ssize_t pointer_select_right_show(struct device *dev, | |||
| 203 | struct device_attribute *attr, | 166 | struct device_attribute *attr, |
| 204 | char *buf) | 167 | char *buf) |
| 205 | { | 168 | { |
| 206 | struct hid_device *hdev; | 169 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 207 | struct tpkbd_data_pointer *data_pointer; | 170 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 208 | |||
| 209 | hdev = container_of(dev, struct hid_device, dev); | ||
| 210 | if (hdev == NULL) | ||
| 211 | return -ENODEV; | ||
| 212 | |||
| 213 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 214 | 171 | ||
| 215 | return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right); | 172 | return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right); |
| 216 | } | 173 | } |
| @@ -220,16 +177,10 @@ static ssize_t pointer_select_right_store(struct device *dev, | |||
| 220 | const char *buf, | 177 | const char *buf, |
| 221 | size_t count) | 178 | size_t count) |
| 222 | { | 179 | { |
| 223 | struct hid_device *hdev; | 180 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 224 | struct tpkbd_data_pointer *data_pointer; | 181 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 225 | int value; | 182 | int value; |
| 226 | 183 | ||
| 227 | hdev = container_of(dev, struct hid_device, dev); | ||
| 228 | if (hdev == NULL) | ||
| 229 | return -ENODEV; | ||
| 230 | |||
| 231 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 232 | |||
| 233 | if (kstrtoint(buf, 10, &value)) | 184 | if (kstrtoint(buf, 10, &value)) |
| 234 | return -EINVAL; | 185 | return -EINVAL; |
| 235 | if (value < 0 || value > 1) | 186 | if (value < 0 || value > 1) |
| @@ -245,14 +196,8 @@ static ssize_t pointer_sensitivity_show(struct device *dev, | |||
| 245 | struct device_attribute *attr, | 196 | struct device_attribute *attr, |
| 246 | char *buf) | 197 | char *buf) |
| 247 | { | 198 | { |
| 248 | struct hid_device *hdev; | 199 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 249 | struct tpkbd_data_pointer *data_pointer; | 200 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 250 | |||
| 251 | hdev = container_of(dev, struct hid_device, dev); | ||
| 252 | if (hdev == NULL) | ||
| 253 | return -ENODEV; | ||
| 254 | |||
| 255 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 256 | 201 | ||
| 257 | return snprintf(buf, PAGE_SIZE, "%u\n", | 202 | return snprintf(buf, PAGE_SIZE, "%u\n", |
| 258 | data_pointer->sensitivity); | 203 | data_pointer->sensitivity); |
| @@ -263,16 +208,10 @@ static ssize_t pointer_sensitivity_store(struct device *dev, | |||
| 263 | const char *buf, | 208 | const char *buf, |
| 264 | size_t count) | 209 | size_t count) |
| 265 | { | 210 | { |
| 266 | struct hid_device *hdev; | 211 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 267 | struct tpkbd_data_pointer *data_pointer; | 212 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 268 | int value; | 213 | int value; |
| 269 | 214 | ||
| 270 | hdev = container_of(dev, struct hid_device, dev); | ||
| 271 | if (hdev == NULL) | ||
| 272 | return -ENODEV; | ||
| 273 | |||
| 274 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 275 | |||
| 276 | if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) | 215 | if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) |
| 277 | return -EINVAL; | 216 | return -EINVAL; |
| 278 | 217 | ||
| @@ -286,14 +225,10 @@ static ssize_t pointer_press_speed_show(struct device *dev, | |||
| 286 | struct device_attribute *attr, | 225 | struct device_attribute *attr, |
| 287 | char *buf) | 226 | char *buf) |
| 288 | { | 227 | { |
| 289 | struct hid_device *hdev; | 228 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 290 | struct tpkbd_data_pointer *data_pointer; | 229 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 291 | 230 | ||
| 292 | hdev = container_of(dev, struct hid_device, dev); | 231 | data_pointer = hid_get_drvdata(hdev); |
| 293 | if (hdev == NULL) | ||
| 294 | return -ENODEV; | ||
| 295 | |||
| 296 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 297 | 232 | ||
| 298 | return snprintf(buf, PAGE_SIZE, "%u\n", | 233 | return snprintf(buf, PAGE_SIZE, "%u\n", |
| 299 | data_pointer->press_speed); | 234 | data_pointer->press_speed); |
| @@ -304,16 +239,10 @@ static ssize_t pointer_press_speed_store(struct device *dev, | |||
| 304 | const char *buf, | 239 | const char *buf, |
| 305 | size_t count) | 240 | size_t count) |
| 306 | { | 241 | { |
| 307 | struct hid_device *hdev; | 242 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 308 | struct tpkbd_data_pointer *data_pointer; | 243 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 309 | int value; | 244 | int value; |
| 310 | 245 | ||
| 311 | hdev = container_of(dev, struct hid_device, dev); | ||
| 312 | if (hdev == NULL) | ||
| 313 | return -ENODEV; | ||
| 314 | |||
| 315 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 316 | |||
| 317 | if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) | 246 | if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) |
| 318 | return -EINVAL; | 247 | return -EINVAL; |
| 319 | 248 | ||
| @@ -370,15 +299,11 @@ static const struct attribute_group tpkbd_attr_group_pointer = { | |||
| 370 | static enum led_brightness tpkbd_led_brightness_get( | 299 | static enum led_brightness tpkbd_led_brightness_get( |
| 371 | struct led_classdev *led_cdev) | 300 | struct led_classdev *led_cdev) |
| 372 | { | 301 | { |
| 373 | struct device *dev; | 302 | struct device *dev = led_cdev->dev->parent; |
| 374 | struct hid_device *hdev; | 303 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 375 | struct tpkbd_data_pointer *data_pointer; | 304 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 376 | int led_nr = 0; | 305 | int led_nr = 0; |
| 377 | 306 | ||
| 378 | dev = led_cdev->dev->parent; | ||
| 379 | hdev = container_of(dev, struct hid_device, dev); | ||
| 380 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 381 | |||
| 382 | if (led_cdev == &data_pointer->led_micmute) | 307 | if (led_cdev == &data_pointer->led_micmute) |
| 383 | led_nr = 1; | 308 | led_nr = 1; |
| 384 | 309 | ||
| @@ -390,16 +315,12 @@ static enum led_brightness tpkbd_led_brightness_get( | |||
| 390 | static void tpkbd_led_brightness_set(struct led_classdev *led_cdev, | 315 | static void tpkbd_led_brightness_set(struct led_classdev *led_cdev, |
| 391 | enum led_brightness value) | 316 | enum led_brightness value) |
| 392 | { | 317 | { |
| 393 | struct device *dev; | 318 | struct device *dev = led_cdev->dev->parent; |
| 394 | struct hid_device *hdev; | 319 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 320 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); | ||
| 395 | struct hid_report *report; | 321 | struct hid_report *report; |
| 396 | struct tpkbd_data_pointer *data_pointer; | ||
| 397 | int led_nr = 0; | 322 | int led_nr = 0; |
| 398 | 323 | ||
| 399 | dev = led_cdev->dev->parent; | ||
| 400 | hdev = container_of(dev, struct hid_device, dev); | ||
| 401 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 402 | |||
| 403 | if (led_cdev == &data_pointer->led_micmute) | 324 | if (led_cdev == &data_pointer->led_micmute) |
| 404 | led_nr = 1; | 325 | led_nr = 1; |
| 405 | 326 | ||
| @@ -508,17 +429,17 @@ err_free: | |||
| 508 | 429 | ||
| 509 | static void tpkbd_remove_tp(struct hid_device *hdev) | 430 | static void tpkbd_remove_tp(struct hid_device *hdev) |
| 510 | { | 431 | { |
| 511 | struct tpkbd_data_pointer *data_pointer; | 432 | struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); |
| 512 | 433 | ||
| 513 | sysfs_remove_group(&hdev->dev.kobj, | 434 | sysfs_remove_group(&hdev->dev.kobj, |
| 514 | &tpkbd_attr_group_pointer); | 435 | &tpkbd_attr_group_pointer); |
| 515 | 436 | ||
| 516 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
| 517 | |||
| 518 | led_classdev_unregister(&data_pointer->led_micmute); | 437 | led_classdev_unregister(&data_pointer->led_micmute); |
| 519 | led_classdev_unregister(&data_pointer->led_mute); | 438 | led_classdev_unregister(&data_pointer->led_mute); |
| 520 | 439 | ||
| 521 | hid_set_drvdata(hdev, NULL); | 440 | hid_set_drvdata(hdev, NULL); |
| 441 | kfree(data_pointer->led_micmute.name); | ||
| 442 | kfree(data_pointer->led_mute.name); | ||
| 522 | kfree(data_pointer); | 443 | kfree(data_pointer); |
| 523 | } | 444 | } |
| 524 | 445 | ||
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index fc37ed6b108c..a2f8e88b9fa2 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | * Copyright (c) 2008 Jiri Slaby | 8 | * Copyright (c) 2008 Jiri Slaby |
| 10 | * Copyright (c) 2010 Hendrik Iben | 9 | * Copyright (c) 2010 Hendrik Iben |
| 11 | */ | 10 | */ |
| @@ -109,7 +108,7 @@ static __u8 dfp_rdesc_fixed[] = { | |||
| 109 | static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, | 108 | static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, |
| 110 | unsigned int *rsize) | 109 | unsigned int *rsize) |
| 111 | { | 110 | { |
| 112 | struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); | 111 | struct lg_drv_data *drv_data = hid_get_drvdata(hdev); |
| 113 | 112 | ||
| 114 | if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && | 113 | if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && |
| 115 | rdesc[84] == 0x8c && rdesc[85] == 0x02) { | 114 | rdesc[84] == 0x8c && rdesc[85] == 0x02) { |
| @@ -278,7 +277,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 278 | 0, 0, 0, 0, 0,183,184,185,186,187, | 277 | 0, 0, 0, 0, 0,183,184,185,186,187, |
| 279 | 188,189,190,191,192,193,194, 0, 0, 0 | 278 | 188,189,190,191,192,193,194, 0, 0, 0 |
| 280 | }; | 279 | }; |
| 281 | struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); | 280 | struct lg_drv_data *drv_data = hid_get_drvdata(hdev); |
| 282 | unsigned int hid = usage->hid; | 281 | unsigned int hid = usage->hid; |
| 283 | 282 | ||
| 284 | if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER && | 283 | if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER && |
| @@ -319,7 +318,7 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi, | |||
| 319 | struct hid_field *field, struct hid_usage *usage, | 318 | struct hid_field *field, struct hid_usage *usage, |
| 320 | unsigned long **bit, int *max) | 319 | unsigned long **bit, int *max) |
| 321 | { | 320 | { |
| 322 | struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); | 321 | struct lg_drv_data *drv_data = hid_get_drvdata(hdev); |
| 323 | 322 | ||
| 324 | if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY && | 323 | if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY && |
| 325 | (field->flags & HID_MAIN_ITEM_RELATIVE)) | 324 | (field->flags & HID_MAIN_ITEM_RELATIVE)) |
| @@ -335,13 +334,16 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi, | |||
| 335 | static int lg_event(struct hid_device *hdev, struct hid_field *field, | 334 | static int lg_event(struct hid_device *hdev, struct hid_field *field, |
| 336 | struct hid_usage *usage, __s32 value) | 335 | struct hid_usage *usage, __s32 value) |
| 337 | { | 336 | { |
| 338 | struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); | 337 | struct lg_drv_data *drv_data = hid_get_drvdata(hdev); |
| 339 | 338 | ||
| 340 | if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) { | 339 | if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) { |
| 341 | input_event(field->hidinput->input, usage->type, usage->code, | 340 | input_event(field->hidinput->input, usage->type, usage->code, |
| 342 | -value); | 341 | -value); |
| 343 | return 1; | 342 | return 1; |
| 344 | } | 343 | } |
| 344 | if (drv_data->quirks & LG_FF4) { | ||
| 345 | return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data); | ||
| 346 | } | ||
| 345 | 347 | ||
| 346 | return 0; | 348 | return 0; |
| 347 | } | 349 | } |
| @@ -358,7 +360,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
| 358 | return -ENOMEM; | 360 | return -ENOMEM; |
| 359 | } | 361 | } |
| 360 | drv_data->quirks = id->driver_data; | 362 | drv_data->quirks = id->driver_data; |
| 361 | 363 | ||
| 362 | hid_set_drvdata(hdev, (void *)drv_data); | 364 | hid_set_drvdata(hdev, (void *)drv_data); |
| 363 | 365 | ||
| 364 | if (drv_data->quirks & LG_NOGET) | 366 | if (drv_data->quirks & LG_NOGET) |
| @@ -380,7 +382,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
| 380 | } | 382 | } |
| 381 | 383 | ||
| 382 | /* Setup wireless link with Logitech Wii wheel */ | 384 | /* Setup wireless link with Logitech Wii wheel */ |
| 383 | if(hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) { | 385 | if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) { |
| 384 | unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | 386 | unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
| 385 | 387 | ||
| 386 | ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); | 388 | ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); |
| @@ -416,7 +418,7 @@ err_free: | |||
| 416 | 418 | ||
| 417 | static void lg_remove(struct hid_device *hdev) | 419 | static void lg_remove(struct hid_device *hdev) |
| 418 | { | 420 | { |
| 419 | struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); | 421 | struct lg_drv_data *drv_data = hid_get_drvdata(hdev); |
| 420 | if (drv_data->quirks & LG_FF4) | 422 | if (drv_data->quirks & LG_FF4) |
| 421 | lg4ff_deinit(hdev); | 423 | lg4ff_deinit(hdev); |
| 422 | 424 | ||
| @@ -476,7 +478,7 @@ static const struct hid_device_id lg_devices[] = { | |||
| 476 | .driver_data = LG_NOGET | LG_FF4 }, | 478 | .driver_data = LG_NOGET | LG_FF4 }, |
| 477 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL), | 479 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL), |
| 478 | .driver_data = LG_FF4 }, | 480 | .driver_data = LG_FF4 }, |
| 479 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ), | 481 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG), |
| 480 | .driver_data = LG_FF }, | 482 | .driver_data = LG_FF }, |
| 481 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), | 483 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), |
| 482 | .driver_data = LG_FF2 }, | 484 | .driver_data = LG_FF2 }, |
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h index d64cf8d2751e..142ce3f5f055 100644 --- a/drivers/hid/hid-lg.h +++ b/drivers/hid/hid-lg.h | |||
| @@ -25,9 +25,13 @@ static inline int lg3ff_init(struct hid_device *hdev) { return -1; } | |||
| 25 | #endif | 25 | #endif |
| 26 | 26 | ||
| 27 | #ifdef CONFIG_LOGIWHEELS_FF | 27 | #ifdef CONFIG_LOGIWHEELS_FF |
| 28 | int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, | ||
| 29 | struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data); | ||
| 28 | int lg4ff_init(struct hid_device *hdev); | 30 | int lg4ff_init(struct hid_device *hdev); |
| 29 | int lg4ff_deinit(struct hid_device *hdev); | 31 | int lg4ff_deinit(struct hid_device *hdev); |
| 30 | #else | 32 | #else |
| 33 | static inline int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, | ||
| 34 | struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data) { return 0; } | ||
| 31 | static inline int lg4ff_init(struct hid_device *hdev) { return -1; } | 35 | static inline int lg4ff_init(struct hid_device *hdev) { return -1; } |
| 32 | static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; } | 36 | static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; } |
| 33 | #endif | 37 | #endif |
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index f3390ee6105c..d7947c701f30 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c | |||
| @@ -43,6 +43,11 @@ | |||
| 43 | #define G27_REV_MAJ 0x12 | 43 | #define G27_REV_MAJ 0x12 |
| 44 | #define G27_REV_MIN 0x38 | 44 | #define G27_REV_MIN 0x38 |
| 45 | 45 | ||
| 46 | #define DFP_X_MIN 0 | ||
| 47 | #define DFP_X_MAX 16383 | ||
| 48 | #define DFP_PEDAL_MIN 0 | ||
| 49 | #define DFP_PEDAL_MAX 255 | ||
| 50 | |||
| 46 | #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev) | 51 | #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev) |
| 47 | 52 | ||
| 48 | static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range); | 53 | static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range); |
| @@ -53,6 +58,7 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at | |||
| 53 | static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store); | 58 | static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store); |
| 54 | 59 | ||
| 55 | struct lg4ff_device_entry { | 60 | struct lg4ff_device_entry { |
| 61 | __u32 product_id; | ||
| 56 | __u16 range; | 62 | __u16 range; |
| 57 | __u16 min_range; | 63 | __u16 min_range; |
| 58 | __u16 max_range; | 64 | __u16 max_range; |
| @@ -129,26 +135,77 @@ static const struct lg4ff_usb_revision lg4ff_revs[] = { | |||
| 129 | {G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */ | 135 | {G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */ |
| 130 | }; | 136 | }; |
| 131 | 137 | ||
| 138 | /* Recalculates X axis value accordingly to currently selected range */ | ||
| 139 | static __s32 lg4ff_adjust_dfp_x_axis(__s32 value, __u16 range) | ||
| 140 | { | ||
| 141 | __u16 max_range; | ||
| 142 | __s32 new_value; | ||
| 143 | |||
| 144 | if (range == 900) | ||
| 145 | return value; | ||
| 146 | else if (range == 200) | ||
| 147 | return value; | ||
| 148 | else if (range < 200) | ||
| 149 | max_range = 200; | ||
| 150 | else | ||
| 151 | max_range = 900; | ||
| 152 | |||
| 153 | new_value = 8192 + mult_frac(value - 8192, max_range, range); | ||
| 154 | if (new_value < 0) | ||
| 155 | return 0; | ||
| 156 | else if (new_value > 16383) | ||
| 157 | return 16383; | ||
| 158 | else | ||
| 159 | return new_value; | ||
| 160 | } | ||
| 161 | |||
| 162 | int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, | ||
| 163 | struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data) | ||
| 164 | { | ||
| 165 | struct lg4ff_device_entry *entry = drv_data->device_props; | ||
| 166 | __s32 new_value = 0; | ||
| 167 | |||
| 168 | if (!entry) { | ||
| 169 | hid_err(hid, "Device properties not found"); | ||
| 170 | return 0; | ||
| 171 | } | ||
| 172 | |||
| 173 | switch (entry->product_id) { | ||
| 174 | case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: | ||
| 175 | switch (usage->code) { | ||
| 176 | case ABS_X: | ||
| 177 | new_value = lg4ff_adjust_dfp_x_axis(value, entry->range); | ||
| 178 | input_event(field->hidinput->input, usage->type, usage->code, new_value); | ||
| 179 | return 1; | ||
| 180 | default: | ||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | default: | ||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 132 | static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect) | 188 | static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect) |
| 133 | { | 189 | { |
| 134 | struct hid_device *hid = input_get_drvdata(dev); | 190 | struct hid_device *hid = input_get_drvdata(dev); |
| 135 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; | 191 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; |
| 136 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); | 192 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); |
| 193 | __s32 *value = report->field[0]->value; | ||
| 137 | int x; | 194 | int x; |
| 138 | 195 | ||
| 139 | #define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff | 196 | #define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while (0) |
| 140 | 197 | ||
| 141 | switch (effect->type) { | 198 | switch (effect->type) { |
| 142 | case FF_CONSTANT: | 199 | case FF_CONSTANT: |
| 143 | x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */ | 200 | x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */ |
| 144 | CLAMP(x); | 201 | CLAMP(x); |
| 145 | report->field[0]->value[0] = 0x11; /* Slot 1 */ | 202 | value[0] = 0x11; /* Slot 1 */ |
| 146 | report->field[0]->value[1] = 0x08; | 203 | value[1] = 0x08; |
| 147 | report->field[0]->value[2] = x; | 204 | value[2] = x; |
| 148 | report->field[0]->value[3] = 0x80; | 205 | value[3] = 0x80; |
| 149 | report->field[0]->value[4] = 0x00; | 206 | value[4] = 0x00; |
| 150 | report->field[0]->value[5] = 0x00; | 207 | value[5] = 0x00; |
| 151 | report->field[0]->value[6] = 0x00; | 208 | value[6] = 0x00; |
| 152 | 209 | ||
| 153 | usbhid_submit_report(hid, report, USB_DIR_OUT); | 210 | usbhid_submit_report(hid, report, USB_DIR_OUT); |
| 154 | break; | 211 | break; |
| @@ -163,14 +220,15 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud | |||
| 163 | struct hid_device *hid = input_get_drvdata(dev); | 220 | struct hid_device *hid = input_get_drvdata(dev); |
| 164 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; | 221 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; |
| 165 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); | 222 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); |
| 223 | __s32 *value = report->field[0]->value; | ||
| 166 | 224 | ||
| 167 | report->field[0]->value[0] = 0xfe; | 225 | value[0] = 0xfe; |
| 168 | report->field[0]->value[1] = 0x0d; | 226 | value[1] = 0x0d; |
| 169 | report->field[0]->value[2] = magnitude >> 13; | 227 | value[2] = magnitude >> 13; |
| 170 | report->field[0]->value[3] = magnitude >> 13; | 228 | value[3] = magnitude >> 13; |
| 171 | report->field[0]->value[4] = magnitude >> 8; | 229 | value[4] = magnitude >> 8; |
| 172 | report->field[0]->value[5] = 0x00; | 230 | value[5] = 0x00; |
| 173 | report->field[0]->value[6] = 0x00; | 231 | value[6] = 0x00; |
| 174 | 232 | ||
| 175 | usbhid_submit_report(hid, report, USB_DIR_OUT); | 233 | usbhid_submit_report(hid, report, USB_DIR_OUT); |
| 176 | } | 234 | } |
| @@ -181,16 +239,16 @@ static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) | |||
| 181 | struct hid_device *hid = input_get_drvdata(dev); | 239 | struct hid_device *hid = input_get_drvdata(dev); |
| 182 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; | 240 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; |
| 183 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); | 241 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); |
| 242 | __s32 *value = report->field[0]->value; | ||
| 184 | magnitude = magnitude * 90 / 65535; | 243 | magnitude = magnitude * 90 / 65535; |
| 185 | |||
| 186 | 244 | ||
| 187 | report->field[0]->value[0] = 0xfe; | 245 | value[0] = 0xfe; |
| 188 | report->field[0]->value[1] = 0x03; | 246 | value[1] = 0x03; |
| 189 | report->field[0]->value[2] = magnitude >> 14; | 247 | value[2] = magnitude >> 14; |
| 190 | report->field[0]->value[3] = magnitude >> 14; | 248 | value[3] = magnitude >> 14; |
| 191 | report->field[0]->value[4] = magnitude; | 249 | value[4] = magnitude; |
| 192 | report->field[0]->value[5] = 0x00; | 250 | value[5] = 0x00; |
| 193 | report->field[0]->value[6] = 0x00; | 251 | value[6] = 0x00; |
| 194 | 252 | ||
| 195 | usbhid_submit_report(hid, report, USB_DIR_OUT); | 253 | usbhid_submit_report(hid, report, USB_DIR_OUT); |
| 196 | } | 254 | } |
| @@ -200,15 +258,17 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range) | |||
| 200 | { | 258 | { |
| 201 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; | 259 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; |
| 202 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); | 260 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); |
| 261 | __s32 *value = report->field[0]->value; | ||
| 262 | |||
| 203 | dbg_hid("G25/G27/DFGT: setting range to %u\n", range); | 263 | dbg_hid("G25/G27/DFGT: setting range to %u\n", range); |
| 204 | 264 | ||
| 205 | report->field[0]->value[0] = 0xf8; | 265 | value[0] = 0xf8; |
| 206 | report->field[0]->value[1] = 0x81; | 266 | value[1] = 0x81; |
| 207 | report->field[0]->value[2] = range & 0x00ff; | 267 | value[2] = range & 0x00ff; |
| 208 | report->field[0]->value[3] = (range & 0xff00) >> 8; | 268 | value[3] = (range & 0xff00) >> 8; |
| 209 | report->field[0]->value[4] = 0x00; | 269 | value[4] = 0x00; |
| 210 | report->field[0]->value[5] = 0x00; | 270 | value[5] = 0x00; |
| 211 | report->field[0]->value[6] = 0x00; | 271 | value[6] = 0x00; |
| 212 | 272 | ||
| 213 | usbhid_submit_report(hid, report, USB_DIR_OUT); | 273 | usbhid_submit_report(hid, report, USB_DIR_OUT); |
| 214 | } | 274 | } |
| @@ -219,16 +279,18 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) | |||
| 219 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; | 279 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; |
| 220 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); | 280 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); |
| 221 | int start_left, start_right, full_range; | 281 | int start_left, start_right, full_range; |
| 282 | __s32 *value = report->field[0]->value; | ||
| 283 | |||
| 222 | dbg_hid("Driving Force Pro: setting range to %u\n", range); | 284 | dbg_hid("Driving Force Pro: setting range to %u\n", range); |
| 223 | 285 | ||
| 224 | /* Prepare "coarse" limit command */ | 286 | /* Prepare "coarse" limit command */ |
| 225 | report->field[0]->value[0] = 0xf8; | 287 | value[0] = 0xf8; |
| 226 | report->field[0]->value[1] = 0x00; /* Set later */ | 288 | value[1] = 0x00; /* Set later */ |
| 227 | report->field[0]->value[2] = 0x00; | 289 | value[2] = 0x00; |
| 228 | report->field[0]->value[3] = 0x00; | 290 | value[3] = 0x00; |
| 229 | report->field[0]->value[4] = 0x00; | 291 | value[4] = 0x00; |
| 230 | report->field[0]->value[5] = 0x00; | 292 | value[5] = 0x00; |
| 231 | report->field[0]->value[6] = 0x00; | 293 | value[6] = 0x00; |
| 232 | 294 | ||
| 233 | if (range > 200) { | 295 | if (range > 200) { |
| 234 | report->field[0]->value[1] = 0x03; | 296 | report->field[0]->value[1] = 0x03; |
| @@ -240,13 +302,13 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) | |||
| 240 | usbhid_submit_report(hid, report, USB_DIR_OUT); | 302 | usbhid_submit_report(hid, report, USB_DIR_OUT); |
| 241 | 303 | ||
| 242 | /* Prepare "fine" limit command */ | 304 | /* Prepare "fine" limit command */ |
| 243 | report->field[0]->value[0] = 0x81; | 305 | value[0] = 0x81; |
| 244 | report->field[0]->value[1] = 0x0b; | 306 | value[1] = 0x0b; |
| 245 | report->field[0]->value[2] = 0x00; | 307 | value[2] = 0x00; |
| 246 | report->field[0]->value[3] = 0x00; | 308 | value[3] = 0x00; |
| 247 | report->field[0]->value[4] = 0x00; | 309 | value[4] = 0x00; |
| 248 | report->field[0]->value[5] = 0x00; | 310 | value[5] = 0x00; |
| 249 | report->field[0]->value[6] = 0x00; | 311 | value[6] = 0x00; |
| 250 | 312 | ||
| 251 | if (range == 200 || range == 900) { /* Do not apply any fine limit */ | 313 | if (range == 200 || range == 900) { /* Do not apply any fine limit */ |
| 252 | usbhid_submit_report(hid, report, USB_DIR_OUT); | 314 | usbhid_submit_report(hid, report, USB_DIR_OUT); |
| @@ -257,11 +319,11 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) | |||
| 257 | start_left = (((full_range - range + 1) * 2047) / full_range); | 319 | start_left = (((full_range - range + 1) * 2047) / full_range); |
| 258 | start_right = 0xfff - start_left; | 320 | start_right = 0xfff - start_left; |
| 259 | 321 | ||
| 260 | report->field[0]->value[2] = start_left >> 4; | 322 | value[2] = start_left >> 4; |
| 261 | report->field[0]->value[3] = start_right >> 4; | 323 | value[3] = start_right >> 4; |
| 262 | report->field[0]->value[4] = 0xff; | 324 | value[4] = 0xff; |
| 263 | report->field[0]->value[5] = (start_right & 0xe) << 4 | (start_left & 0xe); | 325 | value[5] = (start_right & 0xe) << 4 | (start_left & 0xe); |
| 264 | report->field[0]->value[6] = 0xff; | 326 | value[6] = 0xff; |
| 265 | 327 | ||
| 266 | usbhid_submit_report(hid, report, USB_DIR_OUT); | 328 | usbhid_submit_report(hid, report, USB_DIR_OUT); |
| 267 | } | 329 | } |
| @@ -344,14 +406,15 @@ static void lg4ff_set_leds(struct hid_device *hid, __u8 leds) | |||
| 344 | { | 406 | { |
| 345 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; | 407 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; |
| 346 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); | 408 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); |
| 347 | 409 | __s32 *value = report->field[0]->value; | |
| 348 | report->field[0]->value[0] = 0xf8; | 410 | |
| 349 | report->field[0]->value[1] = 0x12; | 411 | value[0] = 0xf8; |
| 350 | report->field[0]->value[2] = leds; | 412 | value[1] = 0x12; |
| 351 | report->field[0]->value[3] = 0x00; | 413 | value[2] = leds; |
| 352 | report->field[0]->value[4] = 0x00; | 414 | value[3] = 0x00; |
| 353 | report->field[0]->value[5] = 0x00; | 415 | value[4] = 0x00; |
| 354 | report->field[0]->value[6] = 0x00; | 416 | value[5] = 0x00; |
| 417 | value[6] = 0x00; | ||
| 355 | usbhid_submit_report(hid, report, USB_DIR_OUT); | 418 | usbhid_submit_report(hid, report, USB_DIR_OUT); |
| 356 | } | 419 | } |
| 357 | 420 | ||
| @@ -360,7 +423,7 @@ static void lg4ff_led_set_brightness(struct led_classdev *led_cdev, | |||
| 360 | { | 423 | { |
| 361 | struct device *dev = led_cdev->dev->parent; | 424 | struct device *dev = led_cdev->dev->parent; |
| 362 | struct hid_device *hid = container_of(dev, struct hid_device, dev); | 425 | struct hid_device *hid = container_of(dev, struct hid_device, dev); |
| 363 | struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); | 426 | struct lg_drv_data *drv_data = hid_get_drvdata(hid); |
| 364 | struct lg4ff_device_entry *entry; | 427 | struct lg4ff_device_entry *entry; |
| 365 | int i, state = 0; | 428 | int i, state = 0; |
| 366 | 429 | ||
| @@ -395,7 +458,7 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde | |||
| 395 | { | 458 | { |
| 396 | struct device *dev = led_cdev->dev->parent; | 459 | struct device *dev = led_cdev->dev->parent; |
| 397 | struct hid_device *hid = container_of(dev, struct hid_device, dev); | 460 | struct hid_device *hid = container_of(dev, struct hid_device, dev); |
| 398 | struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); | 461 | struct lg_drv_data *drv_data = hid_get_drvdata(hid); |
| 399 | struct lg4ff_device_entry *entry; | 462 | struct lg4ff_device_entry *entry; |
| 400 | int i, value = 0; | 463 | int i, value = 0; |
| 401 | 464 | ||
| @@ -501,7 +564,7 @@ int lg4ff_init(struct hid_device *hid) | |||
| 501 | /* Check if autocentering is available and | 564 | /* Check if autocentering is available and |
| 502 | * set the centering force to zero by default */ | 565 | * set the centering force to zero by default */ |
| 503 | if (test_bit(FF_AUTOCENTER, dev->ffbit)) { | 566 | if (test_bit(FF_AUTOCENTER, dev->ffbit)) { |
| 504 | if(rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN) /* Formula Force EX expects different autocentering command */ | 567 | if (rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN) /* Formula Force EX expects different autocentering command */ |
| 505 | dev->ff->set_autocenter = hid_lg4ff_set_autocenter_ffex; | 568 | dev->ff->set_autocenter = hid_lg4ff_set_autocenter_ffex; |
| 506 | else | 569 | else |
| 507 | dev->ff->set_autocenter = hid_lg4ff_set_autocenter_default; | 570 | dev->ff->set_autocenter = hid_lg4ff_set_autocenter_default; |
| @@ -524,6 +587,7 @@ int lg4ff_init(struct hid_device *hid) | |||
| 524 | } | 587 | } |
| 525 | drv_data->device_props = entry; | 588 | drv_data->device_props = entry; |
| 526 | 589 | ||
| 590 | entry->product_id = lg4ff_devices[i].product_id; | ||
| 527 | entry->min_range = lg4ff_devices[i].min_range; | 591 | entry->min_range = lg4ff_devices[i].min_range; |
| 528 | entry->max_range = lg4ff_devices[i].max_range; | 592 | entry->max_range = lg4ff_devices[i].max_range; |
| 529 | entry->set_range = lg4ff_devices[i].set_range; | 593 | entry->set_range = lg4ff_devices[i].set_range; |
| @@ -534,6 +598,18 @@ int lg4ff_init(struct hid_device *hid) | |||
| 534 | return error; | 598 | return error; |
| 535 | dbg_hid("sysfs interface created\n"); | 599 | dbg_hid("sysfs interface created\n"); |
| 536 | 600 | ||
| 601 | /* Set default axes parameters */ | ||
| 602 | switch (lg4ff_devices[i].product_id) { | ||
| 603 | case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: | ||
| 604 | dbg_hid("Setting axes parameters for Driving Force Pro\n"); | ||
| 605 | input_set_abs_params(dev, ABS_X, DFP_X_MIN, DFP_X_MAX, 0, 0); | ||
| 606 | input_set_abs_params(dev, ABS_Y, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0); | ||
| 607 | input_set_abs_params(dev, ABS_RZ, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0); | ||
| 608 | break; | ||
| 609 | default: | ||
| 610 | break; | ||
| 611 | } | ||
| 612 | |||
| 537 | /* Set the maximum range to start with */ | 613 | /* Set the maximum range to start with */ |
| 538 | entry->range = entry->max_range; | 614 | entry->range = entry->max_range; |
| 539 | if (entry->set_range != NULL) | 615 | if (entry->set_range != NULL) |
| @@ -594,6 +670,8 @@ out: | |||
| 594 | return 0; | 670 | return 0; |
| 595 | } | 671 | } |
| 596 | 672 | ||
| 673 | |||
| 674 | |||
| 597 | int lg4ff_deinit(struct hid_device *hid) | 675 | int lg4ff_deinit(struct hid_device *hid) |
| 598 | { | 676 | { |
| 599 | struct lg4ff_device_entry *entry; | 677 | struct lg4ff_device_entry *entry; |
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 4d524b5f52f5..9500f2f3f8fe 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c | |||
| @@ -193,6 +193,7 @@ static struct hid_ll_driver logi_dj_ll_driver; | |||
| 193 | static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf, | 193 | static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf, |
| 194 | size_t count, | 194 | size_t count, |
| 195 | unsigned char report_type); | 195 | unsigned char report_type); |
| 196 | static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev); | ||
| 196 | 197 | ||
| 197 | static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev, | 198 | static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev, |
| 198 | struct dj_report *dj_report) | 199 | struct dj_report *dj_report) |
| @@ -233,6 +234,7 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, | |||
| 233 | if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] & | 234 | if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] & |
| 234 | SPFUNCTION_DEVICE_LIST_EMPTY) { | 235 | SPFUNCTION_DEVICE_LIST_EMPTY) { |
| 235 | dbg_hid("%s: device list is empty\n", __func__); | 236 | dbg_hid("%s: device list is empty\n", __func__); |
| 237 | djrcv_dev->querying_devices = false; | ||
| 236 | return; | 238 | return; |
| 237 | } | 239 | } |
| 238 | 240 | ||
| @@ -243,6 +245,12 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, | |||
| 243 | return; | 245 | return; |
| 244 | } | 246 | } |
| 245 | 247 | ||
| 248 | if (djrcv_dev->paired_dj_devices[dj_report->device_index]) { | ||
| 249 | /* The device is already known. No need to reallocate it. */ | ||
| 250 | dbg_hid("%s: device is already known\n", __func__); | ||
| 251 | return; | ||
| 252 | } | ||
| 253 | |||
| 246 | dj_hiddev = hid_allocate_device(); | 254 | dj_hiddev = hid_allocate_device(); |
| 247 | if (IS_ERR(dj_hiddev)) { | 255 | if (IS_ERR(dj_hiddev)) { |
| 248 | dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n", | 256 | dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n", |
| @@ -306,6 +314,7 @@ static void delayedwork_callback(struct work_struct *work) | |||
| 306 | struct dj_report dj_report; | 314 | struct dj_report dj_report; |
| 307 | unsigned long flags; | 315 | unsigned long flags; |
| 308 | int count; | 316 | int count; |
| 317 | int retval; | ||
| 309 | 318 | ||
| 310 | dbg_hid("%s\n", __func__); | 319 | dbg_hid("%s\n", __func__); |
| 311 | 320 | ||
| @@ -338,6 +347,25 @@ static void delayedwork_callback(struct work_struct *work) | |||
| 338 | logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report); | 347 | logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report); |
| 339 | break; | 348 | break; |
| 340 | default: | 349 | default: |
| 350 | /* A normal report (i. e. not belonging to a pair/unpair notification) | ||
| 351 | * arriving here, means that the report arrived but we did not have a | ||
| 352 | * paired dj_device associated to the report's device_index, this | ||
| 353 | * means that the original "device paired" notification corresponding | ||
| 354 | * to this dj_device never arrived to this driver. The reason is that | ||
| 355 | * hid-core discards all packets coming from a device while probe() is | ||
| 356 | * executing. */ | ||
| 357 | if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) { | ||
| 358 | /* ok, we don't know the device, just re-ask the | ||
| 359 | * receiver for the list of connected devices. */ | ||
| 360 | retval = logi_dj_recv_query_paired_devices(djrcv_dev); | ||
| 361 | if (!retval) { | ||
| 362 | /* everything went fine, so just leave */ | ||
| 363 | break; | ||
| 364 | } | ||
| 365 | dev_err(&djrcv_dev->hdev->dev, | ||
| 366 | "%s:logi_dj_recv_query_paired_devices " | ||
| 367 | "error:%d\n", __func__, retval); | ||
| 368 | } | ||
| 341 | dbg_hid("%s: unexpected report type\n", __func__); | 369 | dbg_hid("%s: unexpected report type\n", __func__); |
| 342 | } | 370 | } |
| 343 | } | 371 | } |
| @@ -368,6 +396,12 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev, | |||
| 368 | if (!djdev) { | 396 | if (!djdev) { |
| 369 | dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" | 397 | dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" |
| 370 | " is NULL, index %d\n", dj_report->device_index); | 398 | " is NULL, index %d\n", dj_report->device_index); |
| 399 | kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report)); | ||
| 400 | |||
| 401 | if (schedule_work(&djrcv_dev->work) == 0) { | ||
| 402 | dbg_hid("%s: did not schedule the work item, was already " | ||
| 403 | "queued\n", __func__); | ||
| 404 | } | ||
| 371 | return; | 405 | return; |
| 372 | } | 406 | } |
| 373 | 407 | ||
| @@ -398,6 +432,12 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev, | |||
| 398 | if (dj_device == NULL) { | 432 | if (dj_device == NULL) { |
| 399 | dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" | 433 | dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" |
| 400 | " is NULL, index %d\n", dj_report->device_index); | 434 | " is NULL, index %d\n", dj_report->device_index); |
| 435 | kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report)); | ||
| 436 | |||
| 437 | if (schedule_work(&djrcv_dev->work) == 0) { | ||
| 438 | dbg_hid("%s: did not schedule the work item, was already " | ||
| 439 | "queued\n", __func__); | ||
| 440 | } | ||
| 401 | return; | 441 | return; |
| 402 | } | 442 | } |
| 403 | 443 | ||
| @@ -439,6 +479,10 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) | |||
| 439 | struct dj_report *dj_report; | 479 | struct dj_report *dj_report; |
| 440 | int retval; | 480 | int retval; |
| 441 | 481 | ||
| 482 | /* no need to protect djrcv_dev->querying_devices */ | ||
| 483 | if (djrcv_dev->querying_devices) | ||
| 484 | return 0; | ||
| 485 | |||
| 442 | dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL); | 486 | dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL); |
| 443 | if (!dj_report) | 487 | if (!dj_report) |
| 444 | return -ENOMEM; | 488 | return -ENOMEM; |
| @@ -450,6 +494,7 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) | |||
| 450 | return retval; | 494 | return retval; |
| 451 | } | 495 | } |
| 452 | 496 | ||
| 497 | |||
| 453 | static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, | 498 | static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, |
| 454 | unsigned timeout) | 499 | unsigned timeout) |
| 455 | { | 500 | { |
diff --git a/drivers/hid/hid-logitech-dj.h b/drivers/hid/hid-logitech-dj.h index fd28a5e0ca3b..4a4000340ce1 100644 --- a/drivers/hid/hid-logitech-dj.h +++ b/drivers/hid/hid-logitech-dj.h | |||
| @@ -101,6 +101,7 @@ struct dj_receiver_dev { | |||
| 101 | struct work_struct work; | 101 | struct work_struct work; |
| 102 | struct kfifo notif_fifo; | 102 | struct kfifo notif_fifo; |
| 103 | spinlock_t lock; | 103 | spinlock_t lock; |
| 104 | bool querying_devices; | ||
| 104 | }; | 105 | }; |
| 105 | 106 | ||
| 106 | struct dj_device { | 107 | struct dj_device { |
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 73647266daad..25ddf3e3aec6 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c | |||
| @@ -392,7 +392,7 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd | |||
| 392 | 392 | ||
| 393 | __set_bit(EV_ABS, input->evbit); | 393 | __set_bit(EV_ABS, input->evbit); |
| 394 | 394 | ||
| 395 | error = input_mt_init_slots(input, 16); | 395 | error = input_mt_init_slots(input, 16, 0); |
| 396 | if (error) | 396 | if (error) |
| 397 | return error; | 397 | return error; |
| 398 | input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2, | 398 | input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2, |
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index e5c699b6c6f3..3acdcfcc17df 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | * Copyright (c) 2008 Jiri Slaby | 8 | * Copyright (c) 2008 Jiri Slaby |
| 10 | */ | 9 | */ |
| 11 | 10 | ||
diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c index dedf757781ae..cd3643e06fa6 100644 --- a/drivers/hid/hid-monterey.c +++ b/drivers/hid/hid-monterey.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | * Copyright (c) 2008 Jiri Slaby | 8 | * Copyright (c) 2008 Jiri Slaby |
| 10 | */ | 9 | */ |
| 11 | 10 | ||
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 59c8b5c1d2de..3eb02b94fc87 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c | |||
| @@ -51,12 +51,12 @@ MODULE_LICENSE("GPL"); | |||
| 51 | #define MT_QUIRK_VALID_IS_INRANGE (1 << 5) | 51 | #define MT_QUIRK_VALID_IS_INRANGE (1 << 5) |
| 52 | #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6) | 52 | #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6) |
| 53 | #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8) | 53 | #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8) |
| 54 | #define MT_QUIRK_NO_AREA (1 << 9) | ||
| 54 | 55 | ||
| 55 | struct mt_slot { | 56 | struct mt_slot { |
| 56 | __s32 x, y, p, w, h; | 57 | __s32 x, y, p, w, h; |
| 57 | __s32 contactid; /* the device ContactID assigned to this slot */ | 58 | __s32 contactid; /* the device ContactID assigned to this slot */ |
| 58 | bool touch_state; /* is the touch valid? */ | 59 | bool touch_state; /* is the touch valid? */ |
| 59 | bool seen_in_this_frame;/* has this slot been updated */ | ||
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | struct mt_class { | 62 | struct mt_class { |
| @@ -92,8 +92,9 @@ struct mt_device { | |||
| 92 | __u8 touches_by_report; /* how many touches are present in one report: | 92 | __u8 touches_by_report; /* how many touches are present in one report: |
| 93 | * 1 means we should use a serial protocol | 93 | * 1 means we should use a serial protocol |
| 94 | * > 1 means hybrid (multitouch) protocol */ | 94 | * > 1 means hybrid (multitouch) protocol */ |
| 95 | bool serial_maybe; /* need to check for serial protocol */ | ||
| 95 | bool curvalid; /* is the current contact valid? */ | 96 | bool curvalid; /* is the current contact valid? */ |
| 96 | struct mt_slot *slots; | 97 | unsigned mt_flags; /* flags to pass to input-mt */ |
| 97 | }; | 98 | }; |
| 98 | 99 | ||
| 99 | /* classes of device behavior */ | 100 | /* classes of device behavior */ |
| @@ -115,6 +116,9 @@ struct mt_device { | |||
| 115 | #define MT_CLS_EGALAX_SERIAL 0x0104 | 116 | #define MT_CLS_EGALAX_SERIAL 0x0104 |
| 116 | #define MT_CLS_TOPSEED 0x0105 | 117 | #define MT_CLS_TOPSEED 0x0105 |
| 117 | #define MT_CLS_PANASONIC 0x0106 | 118 | #define MT_CLS_PANASONIC 0x0106 |
| 119 | #define MT_CLS_FLATFROG 0x0107 | ||
| 120 | #define MT_CLS_GENERALTOUCH_TWOFINGERS 0x0108 | ||
| 121 | #define MT_CLS_GENERALTOUCH_PWT_TENFINGERS 0x0109 | ||
| 118 | 122 | ||
| 119 | #define MT_DEFAULT_MAXCONTACT 10 | 123 | #define MT_DEFAULT_MAXCONTACT 10 |
| 120 | 124 | ||
| @@ -134,25 +138,6 @@ static int cypress_compute_slot(struct mt_device *td) | |||
| 134 | return -1; | 138 | return -1; |
| 135 | } | 139 | } |
| 136 | 140 | ||
| 137 | static int find_slot_from_contactid(struct mt_device *td) | ||
| 138 | { | ||
| 139 | int i; | ||
| 140 | for (i = 0; i < td->maxcontacts; ++i) { | ||
| 141 | if (td->slots[i].contactid == td->curdata.contactid && | ||
| 142 | td->slots[i].touch_state) | ||
| 143 | return i; | ||
| 144 | } | ||
| 145 | for (i = 0; i < td->maxcontacts; ++i) { | ||
| 146 | if (!td->slots[i].seen_in_this_frame && | ||
| 147 | !td->slots[i].touch_state) | ||
| 148 | return i; | ||
| 149 | } | ||
| 150 | /* should not occurs. If this happens that means | ||
| 151 | * that the device sent more touches that it says | ||
| 152 | * in the report descriptor. It is ignored then. */ | ||
| 153 | return -1; | ||
| 154 | } | ||
| 155 | |||
| 156 | static struct mt_class mt_classes[] = { | 141 | static struct mt_class mt_classes[] = { |
| 157 | { .name = MT_CLS_DEFAULT, | 142 | { .name = MT_CLS_DEFAULT, |
| 158 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, | 143 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, |
| @@ -190,7 +175,9 @@ static struct mt_class mt_classes[] = { | |||
| 190 | MT_QUIRK_SLOT_IS_CONTACTID, | 175 | MT_QUIRK_SLOT_IS_CONTACTID, |
| 191 | .sn_move = 2048, | 176 | .sn_move = 2048, |
| 192 | .sn_width = 128, | 177 | .sn_width = 128, |
| 193 | .sn_height = 128 }, | 178 | .sn_height = 128, |
| 179 | .maxcontacts = 60, | ||
| 180 | }, | ||
| 194 | { .name = MT_CLS_CYPRESS, | 181 | { .name = MT_CLS_CYPRESS, |
| 195 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | | 182 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | |
| 196 | MT_QUIRK_CYPRESS, | 183 | MT_QUIRK_CYPRESS, |
| @@ -215,7 +202,24 @@ static struct mt_class mt_classes[] = { | |||
| 215 | { .name = MT_CLS_PANASONIC, | 202 | { .name = MT_CLS_PANASONIC, |
| 216 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, | 203 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, |
| 217 | .maxcontacts = 4 }, | 204 | .maxcontacts = 4 }, |
| 205 | { .name = MT_CLS_GENERALTOUCH_TWOFINGERS, | ||
| 206 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | | ||
| 207 | MT_QUIRK_VALID_IS_INRANGE | | ||
| 208 | MT_QUIRK_SLOT_IS_CONTACTNUMBER, | ||
| 209 | .maxcontacts = 2 | ||
| 210 | }, | ||
| 211 | { .name = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, | ||
| 212 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | | ||
| 213 | MT_QUIRK_SLOT_IS_CONTACTNUMBER, | ||
| 214 | .maxcontacts = 10 | ||
| 215 | }, | ||
| 218 | 216 | ||
| 217 | { .name = MT_CLS_FLATFROG, | ||
| 218 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | | ||
| 219 | MT_QUIRK_NO_AREA, | ||
| 220 | .sn_move = 2048, | ||
| 221 | .maxcontacts = 40, | ||
| 222 | }, | ||
| 219 | { } | 223 | { } |
| 220 | }; | 224 | }; |
| 221 | 225 | ||
| @@ -319,24 +323,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 319 | * We need to ignore fields that belong to other collections | 323 | * We need to ignore fields that belong to other collections |
| 320 | * such as Mouse that might have the same GenericDesktop usages. */ | 324 | * such as Mouse that might have the same GenericDesktop usages. */ |
| 321 | if (field->application == HID_DG_TOUCHSCREEN) | 325 | if (field->application == HID_DG_TOUCHSCREEN) |
| 322 | set_bit(INPUT_PROP_DIRECT, hi->input->propbit); | 326 | td->mt_flags |= INPUT_MT_DIRECT; |
| 323 | else if (field->application != HID_DG_TOUCHPAD) | 327 | else if (field->application != HID_DG_TOUCHPAD) |
| 324 | return 0; | 328 | return 0; |
| 325 | 329 | ||
| 326 | /* In case of an indirect device (touchpad), we need to add | 330 | /* |
| 327 | * specific BTN_TOOL_* to be handled by the synaptics xorg | 331 | * Model touchscreens providing buttons as touchpads. |
| 328 | * driver. | ||
| 329 | * We also consider that touchscreens providing buttons are touchpads. | ||
| 330 | */ | 332 | */ |
| 331 | if (field->application == HID_DG_TOUCHPAD || | 333 | if (field->application == HID_DG_TOUCHPAD || |
| 332 | (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON || | 334 | (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) |
| 333 | cls->is_indirect) { | 335 | td->mt_flags |= INPUT_MT_POINTER; |
| 334 | set_bit(INPUT_PROP_POINTER, hi->input->propbit); | ||
| 335 | set_bit(BTN_TOOL_FINGER, hi->input->keybit); | ||
| 336 | set_bit(BTN_TOOL_DOUBLETAP, hi->input->keybit); | ||
| 337 | set_bit(BTN_TOOL_TRIPLETAP, hi->input->keybit); | ||
| 338 | set_bit(BTN_TOOL_QUADTAP, hi->input->keybit); | ||
| 339 | } | ||
| 340 | 336 | ||
| 341 | /* eGalax devices provide a Digitizer.Stylus input which overrides | 337 | /* eGalax devices provide a Digitizer.Stylus input which overrides |
| 342 | * the correct Digitizers.Finger X/Y ranges. | 338 | * the correct Digitizers.Finger X/Y ranges. |
| @@ -353,8 +349,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 353 | EV_ABS, ABS_MT_POSITION_X); | 349 | EV_ABS, ABS_MT_POSITION_X); |
| 354 | set_abs(hi->input, ABS_MT_POSITION_X, field, | 350 | set_abs(hi->input, ABS_MT_POSITION_X, field, |
| 355 | cls->sn_move); | 351 | cls->sn_move); |
| 356 | /* touchscreen emulation */ | ||
| 357 | set_abs(hi->input, ABS_X, field, cls->sn_move); | ||
| 358 | mt_store_field(usage, td, hi); | 352 | mt_store_field(usage, td, hi); |
| 359 | td->last_field_index = field->index; | 353 | td->last_field_index = field->index; |
| 360 | return 1; | 354 | return 1; |
| @@ -363,8 +357,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 363 | EV_ABS, ABS_MT_POSITION_Y); | 357 | EV_ABS, ABS_MT_POSITION_Y); |
| 364 | set_abs(hi->input, ABS_MT_POSITION_Y, field, | 358 | set_abs(hi->input, ABS_MT_POSITION_Y, field, |
| 365 | cls->sn_move); | 359 | cls->sn_move); |
| 366 | /* touchscreen emulation */ | ||
| 367 | set_abs(hi->input, ABS_Y, field, cls->sn_move); | ||
| 368 | mt_store_field(usage, td, hi); | 360 | mt_store_field(usage, td, hi); |
| 369 | td->last_field_index = field->index; | 361 | td->last_field_index = field->index; |
| 370 | return 1; | 362 | return 1; |
| @@ -388,9 +380,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 388 | td->last_field_index = field->index; | 380 | td->last_field_index = field->index; |
| 389 | return 1; | 381 | return 1; |
| 390 | case HID_DG_CONTACTID: | 382 | case HID_DG_CONTACTID: |
| 391 | if (!td->maxcontacts) | ||
| 392 | td->maxcontacts = MT_DEFAULT_MAXCONTACT; | ||
| 393 | input_mt_init_slots(hi->input, td->maxcontacts); | ||
| 394 | mt_store_field(usage, td, hi); | 383 | mt_store_field(usage, td, hi); |
| 395 | td->last_field_index = field->index; | 384 | td->last_field_index = field->index; |
| 396 | td->touches_by_report++; | 385 | td->touches_by_report++; |
| @@ -398,18 +387,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 398 | case HID_DG_WIDTH: | 387 | case HID_DG_WIDTH: |
| 399 | hid_map_usage(hi, usage, bit, max, | 388 | hid_map_usage(hi, usage, bit, max, |
| 400 | EV_ABS, ABS_MT_TOUCH_MAJOR); | 389 | EV_ABS, ABS_MT_TOUCH_MAJOR); |
| 401 | set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, | 390 | if (!(cls->quirks & MT_QUIRK_NO_AREA)) |
| 402 | cls->sn_width); | 391 | set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, |
| 392 | cls->sn_width); | ||
| 403 | mt_store_field(usage, td, hi); | 393 | mt_store_field(usage, td, hi); |
| 404 | td->last_field_index = field->index; | 394 | td->last_field_index = field->index; |
| 405 | return 1; | 395 | return 1; |
| 406 | case HID_DG_HEIGHT: | 396 | case HID_DG_HEIGHT: |
| 407 | hid_map_usage(hi, usage, bit, max, | 397 | hid_map_usage(hi, usage, bit, max, |
| 408 | EV_ABS, ABS_MT_TOUCH_MINOR); | 398 | EV_ABS, ABS_MT_TOUCH_MINOR); |
| 409 | set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, | 399 | if (!(cls->quirks & MT_QUIRK_NO_AREA)) { |
| 410 | cls->sn_height); | 400 | set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, |
| 411 | input_set_abs_params(hi->input, | 401 | cls->sn_height); |
| 402 | input_set_abs_params(hi->input, | ||
| 412 | ABS_MT_ORIENTATION, 0, 1, 0, 0); | 403 | ABS_MT_ORIENTATION, 0, 1, 0, 0); |
| 404 | } | ||
| 413 | mt_store_field(usage, td, hi); | 405 | mt_store_field(usage, td, hi); |
| 414 | td->last_field_index = field->index; | 406 | td->last_field_index = field->index; |
| 415 | return 1; | 407 | return 1; |
| @@ -418,9 +410,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 418 | EV_ABS, ABS_MT_PRESSURE); | 410 | EV_ABS, ABS_MT_PRESSURE); |
| 419 | set_abs(hi->input, ABS_MT_PRESSURE, field, | 411 | set_abs(hi->input, ABS_MT_PRESSURE, field, |
| 420 | cls->sn_pressure); | 412 | cls->sn_pressure); |
| 421 | /* touchscreen emulation */ | ||
| 422 | set_abs(hi->input, ABS_PRESSURE, field, | ||
| 423 | cls->sn_pressure); | ||
| 424 | mt_store_field(usage, td, hi); | 413 | mt_store_field(usage, td, hi); |
| 425 | td->last_field_index = field->index; | 414 | td->last_field_index = field->index; |
| 426 | return 1; | 415 | return 1; |
| @@ -464,7 +453,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, | |||
| 464 | return -1; | 453 | return -1; |
| 465 | } | 454 | } |
| 466 | 455 | ||
| 467 | static int mt_compute_slot(struct mt_device *td) | 456 | static int mt_compute_slot(struct mt_device *td, struct input_dev *input) |
| 468 | { | 457 | { |
| 469 | __s32 quirks = td->mtclass.quirks; | 458 | __s32 quirks = td->mtclass.quirks; |
| 470 | 459 | ||
| @@ -480,42 +469,23 @@ static int mt_compute_slot(struct mt_device *td) | |||
| 480 | if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) | 469 | if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) |
| 481 | return td->curdata.contactid - 1; | 470 | return td->curdata.contactid - 1; |
| 482 | 471 | ||
| 483 | return find_slot_from_contactid(td); | 472 | return input_mt_get_slot_by_key(input, td->curdata.contactid); |
| 484 | } | 473 | } |
| 485 | 474 | ||
| 486 | /* | 475 | /* |
| 487 | * this function is called when a whole contact has been processed, | 476 | * this function is called when a whole contact has been processed, |
| 488 | * so that it can assign it to a slot and store the data there | 477 | * so that it can assign it to a slot and store the data there |
| 489 | */ | 478 | */ |
| 490 | static void mt_complete_slot(struct mt_device *td) | 479 | static void mt_complete_slot(struct mt_device *td, struct input_dev *input) |
| 491 | { | 480 | { |
| 492 | td->curdata.seen_in_this_frame = true; | ||
| 493 | if (td->curvalid) { | 481 | if (td->curvalid) { |
| 494 | int slotnum = mt_compute_slot(td); | 482 | int slotnum = mt_compute_slot(td, input); |
| 495 | 483 | struct mt_slot *s = &td->curdata; | |
| 496 | if (slotnum >= 0 && slotnum < td->maxcontacts) | ||
| 497 | td->slots[slotnum] = td->curdata; | ||
| 498 | } | ||
| 499 | td->num_received++; | ||
| 500 | } | ||
| 501 | 484 | ||
| 485 | if (slotnum < 0 || slotnum >= td->maxcontacts) | ||
| 486 | return; | ||
| 502 | 487 | ||
| 503 | /* | 488 | input_mt_slot(input, slotnum); |
| 504 | * this function is called when a whole packet has been received and processed, | ||
| 505 | * so that it can decide what to send to the input layer. | ||
| 506 | */ | ||
| 507 | static void mt_emit_event(struct mt_device *td, struct input_dev *input) | ||
| 508 | { | ||
| 509 | int i; | ||
| 510 | |||
| 511 | for (i = 0; i < td->maxcontacts; ++i) { | ||
| 512 | struct mt_slot *s = &(td->slots[i]); | ||
| 513 | if ((td->mtclass.quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && | ||
| 514 | !s->seen_in_this_frame) { | ||
| 515 | s->touch_state = false; | ||
| 516 | } | ||
| 517 | |||
| 518 | input_mt_slot(input, i); | ||
| 519 | input_mt_report_slot_state(input, MT_TOOL_FINGER, | 489 | input_mt_report_slot_state(input, MT_TOOL_FINGER, |
| 520 | s->touch_state); | 490 | s->touch_state); |
| 521 | if (s->touch_state) { | 491 | if (s->touch_state) { |
| @@ -532,24 +502,29 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input) | |||
| 532 | input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); | 502 | input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); |
| 533 | input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); | 503 | input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); |
| 534 | } | 504 | } |
| 535 | s->seen_in_this_frame = false; | ||
| 536 | |||
| 537 | } | 505 | } |
| 538 | 506 | ||
| 539 | input_mt_report_pointer_emulation(input, true); | 507 | td->num_received++; |
| 508 | } | ||
| 509 | |||
| 510 | /* | ||
| 511 | * this function is called when a whole packet has been received and processed, | ||
| 512 | * so that it can decide what to send to the input layer. | ||
| 513 | */ | ||
| 514 | static void mt_sync_frame(struct mt_device *td, struct input_dev *input) | ||
| 515 | { | ||
| 516 | input_mt_sync_frame(input); | ||
| 540 | input_sync(input); | 517 | input_sync(input); |
| 541 | td->num_received = 0; | 518 | td->num_received = 0; |
| 542 | } | 519 | } |
| 543 | 520 | ||
| 544 | |||
| 545 | |||
| 546 | static int mt_event(struct hid_device *hid, struct hid_field *field, | 521 | static int mt_event(struct hid_device *hid, struct hid_field *field, |
| 547 | struct hid_usage *usage, __s32 value) | 522 | struct hid_usage *usage, __s32 value) |
| 548 | { | 523 | { |
| 549 | struct mt_device *td = hid_get_drvdata(hid); | 524 | struct mt_device *td = hid_get_drvdata(hid); |
| 550 | __s32 quirks = td->mtclass.quirks; | 525 | __s32 quirks = td->mtclass.quirks; |
| 551 | 526 | ||
| 552 | if (hid->claimed & HID_CLAIMED_INPUT && td->slots) { | 527 | if (hid->claimed & HID_CLAIMED_INPUT) { |
| 553 | switch (usage->hid) { | 528 | switch (usage->hid) { |
| 554 | case HID_DG_INRANGE: | 529 | case HID_DG_INRANGE: |
| 555 | if (quirks & MT_QUIRK_ALWAYS_VALID) | 530 | if (quirks & MT_QUIRK_ALWAYS_VALID) |
| @@ -602,11 +577,11 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, | |||
| 602 | } | 577 | } |
| 603 | 578 | ||
| 604 | if (usage->hid == td->last_slot_field) | 579 | if (usage->hid == td->last_slot_field) |
| 605 | mt_complete_slot(td); | 580 | mt_complete_slot(td, field->hidinput->input); |
| 606 | 581 | ||
| 607 | if (field->index == td->last_field_index | 582 | if (field->index == td->last_field_index |
| 608 | && td->num_received >= td->num_expected) | 583 | && td->num_received >= td->num_expected) |
| 609 | mt_emit_event(td, field->hidinput->input); | 584 | mt_sync_frame(td, field->hidinput->input); |
| 610 | 585 | ||
| 611 | } | 586 | } |
| 612 | 587 | ||
| @@ -685,18 +660,45 @@ static void mt_post_parse(struct mt_device *td) | |||
| 685 | } | 660 | } |
| 686 | } | 661 | } |
| 687 | 662 | ||
| 663 | static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) | ||
| 664 | |||
| 665 | { | ||
| 666 | struct mt_device *td = hid_get_drvdata(hdev); | ||
| 667 | struct mt_class *cls = &td->mtclass; | ||
| 668 | struct input_dev *input = hi->input; | ||
| 669 | |||
| 670 | /* Only initialize slots for MT input devices */ | ||
| 671 | if (!test_bit(ABS_MT_POSITION_X, input->absbit)) | ||
| 672 | return; | ||
| 673 | |||
| 674 | if (!td->maxcontacts) | ||
| 675 | td->maxcontacts = MT_DEFAULT_MAXCONTACT; | ||
| 676 | |||
| 677 | mt_post_parse(td); | ||
| 678 | if (td->serial_maybe) | ||
| 679 | mt_post_parse_default_settings(td); | ||
| 680 | |||
| 681 | if (cls->is_indirect) | ||
| 682 | td->mt_flags |= INPUT_MT_POINTER; | ||
| 683 | |||
| 684 | if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) | ||
| 685 | td->mt_flags |= INPUT_MT_DROP_UNUSED; | ||
| 686 | |||
| 687 | input_mt_init_slots(input, td->maxcontacts, td->mt_flags); | ||
| 688 | |||
| 689 | td->mt_flags = 0; | ||
| 690 | } | ||
| 691 | |||
| 688 | static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) | 692 | static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) |
| 689 | { | 693 | { |
| 690 | int ret, i; | 694 | int ret, i; |
| 691 | struct mt_device *td; | 695 | struct mt_device *td; |
| 692 | struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */ | 696 | struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */ |
| 693 | 697 | ||
| 694 | if (id) { | 698 | for (i = 0; mt_classes[i].name ; i++) { |
| 695 | for (i = 0; mt_classes[i].name ; i++) { | 699 | if (id->driver_data == mt_classes[i].name) { |
| 696 | if (id->driver_data == mt_classes[i].name) { | 700 | mtclass = &(mt_classes[i]); |
| 697 | mtclass = &(mt_classes[i]); | 701 | break; |
| 698 | break; | ||
| 699 | } | ||
| 700 | } | 702 | } |
| 701 | } | 703 | } |
| 702 | 704 | ||
| @@ -722,6 +724,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
| 722 | goto fail; | 724 | goto fail; |
| 723 | } | 725 | } |
| 724 | 726 | ||
| 727 | if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) | ||
| 728 | td->serial_maybe = true; | ||
| 729 | |||
| 725 | ret = hid_parse(hdev); | 730 | ret = hid_parse(hdev); |
| 726 | if (ret != 0) | 731 | if (ret != 0) |
| 727 | goto fail; | 732 | goto fail; |
| @@ -730,20 +735,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
| 730 | if (ret) | 735 | if (ret) |
| 731 | goto fail; | 736 | goto fail; |
| 732 | 737 | ||
| 733 | mt_post_parse(td); | ||
| 734 | |||
| 735 | if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) | ||
| 736 | mt_post_parse_default_settings(td); | ||
| 737 | |||
| 738 | td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot), | ||
| 739 | GFP_KERNEL); | ||
| 740 | if (!td->slots) { | ||
| 741 | dev_err(&hdev->dev, "cannot allocate multitouch slots\n"); | ||
| 742 | hid_hw_stop(hdev); | ||
| 743 | ret = -ENOMEM; | ||
| 744 | goto fail; | ||
| 745 | } | ||
| 746 | |||
| 747 | ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); | 738 | ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); |
| 748 | 739 | ||
| 749 | mt_set_maxcontacts(hdev); | 740 | mt_set_maxcontacts(hdev); |
| @@ -767,6 +758,32 @@ static int mt_reset_resume(struct hid_device *hdev) | |||
| 767 | mt_set_input_mode(hdev); | 758 | mt_set_input_mode(hdev); |
| 768 | return 0; | 759 | return 0; |
| 769 | } | 760 | } |
| 761 | |||
| 762 | static int mt_resume(struct hid_device *hdev) | ||
| 763 | { | ||
| 764 | struct usb_interface *intf; | ||
| 765 | struct usb_host_interface *interface; | ||
| 766 | struct usb_device *dev; | ||
| 767 | |||
| 768 | if (hdev->bus != BUS_USB) | ||
| 769 | return 0; | ||
| 770 | |||
| 771 | intf = to_usb_interface(hdev->dev.parent); | ||
| 772 | interface = intf->cur_altsetting; | ||
| 773 | dev = hid_to_usb_dev(hdev); | ||
| 774 | |||
| 775 | /* Some Elan legacy devices require SET_IDLE to be set on resume. | ||
| 776 | * It should be safe to send it to other devices too. | ||
| 777 | * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ | ||
| 778 | |||
| 779 | usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
| 780 | HID_REQ_SET_IDLE, | ||
| 781 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
| 782 | 0, interface->desc.bInterfaceNumber, | ||
| 783 | NULL, 0, USB_CTRL_SET_TIMEOUT); | ||
| 784 | |||
| 785 | return 0; | ||
| 786 | } | ||
| 770 | #endif | 787 | #endif |
| 771 | 788 | ||
| 772 | static void mt_remove(struct hid_device *hdev) | 789 | static void mt_remove(struct hid_device *hdev) |
| @@ -774,7 +791,6 @@ static void mt_remove(struct hid_device *hdev) | |||
| 774 | struct mt_device *td = hid_get_drvdata(hdev); | 791 | struct mt_device *td = hid_get_drvdata(hdev); |
| 775 | sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); | 792 | sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); |
| 776 | hid_hw_stop(hdev); | 793 | hid_hw_stop(hdev); |
| 777 | kfree(td->slots); | ||
| 778 | kfree(td); | 794 | kfree(td); |
| 779 | hid_set_drvdata(hdev, NULL); | 795 | hid_set_drvdata(hdev, NULL); |
| 780 | } | 796 | } |
| @@ -885,17 +901,37 @@ static const struct hid_device_id mt_devices[] = { | |||
| 885 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) }, | 901 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) }, |
| 886 | { .driver_data = MT_CLS_EGALAX_SERIAL, | 902 | { .driver_data = MT_CLS_EGALAX_SERIAL, |
| 887 | MT_USB_DEVICE(USB_VENDOR_ID_DWAV, | 903 | MT_USB_DEVICE(USB_VENDOR_ID_DWAV, |
| 904 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7) }, | ||
| 905 | { .driver_data = MT_CLS_EGALAX_SERIAL, | ||
| 906 | MT_USB_DEVICE(USB_VENDOR_ID_DWAV, | ||
| 888 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, | 907 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, |
| 908 | { .driver_data = MT_CLS_EGALAX, | ||
| 909 | HID_USB_DEVICE(USB_VENDOR_ID_DWAV, | ||
| 910 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) }, | ||
| 911 | { .driver_data = MT_CLS_EGALAX, | ||
| 912 | HID_USB_DEVICE(USB_VENDOR_ID_DWAV, | ||
| 913 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0) }, | ||
| 914 | { .driver_data = MT_CLS_EGALAX, | ||
| 915 | HID_USB_DEVICE(USB_VENDOR_ID_DWAV, | ||
| 916 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) }, | ||
| 889 | 917 | ||
| 890 | /* Elo TouchSystems IntelliTouch Plus panel */ | 918 | /* Elo TouchSystems IntelliTouch Plus panel */ |
| 891 | { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID, | 919 | { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID, |
| 892 | MT_USB_DEVICE(USB_VENDOR_ID_ELO, | 920 | MT_USB_DEVICE(USB_VENDOR_ID_ELO, |
| 893 | USB_DEVICE_ID_ELO_TS2515) }, | 921 | USB_DEVICE_ID_ELO_TS2515) }, |
| 894 | 922 | ||
| 923 | /* Flatfrog Panels */ | ||
| 924 | { .driver_data = MT_CLS_FLATFROG, | ||
| 925 | MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG, | ||
| 926 | USB_DEVICE_ID_MULTITOUCH_3200) }, | ||
| 927 | |||
| 895 | /* GeneralTouch panel */ | 928 | /* GeneralTouch panel */ |
| 896 | { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, | 929 | { .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS, |
| 897 | MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, | 930 | MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, |
| 898 | USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, | 931 | USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, |
| 932 | { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, | ||
| 933 | MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, | ||
| 934 | USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS) }, | ||
| 899 | 935 | ||
| 900 | /* Gametel game controller */ | 936 | /* Gametel game controller */ |
| 901 | { .driver_data = MT_CLS_DEFAULT, | 937 | { .driver_data = MT_CLS_DEFAULT, |
| @@ -1087,11 +1123,13 @@ static struct hid_driver mt_driver = { | |||
| 1087 | .remove = mt_remove, | 1123 | .remove = mt_remove, |
| 1088 | .input_mapping = mt_input_mapping, | 1124 | .input_mapping = mt_input_mapping, |
| 1089 | .input_mapped = mt_input_mapped, | 1125 | .input_mapped = mt_input_mapped, |
| 1126 | .input_configured = mt_input_configured, | ||
| 1090 | .feature_mapping = mt_feature_mapping, | 1127 | .feature_mapping = mt_feature_mapping, |
| 1091 | .usage_table = mt_grabbed_usages, | 1128 | .usage_table = mt_grabbed_usages, |
| 1092 | .event = mt_event, | 1129 | .event = mt_event, |
| 1093 | #ifdef CONFIG_PM | 1130 | #ifdef CONFIG_PM |
| 1094 | .reset_resume = mt_reset_resume, | 1131 | .reset_resume = mt_reset_resume, |
| 1132 | .resume = mt_resume, | ||
| 1095 | #endif | 1133 | #endif |
| 1096 | }; | 1134 | }; |
| 1097 | 1135 | ||
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 9fae2ebdd758..86a969f63292 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c | |||
| @@ -882,10 +882,10 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
| 882 | nd->activate_slack = activate_slack; | 882 | nd->activate_slack = activate_slack; |
| 883 | nd->act_state = activate_slack; | 883 | nd->act_state = activate_slack; |
| 884 | nd->deactivate_slack = -deactivate_slack; | 884 | nd->deactivate_slack = -deactivate_slack; |
| 885 | nd->sensor_logical_width = 0; | 885 | nd->sensor_logical_width = 1; |
| 886 | nd->sensor_logical_height = 0; | 886 | nd->sensor_logical_height = 1; |
| 887 | nd->sensor_physical_width = 0; | 887 | nd->sensor_physical_width = 1; |
| 888 | nd->sensor_physical_height = 0; | 888 | nd->sensor_physical_height = 1; |
| 889 | 889 | ||
| 890 | hid_set_drvdata(hdev, nd); | 890 | hid_set_drvdata(hdev, nd); |
| 891 | 891 | ||
diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c index f1ea3ff8a98d..4c521de4e7e6 100644 --- a/drivers/hid/hid-petalynx.c +++ b/drivers/hid/hid-petalynx.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | * Copyright (c) 2008 Jiri Slaby | 8 | * Copyright (c) 2008 Jiri Slaby |
| 10 | */ | 9 | */ |
| 11 | 10 | ||
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c deleted file mode 100644 index 27c8ebdfad01..000000000000 --- a/drivers/hid/hid-picolcd.c +++ /dev/null | |||
| @@ -1,2748 +0,0 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Copyright (C) 2010 by Bruno Prémont <bonbons@linux-vserver.org> * | ||
| 3 | * * | ||
| 4 | * Based on Logitech G13 driver (v0.4) * | ||
| 5 | * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * | ||
| 6 | * * | ||
| 7 | * This program is free software: you can redistribute it and/or modify * | ||
| 8 | * it under the terms of the GNU General Public License as published by * | ||
| 9 | * the Free Software Foundation, version 2 of the License. * | ||
| 10 | * * | ||
| 11 | * This driver is distributed in the hope that it will be useful, but * | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * | ||
| 14 | * General Public License for more details. * | ||
| 15 | * * | ||
| 16 | * You should have received a copy of the GNU General Public License * | ||
| 17 | * along with this software. If not see <http://www.gnu.org/licenses/>. * | ||
| 18 | ***************************************************************************/ | ||
| 19 | |||
| 20 | #include <linux/hid.h> | ||
| 21 | #include <linux/hid-debug.h> | ||
| 22 | #include <linux/input.h> | ||
| 23 | #include "hid-ids.h" | ||
| 24 | #include "usbhid/usbhid.h" | ||
| 25 | #include <linux/usb.h> | ||
| 26 | |||
| 27 | #include <linux/fb.h> | ||
| 28 | #include <linux/vmalloc.h> | ||
| 29 | #include <linux/backlight.h> | ||
| 30 | #include <linux/lcd.h> | ||
| 31 | |||
| 32 | #include <linux/leds.h> | ||
| 33 | |||
| 34 | #include <linux/seq_file.h> | ||
| 35 | #include <linux/debugfs.h> | ||
| 36 | |||
| 37 | #include <linux/completion.h> | ||
| 38 | #include <linux/uaccess.h> | ||
| 39 | #include <linux/module.h> | ||
| 40 | |||
| 41 | #define PICOLCD_NAME "PicoLCD (graphic)" | ||
| 42 | |||
| 43 | /* Report numbers */ | ||
| 44 | #define REPORT_ERROR_CODE 0x10 /* LCD: IN[16] */ | ||
| 45 | #define ERR_SUCCESS 0x00 | ||
| 46 | #define ERR_PARAMETER_MISSING 0x01 | ||
| 47 | #define ERR_DATA_MISSING 0x02 | ||
| 48 | #define ERR_BLOCK_READ_ONLY 0x03 | ||
| 49 | #define ERR_BLOCK_NOT_ERASABLE 0x04 | ||
| 50 | #define ERR_BLOCK_TOO_BIG 0x05 | ||
| 51 | #define ERR_SECTION_OVERFLOW 0x06 | ||
| 52 | #define ERR_INVALID_CMD_LEN 0x07 | ||
| 53 | #define ERR_INVALID_DATA_LEN 0x08 | ||
| 54 | #define REPORT_KEY_STATE 0x11 /* LCD: IN[2] */ | ||
| 55 | #define REPORT_IR_DATA 0x21 /* LCD: IN[63] */ | ||
| 56 | #define REPORT_EE_DATA 0x32 /* LCD: IN[63] */ | ||
| 57 | #define REPORT_MEMORY 0x41 /* LCD: IN[63] */ | ||
| 58 | #define REPORT_LED_STATE 0x81 /* LCD: OUT[1] */ | ||
| 59 | #define REPORT_BRIGHTNESS 0x91 /* LCD: OUT[1] */ | ||
| 60 | #define REPORT_CONTRAST 0x92 /* LCD: OUT[1] */ | ||
| 61 | #define REPORT_RESET 0x93 /* LCD: OUT[2] */ | ||
| 62 | #define REPORT_LCD_CMD 0x94 /* LCD: OUT[63] */ | ||
| 63 | #define REPORT_LCD_DATA 0x95 /* LCD: OUT[63] */ | ||
| 64 | #define REPORT_LCD_CMD_DATA 0x96 /* LCD: OUT[63] */ | ||
| 65 | #define REPORT_EE_READ 0xa3 /* LCD: OUT[63] */ | ||
| 66 | #define REPORT_EE_WRITE 0xa4 /* LCD: OUT[63] */ | ||
| 67 | #define REPORT_ERASE_MEMORY 0xb2 /* LCD: OUT[2] */ | ||
| 68 | #define REPORT_READ_MEMORY 0xb3 /* LCD: OUT[3] */ | ||
| 69 | #define REPORT_WRITE_MEMORY 0xb4 /* LCD: OUT[63] */ | ||
| 70 | #define REPORT_SPLASH_RESTART 0xc1 /* LCD: OUT[1] */ | ||
| 71 | #define REPORT_EXIT_KEYBOARD 0xef /* LCD: OUT[2] */ | ||
| 72 | #define REPORT_VERSION 0xf1 /* LCD: IN[2],OUT[1] Bootloader: IN[2],OUT[1] */ | ||
| 73 | #define REPORT_BL_ERASE_MEMORY 0xf2 /* Bootloader: IN[36],OUT[4] */ | ||
| 74 | #define REPORT_BL_READ_MEMORY 0xf3 /* Bootloader: IN[36],OUT[4] */ | ||
| 75 | #define REPORT_BL_WRITE_MEMORY 0xf4 /* Bootloader: IN[36],OUT[36] */ | ||
| 76 | #define REPORT_DEVID 0xf5 /* LCD: IN[5], OUT[1] Bootloader: IN[5],OUT[1] */ | ||
| 77 | #define REPORT_SPLASH_SIZE 0xf6 /* LCD: IN[4], OUT[1] */ | ||
| 78 | #define REPORT_HOOK_VERSION 0xf7 /* LCD: IN[2], OUT[1] */ | ||
| 79 | #define REPORT_EXIT_FLASHER 0xff /* Bootloader: OUT[2] */ | ||
| 80 | |||
| 81 | #ifdef CONFIG_HID_PICOLCD_FB | ||
| 82 | /* Framebuffer | ||
| 83 | * | ||
| 84 | * The PicoLCD use a Topway LCD module of 256x64 pixel | ||
| 85 | * This display area is tiled over 4 controllers with 8 tiles | ||
| 86 | * each. Each tile has 8x64 pixel, each data byte representing | ||
| 87 | * a 1-bit wide vertical line of the tile. | ||
| 88 | * | ||
| 89 | * The display can be updated at a tile granularity. | ||
| 90 | * | ||
| 91 | * Chip 1 Chip 2 Chip 3 Chip 4 | ||
| 92 | * +----------------+----------------+----------------+----------------+ | ||
| 93 | * | Tile 1 | Tile 1 | Tile 1 | Tile 1 | | ||
| 94 | * +----------------+----------------+----------------+----------------+ | ||
| 95 | * | Tile 2 | Tile 2 | Tile 2 | Tile 2 | | ||
| 96 | * +----------------+----------------+----------------+----------------+ | ||
| 97 | * ... | ||
| 98 | * +----------------+----------------+----------------+----------------+ | ||
| 99 | * | Tile 8 | Tile 8 | Tile 8 | Tile 8 | | ||
| 100 | * +----------------+----------------+----------------+----------------+ | ||
| 101 | */ | ||
| 102 | #define PICOLCDFB_NAME "picolcdfb" | ||
| 103 | #define PICOLCDFB_WIDTH (256) | ||
| 104 | #define PICOLCDFB_HEIGHT (64) | ||
| 105 | #define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8) | ||
| 106 | |||
| 107 | #define PICOLCDFB_UPDATE_RATE_LIMIT 10 | ||
| 108 | #define PICOLCDFB_UPDATE_RATE_DEFAULT 2 | ||
| 109 | |||
| 110 | /* Framebuffer visual structures */ | ||
| 111 | static const struct fb_fix_screeninfo picolcdfb_fix = { | ||
| 112 | .id = PICOLCDFB_NAME, | ||
| 113 | .type = FB_TYPE_PACKED_PIXELS, | ||
| 114 | .visual = FB_VISUAL_MONO01, | ||
| 115 | .xpanstep = 0, | ||
| 116 | .ypanstep = 0, | ||
| 117 | .ywrapstep = 0, | ||
| 118 | .line_length = PICOLCDFB_WIDTH / 8, | ||
| 119 | .accel = FB_ACCEL_NONE, | ||
| 120 | }; | ||
| 121 | |||
| 122 | static const struct fb_var_screeninfo picolcdfb_var = { | ||
| 123 | .xres = PICOLCDFB_WIDTH, | ||
| 124 | .yres = PICOLCDFB_HEIGHT, | ||
| 125 | .xres_virtual = PICOLCDFB_WIDTH, | ||
| 126 | .yres_virtual = PICOLCDFB_HEIGHT, | ||
| 127 | .width = 103, | ||
| 128 | .height = 26, | ||
| 129 | .bits_per_pixel = 1, | ||
| 130 | .grayscale = 1, | ||
| 131 | .red = { | ||
| 132 | .offset = 0, | ||
| 133 | .length = 1, | ||
| 134 | .msb_right = 0, | ||
| 135 | }, | ||
| 136 | .green = { | ||
| 137 | .offset = 0, | ||
| 138 | .length = 1, | ||
| 139 | .msb_right = 0, | ||
| 140 | }, | ||
| 141 | .blue = { | ||
| 142 | .offset = 0, | ||
| 143 | .length = 1, | ||
| 144 | .msb_right = 0, | ||
| 145 | }, | ||
| 146 | .transp = { | ||
| 147 | .offset = 0, | ||
| 148 | .length = 0, | ||
| 149 | .msb_right = 0, | ||
| 150 | }, | ||
| 151 | }; | ||
| 152 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
| 153 | |||
| 154 | /* Input device | ||
| 155 | * | ||
| 156 | * The PicoLCD has an IR receiver header, a built-in keypad with 5 keys | ||
| 157 | * and header for 4x4 key matrix. The built-in keys are part of the matrix. | ||
| 158 | */ | ||
| 159 | static const unsigned short def_keymap[] = { | ||
| 160 | KEY_RESERVED, /* none */ | ||
| 161 | KEY_BACK, /* col 4 + row 1 */ | ||
| 162 | KEY_HOMEPAGE, /* col 3 + row 1 */ | ||
| 163 | KEY_RESERVED, /* col 2 + row 1 */ | ||
| 164 | KEY_RESERVED, /* col 1 + row 1 */ | ||
| 165 | KEY_SCROLLUP, /* col 4 + row 2 */ | ||
| 166 | KEY_OK, /* col 3 + row 2 */ | ||
| 167 | KEY_SCROLLDOWN, /* col 2 + row 2 */ | ||
| 168 | KEY_RESERVED, /* col 1 + row 2 */ | ||
| 169 | KEY_RESERVED, /* col 4 + row 3 */ | ||
| 170 | KEY_RESERVED, /* col 3 + row 3 */ | ||
| 171 | KEY_RESERVED, /* col 2 + row 3 */ | ||
| 172 | KEY_RESERVED, /* col 1 + row 3 */ | ||
| 173 | KEY_RESERVED, /* col 4 + row 4 */ | ||
| 174 | KEY_RESERVED, /* col 3 + row 4 */ | ||
| 175 | KEY_RESERVED, /* col 2 + row 4 */ | ||
| 176 | KEY_RESERVED, /* col 1 + row 4 */ | ||
| 177 | }; | ||
| 178 | #define PICOLCD_KEYS ARRAY_SIZE(def_keymap) | ||
| 179 | |||
| 180 | /* Description of in-progress IO operation, used for operations | ||
| 181 | * that trigger response from device */ | ||
| 182 | struct picolcd_pending { | ||
| 183 | struct hid_report *out_report; | ||
| 184 | struct hid_report *in_report; | ||
| 185 | struct completion ready; | ||
| 186 | int raw_size; | ||
| 187 | u8 raw_data[64]; | ||
| 188 | }; | ||
| 189 | |||
| 190 | /* Per device data structure */ | ||
| 191 | struct picolcd_data { | ||
| 192 | struct hid_device *hdev; | ||
| 193 | #ifdef CONFIG_DEBUG_FS | ||
| 194 | struct dentry *debug_reset; | ||
| 195 | struct dentry *debug_eeprom; | ||
| 196 | struct dentry *debug_flash; | ||
| 197 | struct mutex mutex_flash; | ||
| 198 | int addr_sz; | ||
| 199 | #endif | ||
| 200 | u8 version[2]; | ||
| 201 | unsigned short opmode_delay; | ||
| 202 | /* input stuff */ | ||
| 203 | u8 pressed_keys[2]; | ||
| 204 | struct input_dev *input_keys; | ||
| 205 | struct input_dev *input_cir; | ||
| 206 | unsigned short keycode[PICOLCD_KEYS]; | ||
| 207 | |||
| 208 | #ifdef CONFIG_HID_PICOLCD_FB | ||
| 209 | /* Framebuffer stuff */ | ||
| 210 | u8 fb_update_rate; | ||
| 211 | u8 fb_bpp; | ||
| 212 | u8 fb_force; | ||
| 213 | u8 *fb_vbitmap; /* local copy of what was sent to PicoLCD */ | ||
| 214 | u8 *fb_bitmap; /* framebuffer */ | ||
| 215 | struct fb_info *fb_info; | ||
| 216 | struct fb_deferred_io fb_defio; | ||
| 217 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
| 218 | #ifdef CONFIG_HID_PICOLCD_LCD | ||
| 219 | struct lcd_device *lcd; | ||
| 220 | u8 lcd_contrast; | ||
| 221 | #endif /* CONFIG_HID_PICOLCD_LCD */ | ||
| 222 | #ifdef CONFIG_HID_PICOLCD_BACKLIGHT | ||
| 223 | struct backlight_device *backlight; | ||
| 224 | u8 lcd_brightness; | ||
| 225 | u8 lcd_power; | ||
| 226 | #endif /* CONFIG_HID_PICOLCD_BACKLIGHT */ | ||
| 227 | #ifdef CONFIG_HID_PICOLCD_LEDS | ||
| 228 | /* LED stuff */ | ||
| 229 | u8 led_state; | ||
| 230 | struct led_classdev *led[8]; | ||
| 231 | #endif /* CONFIG_HID_PICOLCD_LEDS */ | ||
| 232 | |||
| 233 | /* Housekeeping stuff */ | ||
| 234 | spinlock_t lock; | ||
| 235 | struct mutex mutex; | ||
| 236 | struct picolcd_pending *pending; | ||
| 237 | int status; | ||
| 238 | #define PICOLCD_BOOTLOADER 1 | ||
| 239 | #define PICOLCD_FAILED 2 | ||
| 240 | #define PICOLCD_READY_FB 4 | ||
| 241 | }; | ||
| 242 | |||
| 243 | |||
| 244 | /* Find a given report */ | ||
| 245 | #define picolcd_in_report(id, dev) picolcd_report(id, dev, HID_INPUT_REPORT) | ||
| 246 | #define picolcd_out_report(id, dev) picolcd_report(id, dev, HID_OUTPUT_REPORT) | ||
| 247 | |||
| 248 | static struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir) | ||
| 249 | { | ||
| 250 | struct list_head *feature_report_list = &hdev->report_enum[dir].report_list; | ||
| 251 | struct hid_report *report = NULL; | ||
| 252 | |||
| 253 | list_for_each_entry(report, feature_report_list, list) { | ||
| 254 | if (report->id == id) | ||
| 255 | return report; | ||
| 256 | } | ||
| 257 | hid_warn(hdev, "No report with id 0x%x found\n", id); | ||
| 258 | return NULL; | ||
| 259 | } | ||
| 260 | |||
| 261 | #ifdef CONFIG_DEBUG_FS | ||
| 262 | static void picolcd_debug_out_report(struct picolcd_data *data, | ||
| 263 | struct hid_device *hdev, struct hid_report *report); | ||
| 264 | #define usbhid_submit_report(a, b, c) \ | ||
| 265 | do { \ | ||
| 266 | picolcd_debug_out_report(hid_get_drvdata(a), a, b); \ | ||
| 267 | usbhid_submit_report(a, b, c); \ | ||
| 268 | } while (0) | ||
| 269 | #endif | ||
| 270 | |||
| 271 | /* Submit a report and wait for a reply from device - if device fades away | ||
| 272 | * or does not respond in time, return NULL */ | ||
| 273 | static struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev, | ||
| 274 | int report_id, const u8 *raw_data, int size) | ||
| 275 | { | ||
| 276 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
| 277 | struct picolcd_pending *work; | ||
| 278 | struct hid_report *report = picolcd_out_report(report_id, hdev); | ||
| 279 | unsigned long flags; | ||
| 280 | int i, j, k; | ||
| 281 | |||
| 282 | if (!report || !data) | ||
| 283 | return NULL; | ||
| 284 | if (data->status & PICOLCD_FAILED) | ||
| 285 | return NULL; | ||
| 286 | work = kzalloc(sizeof(*work), GFP_KERNEL); | ||
| 287 | if (!work) | ||
| 288 | return NULL; | ||
| 289 | |||
| 290 | init_completion(&work->ready); | ||
| 291 | work->out_report = report; | ||
| 292 | work->in_report = NULL; | ||
| 293 | work->raw_size = 0; | ||
| 294 | |||
| 295 | mutex_lock(&data->mutex); | ||
| 296 | spin_lock_irqsave(&data->lock, flags); | ||
| 297 | for (i = k = 0; i < report->maxfield; i++) | ||
| 298 | for (j = 0; j < report->field[i]->report_count; j++) { | ||
| 299 | hid_set_field(report->field[i], j, k < size ? raw_data[k] : 0); | ||
| 300 | k++; | ||
| 301 | } | ||
| 302 | data->pending = work; | ||
| 303 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
| 304 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 305 | wait_for_completion_interruptible_timeout(&work->ready, HZ*2); | ||
| 306 | spin_lock_irqsave(&data->lock, flags); | ||
| 307 | data->pending = NULL; | ||
| 308 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 309 | mutex_unlock(&data->mutex); | ||
| 310 | return work; | ||
| 311 | } | ||
| 312 | |||
| 313 | #ifdef CONFIG_HID_PICOLCD_FB | ||
| 314 | /* Send a given tile to PicoLCD */ | ||
| 315 | static int picolcd_fb_send_tile(struct hid_device *hdev, int chip, int tile) | ||
| 316 | { | ||
| 317 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
| 318 | struct hid_report *report1 = picolcd_out_report(REPORT_LCD_CMD_DATA, hdev); | ||
| 319 | struct hid_report *report2 = picolcd_out_report(REPORT_LCD_DATA, hdev); | ||
| 320 | unsigned long flags; | ||
| 321 | u8 *tdata; | ||
| 322 | int i; | ||
| 323 | |||
| 324 | if (!report1 || report1->maxfield != 1 || !report2 || report2->maxfield != 1) | ||
| 325 | return -ENODEV; | ||
| 326 | |||
| 327 | spin_lock_irqsave(&data->lock, flags); | ||
| 328 | hid_set_field(report1->field[0], 0, chip << 2); | ||
| 329 | hid_set_field(report1->field[0], 1, 0x02); | ||
| 330 | hid_set_field(report1->field[0], 2, 0x00); | ||
| 331 | hid_set_field(report1->field[0], 3, 0x00); | ||
| 332 | hid_set_field(report1->field[0], 4, 0xb8 | tile); | ||
| 333 | hid_set_field(report1->field[0], 5, 0x00); | ||
| 334 | hid_set_field(report1->field[0], 6, 0x00); | ||
| 335 | hid_set_field(report1->field[0], 7, 0x40); | ||
| 336 | hid_set_field(report1->field[0], 8, 0x00); | ||
| 337 | hid_set_field(report1->field[0], 9, 0x00); | ||
| 338 | hid_set_field(report1->field[0], 10, 32); | ||
| 339 | |||
| 340 | hid_set_field(report2->field[0], 0, (chip << 2) | 0x01); | ||
| 341 | hid_set_field(report2->field[0], 1, 0x00); | ||
| 342 | hid_set_field(report2->field[0], 2, 0x00); | ||
| 343 | hid_set_field(report2->field[0], 3, 32); | ||
| 344 | |||
| 345 | tdata = data->fb_vbitmap + (tile * 4 + chip) * 64; | ||
| 346 | for (i = 0; i < 64; i++) | ||
| 347 | if (i < 32) | ||
| 348 | hid_set_field(report1->field[0], 11 + i, tdata[i]); | ||
| 349 | else | ||
| 350 | hid_set_field(report2->field[0], 4 + i - 32, tdata[i]); | ||
| 351 | |||
| 352 | usbhid_submit_report(data->hdev, report1, USB_DIR_OUT); | ||
| 353 | usbhid_submit_report(data->hdev, report2, USB_DIR_OUT); | ||
| 354 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 355 | return 0; | ||
| 356 | } | ||
| 357 | |||
| 358 | /* Translate a single tile*/ | ||
| 359 | static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp, | ||
| 360 | int chip, int tile) | ||
| 361 | { | ||
| 362 | int i, b, changed = 0; | ||
| 363 | u8 tdata[64]; | ||
| 364 | u8 *vdata = vbitmap + (tile * 4 + chip) * 64; | ||
| 365 | |||
| 366 | if (bpp == 1) { | ||
| 367 | for (b = 7; b >= 0; b--) { | ||
| 368 | const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32; | ||
| 369 | for (i = 0; i < 64; i++) { | ||
| 370 | tdata[i] <<= 1; | ||
| 371 | tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01; | ||
| 372 | } | ||
| 373 | } | ||
| 374 | } else if (bpp == 8) { | ||
| 375 | for (b = 7; b >= 0; b--) { | ||
| 376 | const u8 *bdata = bitmap + (tile * 256 + chip * 8 + b * 32) * 8; | ||
| 377 | for (i = 0; i < 64; i++) { | ||
| 378 | tdata[i] <<= 1; | ||
| 379 | tdata[i] |= (bdata[i] & 0x80) ? 0x01 : 0x00; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | } else { | ||
| 383 | /* Oops, we should never get here! */ | ||
| 384 | WARN_ON(1); | ||
| 385 | return 0; | ||
| 386 | } | ||
| 387 | |||
| 388 | for (i = 0; i < 64; i++) | ||
| 389 | if (tdata[i] != vdata[i]) { | ||
| 390 | changed = 1; | ||
| 391 | vdata[i] = tdata[i]; | ||
| 392 | } | ||
| 393 | return changed; | ||
| 394 | } | ||
| 395 | |||
| 396 | /* Reconfigure LCD display */ | ||
| 397 | static int picolcd_fb_reset(struct picolcd_data *data, int clear) | ||
| 398 | { | ||
| 399 | struct hid_report *report = picolcd_out_report(REPORT_LCD_CMD, data->hdev); | ||
| 400 | int i, j; | ||
| 401 | unsigned long flags; | ||
| 402 | static const u8 mapcmd[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 }; | ||
| 403 | |||
| 404 | if (!report || report->maxfield != 1) | ||
| 405 | return -ENODEV; | ||
| 406 | |||
| 407 | spin_lock_irqsave(&data->lock, flags); | ||
| 408 | for (i = 0; i < 4; i++) { | ||
| 409 | for (j = 0; j < report->field[0]->maxusage; j++) | ||
| 410 | if (j == 0) | ||
| 411 | hid_set_field(report->field[0], j, i << 2); | ||
| 412 | else if (j < sizeof(mapcmd)) | ||
| 413 | hid_set_field(report->field[0], j, mapcmd[j]); | ||
| 414 | else | ||
| 415 | hid_set_field(report->field[0], j, 0); | ||
| 416 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
| 417 | } | ||
| 418 | |||
| 419 | data->status |= PICOLCD_READY_FB; | ||
| 420 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 421 | |||
| 422 | if (data->fb_bitmap) { | ||
| 423 | if (clear) { | ||
| 424 | memset(data->fb_vbitmap, 0, PICOLCDFB_SIZE); | ||
| 425 | memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp); | ||
| 426 | } | ||
| 427 | data->fb_force = 1; | ||
| 428 | } | ||
| 429 | |||
| 430 | /* schedule first output of framebuffer */ | ||
| 431 | if (data->fb_info) | ||
| 432 | schedule_delayed_work(&data->fb_info->deferred_work, 0); | ||
| 433 | |||
| 434 | return 0; | ||
| 435 | } | ||
| 436 | |||
| 437 | /* Update fb_vbitmap from the screen_base and send changed tiles to device */ | ||
| 438 | static void picolcd_fb_update(struct picolcd_data *data) | ||
| 439 | { | ||
| 440 | int chip, tile, n; | ||
| 441 | unsigned long flags; | ||
| 442 | |||
| 443 | if (!data) | ||
| 444 | return; | ||
| 445 | |||
| 446 | spin_lock_irqsave(&data->lock, flags); | ||
| 447 | if (!(data->status & PICOLCD_READY_FB)) { | ||
| 448 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 449 | picolcd_fb_reset(data, 0); | ||
| 450 | } else { | ||
| 451 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 452 | } | ||
| 453 | |||
| 454 | /* | ||
| 455 | * Translate the framebuffer into the format needed by the PicoLCD. | ||
| 456 | * See display layout above. | ||
| 457 | * Do this one tile after the other and push those tiles that changed. | ||
| 458 | * | ||
| 459 | * Wait for our IO to complete as otherwise we might flood the queue! | ||
| 460 | */ | ||
| 461 | n = 0; | ||
| 462 | for (chip = 0; chip < 4; chip++) | ||
| 463 | for (tile = 0; tile < 8; tile++) | ||
| 464 | if (picolcd_fb_update_tile(data->fb_vbitmap, | ||
| 465 | data->fb_bitmap, data->fb_bpp, chip, tile) || | ||
| 466 | data->fb_force) { | ||
| 467 | n += 2; | ||
| 468 | if (!data->fb_info->par) | ||
| 469 | return; /* device lost! */ | ||
| 470 | if (n >= HID_OUTPUT_FIFO_SIZE / 2) { | ||
| 471 | usbhid_wait_io(data->hdev); | ||
| 472 | n = 0; | ||
| 473 | } | ||
| 474 | picolcd_fb_send_tile(data->hdev, chip, tile); | ||
| 475 | } | ||
| 476 | data->fb_force = false; | ||
| 477 | if (n) | ||
| 478 | usbhid_wait_io(data->hdev); | ||
| 479 | } | ||
| 480 | |||
| 481 | /* Stub to call the system default and update the image on the picoLCD */ | ||
| 482 | static void picolcd_fb_fillrect(struct fb_info *info, | ||
| 483 | const struct fb_fillrect *rect) | ||
| 484 | { | ||
| 485 | if (!info->par) | ||
| 486 | return; | ||
| 487 | sys_fillrect(info, rect); | ||
| 488 | |||
| 489 | schedule_delayed_work(&info->deferred_work, 0); | ||
| 490 | } | ||
| 491 | |||
| 492 | /* Stub to call the system default and update the image on the picoLCD */ | ||
| 493 | static void picolcd_fb_copyarea(struct fb_info *info, | ||
| 494 | const struct fb_copyarea *area) | ||
| 495 | { | ||
| 496 | if (!info->par) | ||
| 497 | return; | ||
| 498 | sys_copyarea(info, area); | ||
| 499 | |||
| 500 | schedule_delayed_work(&info->deferred_work, 0); | ||
| 501 | } | ||
| 502 | |||
| 503 | /* Stub to call the system default and update the image on the picoLCD */ | ||
| 504 | static void picolcd_fb_imageblit(struct fb_info *info, const struct fb_image *image) | ||
| 505 | { | ||
| 506 | if (!info->par) | ||
| 507 | return; | ||
| 508 | sys_imageblit(info, image); | ||
| 509 | |||
| 510 | schedule_delayed_work(&info->deferred_work, 0); | ||
| 511 | } | ||
| 512 | |||
| 513 | /* | ||
| 514 | * this is the slow path from userspace. they can seek and write to | ||
| 515 | * the fb. it's inefficient to do anything less than a full screen draw | ||
| 516 | */ | ||
| 517 | static ssize_t picolcd_fb_write(struct fb_info *info, const char __user *buf, | ||
| 518 | size_t count, loff_t *ppos) | ||
| 519 | { | ||
| 520 | ssize_t ret; | ||
| 521 | if (!info->par) | ||
| 522 | return -ENODEV; | ||
| 523 | ret = fb_sys_write(info, buf, count, ppos); | ||
| 524 | if (ret >= 0) | ||
| 525 | schedule_delayed_work(&info->deferred_work, 0); | ||
| 526 | return ret; | ||
| 527 | } | ||
| 528 | |||
| 529 | static int picolcd_fb_blank(int blank, struct fb_info *info) | ||
| 530 | { | ||
| 531 | if (!info->par) | ||
| 532 | return -ENODEV; | ||
| 533 | /* We let fb notification do this for us via lcd/backlight device */ | ||
| 534 | return 0; | ||
| 535 | } | ||
| 536 | |||
| 537 | static void picolcd_fb_destroy(struct fb_info *info) | ||
| 538 | { | ||
| 539 | struct picolcd_data *data = info->par; | ||
| 540 | u32 *ref_cnt = info->pseudo_palette; | ||
| 541 | int may_release; | ||
| 542 | |||
| 543 | info->par = NULL; | ||
| 544 | if (data) | ||
| 545 | data->fb_info = NULL; | ||
| 546 | fb_deferred_io_cleanup(info); | ||
| 547 | |||
| 548 | ref_cnt--; | ||
| 549 | mutex_lock(&info->lock); | ||
| 550 | (*ref_cnt)--; | ||
| 551 | may_release = !*ref_cnt; | ||
| 552 | mutex_unlock(&info->lock); | ||
| 553 | if (may_release) { | ||
| 554 | vfree((u8 *)info->fix.smem_start); | ||
| 555 | framebuffer_release(info); | ||
| 556 | } | ||
| 557 | } | ||
| 558 | |||
| 559 | static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||
| 560 | { | ||
| 561 | __u32 bpp = var->bits_per_pixel; | ||
| 562 | __u32 activate = var->activate; | ||
| 563 | |||
| 564 | /* only allow 1/8 bit depth (8-bit is grayscale) */ | ||
| 565 | *var = picolcdfb_var; | ||
| 566 | var->activate = activate; | ||
| 567 | if (bpp >= 8) { | ||
| 568 | var->bits_per_pixel = 8; | ||
| 569 | var->red.length = 8; | ||
| 570 | var->green.length = 8; | ||
| 571 | var->blue.length = 8; | ||
| 572 | } else { | ||
| 573 | var->bits_per_pixel = 1; | ||
| 574 | var->red.length = 1; | ||
| 575 | var->green.length = 1; | ||
| 576 | var->blue.length = 1; | ||
| 577 | } | ||
| 578 | return 0; | ||
| 579 | } | ||
| 580 | |||
| 581 | static int picolcd_set_par(struct fb_info *info) | ||
| 582 | { | ||
| 583 | struct picolcd_data *data = info->par; | ||
| 584 | u8 *tmp_fb, *o_fb; | ||
| 585 | if (!data) | ||
| 586 | return -ENODEV; | ||
| 587 | if (info->var.bits_per_pixel == data->fb_bpp) | ||
| 588 | return 0; | ||
| 589 | /* switch between 1/8 bit depths */ | ||
| 590 | if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8) | ||
| 591 | return -EINVAL; | ||
| 592 | |||
| 593 | o_fb = data->fb_bitmap; | ||
| 594 | tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL); | ||
| 595 | if (!tmp_fb) | ||
| 596 | return -ENOMEM; | ||
| 597 | |||
| 598 | /* translate FB content to new bits-per-pixel */ | ||
| 599 | if (info->var.bits_per_pixel == 1) { | ||
| 600 | int i, b; | ||
| 601 | for (i = 0; i < PICOLCDFB_SIZE; i++) { | ||
| 602 | u8 p = 0; | ||
| 603 | for (b = 0; b < 8; b++) { | ||
| 604 | p <<= 1; | ||
| 605 | p |= o_fb[i*8+b] ? 0x01 : 0x00; | ||
| 606 | } | ||
| 607 | tmp_fb[i] = p; | ||
| 608 | } | ||
| 609 | memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE); | ||
| 610 | info->fix.visual = FB_VISUAL_MONO01; | ||
| 611 | info->fix.line_length = PICOLCDFB_WIDTH / 8; | ||
| 612 | } else { | ||
| 613 | int i; | ||
| 614 | memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE); | ||
| 615 | for (i = 0; i < PICOLCDFB_SIZE * 8; i++) | ||
| 616 | o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00; | ||
| 617 | info->fix.visual = FB_VISUAL_DIRECTCOLOR; | ||
| 618 | info->fix.line_length = PICOLCDFB_WIDTH; | ||
| 619 | } | ||
| 620 | |||
| 621 | kfree(tmp_fb); | ||
| 622 | data->fb_bpp = info->var.bits_per_pixel; | ||
| 623 | return 0; | ||
| 624 | } | ||
| 625 | |||
| 626 | /* Do refcounting on our FB and cleanup per worker if FB is | ||
| 627 | * closed after unplug of our device | ||
| 628 | * (fb_release holds info->lock and still touches info after | ||
| 629 | * we return so we can't release it immediately. | ||
| 630 | */ | ||
| 631 | struct picolcd_fb_cleanup_item { | ||
| 632 | struct fb_info *info; | ||
| 633 | struct picolcd_fb_cleanup_item *next; | ||
| 634 | }; | ||
| 635 | static struct picolcd_fb_cleanup_item *fb_pending; | ||
| 636 | static DEFINE_SPINLOCK(fb_pending_lock); | ||
| 637 | |||
| 638 | static void picolcd_fb_do_cleanup(struct work_struct *data) | ||
| 639 | { | ||
| 640 | struct picolcd_fb_cleanup_item *item; | ||
| 641 | unsigned long flags; | ||
| 642 | |||
| 643 | do { | ||
| 644 | spin_lock_irqsave(&fb_pending_lock, flags); | ||
| 645 | item = fb_pending; | ||
| 646 | fb_pending = item ? item->next : NULL; | ||
| 647 | spin_unlock_irqrestore(&fb_pending_lock, flags); | ||
| 648 | |||
| 649 | if (item) { | ||
| 650 | u8 *fb = (u8 *)item->info->fix.smem_start; | ||
| 651 | /* make sure we do not race against fb core when | ||
| 652 | * releasing */ | ||
| 653 | mutex_lock(&item->info->lock); | ||
| 654 | mutex_unlock(&item->info->lock); | ||
| 655 | framebuffer_release(item->info); | ||
| 656 | vfree(fb); | ||
| 657 | } | ||
| 658 | } while (item); | ||
| 659 | } | ||
| 660 | |||
| 661 | static DECLARE_WORK(picolcd_fb_cleanup, picolcd_fb_do_cleanup); | ||
| 662 | |||
| 663 | static int picolcd_fb_open(struct fb_info *info, int u) | ||
| 664 | { | ||
| 665 | u32 *ref_cnt = info->pseudo_palette; | ||
| 666 | ref_cnt--; | ||
| 667 | |||
| 668 | (*ref_cnt)++; | ||
| 669 | return 0; | ||
| 670 | } | ||
| 671 | |||
| 672 | static int picolcd_fb_release(struct fb_info *info, int u) | ||
| 673 | { | ||
| 674 | u32 *ref_cnt = info->pseudo_palette; | ||
| 675 | ref_cnt--; | ||
| 676 | |||
| 677 | (*ref_cnt)++; | ||
| 678 | if (!*ref_cnt) { | ||
| 679 | unsigned long flags; | ||
| 680 | struct picolcd_fb_cleanup_item *item = (struct picolcd_fb_cleanup_item *)ref_cnt; | ||
| 681 | item--; | ||
| 682 | spin_lock_irqsave(&fb_pending_lock, flags); | ||
| 683 | item->next = fb_pending; | ||
| 684 | fb_pending = item; | ||
| 685 | spin_unlock_irqrestore(&fb_pending_lock, flags); | ||
| 686 | schedule_work(&picolcd_fb_cleanup); | ||
| 687 | } | ||
| 688 | return 0; | ||
| 689 | } | ||
| 690 | |||
| 691 | /* Note this can't be const because of struct fb_info definition */ | ||
| 692 | static struct fb_ops picolcdfb_ops = { | ||
| 693 | .owner = THIS_MODULE, | ||
| 694 | .fb_destroy = picolcd_fb_destroy, | ||
| 695 | .fb_open = picolcd_fb_open, | ||
| 696 | .fb_release = picolcd_fb_release, | ||
| 697 | .fb_read = fb_sys_read, | ||
| 698 | .fb_write = picolcd_fb_write, | ||
| 699 | .fb_blank = picolcd_fb_blank, | ||
| 700 | .fb_fillrect = picolcd_fb_fillrect, | ||
| 701 | .fb_copyarea = picolcd_fb_copyarea, | ||
| 702 | .fb_imageblit = picolcd_fb_imageblit, | ||
| 703 | .fb_check_var = picolcd_fb_check_var, | ||
| 704 | .fb_set_par = picolcd_set_par, | ||
| 705 | }; | ||
| 706 | |||
| 707 | |||
| 708 | /* Callback from deferred IO workqueue */ | ||
| 709 | static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist) | ||
| 710 | { | ||
| 711 | picolcd_fb_update(info->par); | ||
| 712 | } | ||
| 713 | |||
| 714 | static const struct fb_deferred_io picolcd_fb_defio = { | ||
| 715 | .delay = HZ / PICOLCDFB_UPDATE_RATE_DEFAULT, | ||
| 716 | .deferred_io = picolcd_fb_deferred_io, | ||
| 717 | }; | ||
| 718 | |||
| 719 | |||
| 720 | /* | ||
| 721 | * The "fb_update_rate" sysfs attribute | ||
| 722 | */ | ||
| 723 | static ssize_t picolcd_fb_update_rate_show(struct device *dev, | ||
| 724 | struct device_attribute *attr, char *buf) | ||
| 725 | { | ||
| 726 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
| 727 | unsigned i, fb_update_rate = data->fb_update_rate; | ||
| 728 | size_t ret = 0; | ||
| 729 | |||
| 730 | for (i = 1; i <= PICOLCDFB_UPDATE_RATE_LIMIT; i++) | ||
| 731 | if (ret >= PAGE_SIZE) | ||
| 732 | break; | ||
| 733 | else if (i == fb_update_rate) | ||
| 734 | ret += snprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i); | ||
| 735 | else | ||
| 736 | ret += snprintf(buf+ret, PAGE_SIZE-ret, "%u ", i); | ||
| 737 | if (ret > 0) | ||
| 738 | buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n'; | ||
| 739 | return ret; | ||
| 740 | } | ||
| 741 | |||
| 742 | static ssize_t picolcd_fb_update_rate_store(struct device *dev, | ||
| 743 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 744 | { | ||
| 745 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
| 746 | int i; | ||
| 747 | unsigned u; | ||
| 748 | |||
| 749 | if (count < 1 || count > 10) | ||
| 750 | return -EINVAL; | ||
| 751 | |||
| 752 | i = sscanf(buf, "%u", &u); | ||
| 753 | if (i != 1) | ||
| 754 | return -EINVAL; | ||
| 755 | |||
| 756 | if (u > PICOLCDFB_UPDATE_RATE_LIMIT) | ||
| 757 | return -ERANGE; | ||
| 758 | else if (u == 0) | ||
| 759 | u = PICOLCDFB_UPDATE_RATE_DEFAULT; | ||
| 760 | |||
| 761 | data->fb_update_rate = u; | ||
| 762 | data->fb_defio.delay = HZ / data->fb_update_rate; | ||
| 763 | return count; | ||
| 764 | } | ||
| 765 | |||
| 766 | static DEVICE_ATTR(fb_update_rate, 0666, picolcd_fb_update_rate_show, | ||
| 767 | picolcd_fb_update_rate_store); | ||
| 768 | |||
| 769 | /* initialize Framebuffer device */ | ||
| 770 | static int picolcd_init_framebuffer(struct picolcd_data *data) | ||
| 771 | { | ||
| 772 | struct device *dev = &data->hdev->dev; | ||
| 773 | struct fb_info *info = NULL; | ||
| 774 | int i, error = -ENOMEM; | ||
| 775 | u8 *fb_vbitmap = NULL; | ||
| 776 | u8 *fb_bitmap = NULL; | ||
| 777 | u32 *palette; | ||
| 778 | |||
| 779 | fb_bitmap = vmalloc(PICOLCDFB_SIZE*8); | ||
| 780 | if (fb_bitmap == NULL) { | ||
| 781 | dev_err(dev, "can't get a free page for framebuffer\n"); | ||
| 782 | goto err_nomem; | ||
| 783 | } | ||
| 784 | |||
| 785 | fb_vbitmap = kmalloc(PICOLCDFB_SIZE, GFP_KERNEL); | ||
| 786 | if (fb_vbitmap == NULL) { | ||
| 787 | dev_err(dev, "can't alloc vbitmap image buffer\n"); | ||
| 788 | goto err_nomem; | ||
| 789 | } | ||
| 790 | |||
| 791 | data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT; | ||
| 792 | data->fb_defio = picolcd_fb_defio; | ||
| 793 | /* The extra memory is: | ||
| 794 | * - struct picolcd_fb_cleanup_item | ||
| 795 | * - u32 for ref_count | ||
| 796 | * - 256*u32 for pseudo_palette | ||
| 797 | */ | ||
| 798 | info = framebuffer_alloc(257 * sizeof(u32) + sizeof(struct picolcd_fb_cleanup_item), dev); | ||
| 799 | if (info == NULL) { | ||
| 800 | dev_err(dev, "failed to allocate a framebuffer\n"); | ||
| 801 | goto err_nomem; | ||
| 802 | } | ||
| 803 | |||
| 804 | palette = info->par + sizeof(struct picolcd_fb_cleanup_item); | ||
| 805 | *palette = 1; | ||
| 806 | palette++; | ||
| 807 | for (i = 0; i < 256; i++) | ||
| 808 | palette[i] = i > 0 && i < 16 ? 0xff : 0; | ||
| 809 | info->pseudo_palette = palette; | ||
| 810 | info->fbdefio = &data->fb_defio; | ||
| 811 | info->screen_base = (char __force __iomem *)fb_bitmap; | ||
| 812 | info->fbops = &picolcdfb_ops; | ||
| 813 | info->var = picolcdfb_var; | ||
| 814 | info->fix = picolcdfb_fix; | ||
| 815 | info->fix.smem_len = PICOLCDFB_SIZE*8; | ||
| 816 | info->fix.smem_start = (unsigned long)fb_bitmap; | ||
| 817 | info->par = data; | ||
| 818 | info->flags = FBINFO_FLAG_DEFAULT; | ||
| 819 | |||
| 820 | data->fb_vbitmap = fb_vbitmap; | ||
| 821 | data->fb_bitmap = fb_bitmap; | ||
| 822 | data->fb_bpp = picolcdfb_var.bits_per_pixel; | ||
| 823 | error = picolcd_fb_reset(data, 1); | ||
| 824 | if (error) { | ||
| 825 | dev_err(dev, "failed to configure display\n"); | ||
| 826 | goto err_cleanup; | ||
| 827 | } | ||
| 828 | error = device_create_file(dev, &dev_attr_fb_update_rate); | ||
| 829 | if (error) { | ||
| 830 | dev_err(dev, "failed to create sysfs attributes\n"); | ||
| 831 | goto err_cleanup; | ||
| 832 | } | ||
| 833 | fb_deferred_io_init(info); | ||
| 834 | data->fb_info = info; | ||
| 835 | error = register_framebuffer(info); | ||
| 836 | if (error) { | ||
| 837 | dev_err(dev, "failed to register framebuffer\n"); | ||
| 838 | goto err_sysfs; | ||
| 839 | } | ||
| 840 | /* schedule first output of framebuffer */ | ||
| 841 | data->fb_force = 1; | ||
| 842 | schedule_delayed_work(&info->deferred_work, 0); | ||
| 843 | return 0; | ||
| 844 | |||
| 845 | err_sysfs: | ||
| 846 | fb_deferred_io_cleanup(info); | ||
| 847 | device_remove_file(dev, &dev_attr_fb_update_rate); | ||
| 848 | err_cleanup: | ||
| 849 | data->fb_vbitmap = NULL; | ||
| 850 | data->fb_bitmap = NULL; | ||
| 851 | data->fb_bpp = 0; | ||
| 852 | data->fb_info = NULL; | ||
| 853 | |||
| 854 | err_nomem: | ||
| 855 | framebuffer_release(info); | ||
| 856 | vfree(fb_bitmap); | ||
| 857 | kfree(fb_vbitmap); | ||
| 858 | return error; | ||
| 859 | } | ||
| 860 | |||
| 861 | static void picolcd_exit_framebuffer(struct picolcd_data *data) | ||
| 862 | { | ||
| 863 | struct fb_info *info = data->fb_info; | ||
| 864 | u8 *fb_vbitmap = data->fb_vbitmap; | ||
| 865 | |||
| 866 | if (!info) | ||
| 867 | return; | ||
| 868 | |||
| 869 | info->par = NULL; | ||
| 870 | device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate); | ||
| 871 | unregister_framebuffer(info); | ||
| 872 | data->fb_vbitmap = NULL; | ||
| 873 | data->fb_bitmap = NULL; | ||
| 874 | data->fb_bpp = 0; | ||
| 875 | data->fb_info = NULL; | ||
| 876 | kfree(fb_vbitmap); | ||
| 877 | } | ||
| 878 | |||
| 879 | #define picolcd_fbinfo(d) ((d)->fb_info) | ||
| 880 | #else | ||
| 881 | static inline int picolcd_fb_reset(struct picolcd_data *data, int clear) | ||
| 882 | { | ||
| 883 | return 0; | ||
| 884 | } | ||
| 885 | static inline int picolcd_init_framebuffer(struct picolcd_data *data) | ||
| 886 | { | ||
| 887 | return 0; | ||
| 888 | } | ||
| 889 | static inline void picolcd_exit_framebuffer(struct picolcd_data *data) | ||
| 890 | { | ||
| 891 | } | ||
| 892 | #define picolcd_fbinfo(d) NULL | ||
| 893 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
| 894 | |||
| 895 | #ifdef CONFIG_HID_PICOLCD_BACKLIGHT | ||
| 896 | /* | ||
| 897 | * backlight class device | ||
| 898 | */ | ||
| 899 | static int picolcd_get_brightness(struct backlight_device *bdev) | ||
| 900 | { | ||
| 901 | struct picolcd_data *data = bl_get_data(bdev); | ||
| 902 | return data->lcd_brightness; | ||
| 903 | } | ||
| 904 | |||
| 905 | static int picolcd_set_brightness(struct backlight_device *bdev) | ||
| 906 | { | ||
| 907 | struct picolcd_data *data = bl_get_data(bdev); | ||
| 908 | struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev); | ||
| 909 | unsigned long flags; | ||
| 910 | |||
| 911 | if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) | ||
| 912 | return -ENODEV; | ||
| 913 | |||
| 914 | data->lcd_brightness = bdev->props.brightness & 0x0ff; | ||
| 915 | data->lcd_power = bdev->props.power; | ||
| 916 | spin_lock_irqsave(&data->lock, flags); | ||
| 917 | hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0); | ||
| 918 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
| 919 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 920 | return 0; | ||
| 921 | } | ||
| 922 | |||
| 923 | static int picolcd_check_bl_fb(struct backlight_device *bdev, struct fb_info *fb) | ||
| 924 | { | ||
| 925 | return fb && fb == picolcd_fbinfo((struct picolcd_data *)bl_get_data(bdev)); | ||
| 926 | } | ||
| 927 | |||
| 928 | static const struct backlight_ops picolcd_blops = { | ||
| 929 | .update_status = picolcd_set_brightness, | ||
| 930 | .get_brightness = picolcd_get_brightness, | ||
| 931 | .check_fb = picolcd_check_bl_fb, | ||
| 932 | }; | ||
| 933 | |||
| 934 | static int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report) | ||
| 935 | { | ||
| 936 | struct device *dev = &data->hdev->dev; | ||
| 937 | struct backlight_device *bdev; | ||
| 938 | struct backlight_properties props; | ||
| 939 | if (!report) | ||
| 940 | return -ENODEV; | ||
| 941 | if (report->maxfield != 1 || report->field[0]->report_count != 1 || | ||
| 942 | report->field[0]->report_size != 8) { | ||
| 943 | dev_err(dev, "unsupported BRIGHTNESS report"); | ||
| 944 | return -EINVAL; | ||
| 945 | } | ||
| 946 | |||
| 947 | memset(&props, 0, sizeof(props)); | ||
| 948 | props.type = BACKLIGHT_RAW; | ||
| 949 | props.max_brightness = 0xff; | ||
| 950 | bdev = backlight_device_register(dev_name(dev), dev, data, | ||
| 951 | &picolcd_blops, &props); | ||
| 952 | if (IS_ERR(bdev)) { | ||
| 953 | dev_err(dev, "failed to register backlight\n"); | ||
| 954 | return PTR_ERR(bdev); | ||
| 955 | } | ||
| 956 | bdev->props.brightness = 0xff; | ||
| 957 | data->lcd_brightness = 0xff; | ||
| 958 | data->backlight = bdev; | ||
| 959 | picolcd_set_brightness(bdev); | ||
| 960 | return 0; | ||
| 961 | } | ||
| 962 | |||
| 963 | static void picolcd_exit_backlight(struct picolcd_data *data) | ||
| 964 | { | ||
| 965 | struct backlight_device *bdev = data->backlight; | ||
| 966 | |||
| 967 | data->backlight = NULL; | ||
| 968 | if (bdev) | ||
| 969 | backlight_device_unregister(bdev); | ||
| 970 | } | ||
| 971 | |||
| 972 | static inline int picolcd_resume_backlight(struct picolcd_data *data) | ||
| 973 | { | ||
| 974 | if (!data->backlight) | ||
| 975 | return 0; | ||
| 976 | return picolcd_set_brightness(data->backlight); | ||
| 977 | } | ||
| 978 | |||
| 979 | #ifdef CONFIG_PM | ||
| 980 | static void picolcd_suspend_backlight(struct picolcd_data *data) | ||
| 981 | { | ||
| 982 | int bl_power = data->lcd_power; | ||
| 983 | if (!data->backlight) | ||
| 984 | return; | ||
| 985 | |||
| 986 | data->backlight->props.power = FB_BLANK_POWERDOWN; | ||
| 987 | picolcd_set_brightness(data->backlight); | ||
| 988 | data->lcd_power = data->backlight->props.power = bl_power; | ||
| 989 | } | ||
| 990 | #endif /* CONFIG_PM */ | ||
| 991 | #else | ||
| 992 | static inline int picolcd_init_backlight(struct picolcd_data *data, | ||
| 993 | struct hid_report *report) | ||
| 994 | { | ||
| 995 | return 0; | ||
| 996 | } | ||
| 997 | static inline void picolcd_exit_backlight(struct picolcd_data *data) | ||
| 998 | { | ||
| 999 | } | ||
| 1000 | static inline int picolcd_resume_backlight(struct picolcd_data *data) | ||
| 1001 | { | ||
| 1002 | return 0; | ||
| 1003 | } | ||
| 1004 | static inline void picolcd_suspend_backlight(struct picolcd_data *data) | ||
| 1005 | { | ||
| 1006 | } | ||
| 1007 | #endif /* CONFIG_HID_PICOLCD_BACKLIGHT */ | ||
| 1008 | |||
| 1009 | #ifdef CONFIG_HID_PICOLCD_LCD | ||
| 1010 | /* | ||
| 1011 | * lcd class device | ||
| 1012 | */ | ||
| 1013 | static int picolcd_get_contrast(struct lcd_device *ldev) | ||
| 1014 | { | ||
| 1015 | struct picolcd_data *data = lcd_get_data(ldev); | ||
| 1016 | return data->lcd_contrast; | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | static int picolcd_set_contrast(struct lcd_device *ldev, int contrast) | ||
| 1020 | { | ||
| 1021 | struct picolcd_data *data = lcd_get_data(ldev); | ||
| 1022 | struct hid_report *report = picolcd_out_report(REPORT_CONTRAST, data->hdev); | ||
| 1023 | unsigned long flags; | ||
| 1024 | |||
| 1025 | if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) | ||
| 1026 | return -ENODEV; | ||
| 1027 | |||
| 1028 | data->lcd_contrast = contrast & 0x0ff; | ||
| 1029 | spin_lock_irqsave(&data->lock, flags); | ||
| 1030 | hid_set_field(report->field[0], 0, data->lcd_contrast); | ||
| 1031 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
| 1032 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 1033 | return 0; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb) | ||
| 1037 | { | ||
| 1038 | return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev)); | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | static struct lcd_ops picolcd_lcdops = { | ||
| 1042 | .get_contrast = picolcd_get_contrast, | ||
| 1043 | .set_contrast = picolcd_set_contrast, | ||
| 1044 | .check_fb = picolcd_check_lcd_fb, | ||
| 1045 | }; | ||
| 1046 | |||
| 1047 | static int picolcd_init_lcd(struct picolcd_data *data, struct hid_report *report) | ||
| 1048 | { | ||
| 1049 | struct device *dev = &data->hdev->dev; | ||
| 1050 | struct lcd_device *ldev; | ||
| 1051 | |||
| 1052 | if (!report) | ||
| 1053 | return -ENODEV; | ||
| 1054 | if (report->maxfield != 1 || report->field[0]->report_count != 1 || | ||
| 1055 | report->field[0]->report_size != 8) { | ||
| 1056 | dev_err(dev, "unsupported CONTRAST report"); | ||
| 1057 | return -EINVAL; | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | ldev = lcd_device_register(dev_name(dev), dev, data, &picolcd_lcdops); | ||
| 1061 | if (IS_ERR(ldev)) { | ||
| 1062 | dev_err(dev, "failed to register LCD\n"); | ||
| 1063 | return PTR_ERR(ldev); | ||
| 1064 | } | ||
| 1065 | ldev->props.max_contrast = 0x0ff; | ||
| 1066 | data->lcd_contrast = 0xe5; | ||
| 1067 | data->lcd = ldev; | ||
| 1068 | picolcd_set_contrast(ldev, 0xe5); | ||
| 1069 | return 0; | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | static void picolcd_exit_lcd(struct picolcd_data *data) | ||
| 1073 | { | ||
| 1074 | struct lcd_device *ldev = data->lcd; | ||
| 1075 | |||
| 1076 | data->lcd = NULL; | ||
| 1077 | if (ldev) | ||
| 1078 | lcd_device_unregister(ldev); | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | static inline int picolcd_resume_lcd(struct picolcd_data *data) | ||
| 1082 | { | ||
| 1083 | if (!data->lcd) | ||
| 1084 | return 0; | ||
| 1085 | return picolcd_set_contrast(data->lcd, data->lcd_contrast); | ||
| 1086 | } | ||
| 1087 | #else | ||
| 1088 | static inline int picolcd_init_lcd(struct picolcd_data *data, | ||
| 1089 | struct hid_report *report) | ||
| 1090 | { | ||
| 1091 | return 0; | ||
| 1092 | } | ||
| 1093 | static inline void picolcd_exit_lcd(struct picolcd_data *data) | ||
| 1094 | { | ||
| 1095 | } | ||
| 1096 | static inline int picolcd_resume_lcd(struct picolcd_data *data) | ||
| 1097 | { | ||
| 1098 | return 0; | ||
| 1099 | } | ||
| 1100 | #endif /* CONFIG_HID_PICOLCD_LCD */ | ||
| 1101 | |||
| 1102 | #ifdef CONFIG_HID_PICOLCD_LEDS | ||
| 1103 | /** | ||
| 1104 | * LED class device | ||
| 1105 | */ | ||
| 1106 | static void picolcd_leds_set(struct picolcd_data *data) | ||
| 1107 | { | ||
| 1108 | struct hid_report *report; | ||
| 1109 | unsigned long flags; | ||
| 1110 | |||
| 1111 | if (!data->led[0]) | ||
| 1112 | return; | ||
| 1113 | report = picolcd_out_report(REPORT_LED_STATE, data->hdev); | ||
| 1114 | if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) | ||
| 1115 | return; | ||
| 1116 | |||
| 1117 | spin_lock_irqsave(&data->lock, flags); | ||
| 1118 | hid_set_field(report->field[0], 0, data->led_state); | ||
| 1119 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
| 1120 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | static void picolcd_led_set_brightness(struct led_classdev *led_cdev, | ||
| 1124 | enum led_brightness value) | ||
| 1125 | { | ||
| 1126 | struct device *dev; | ||
| 1127 | struct hid_device *hdev; | ||
| 1128 | struct picolcd_data *data; | ||
| 1129 | int i, state = 0; | ||
| 1130 | |||
| 1131 | dev = led_cdev->dev->parent; | ||
| 1132 | hdev = container_of(dev, struct hid_device, dev); | ||
| 1133 | data = hid_get_drvdata(hdev); | ||
| 1134 | for (i = 0; i < 8; i++) { | ||
| 1135 | if (led_cdev != data->led[i]) | ||
| 1136 | continue; | ||
| 1137 | state = (data->led_state >> i) & 1; | ||
| 1138 | if (value == LED_OFF && state) { | ||
| 1139 | data->led_state &= ~(1 << i); | ||
| 1140 | picolcd_leds_set(data); | ||
| 1141 | } else if (value != LED_OFF && !state) { | ||
| 1142 | data->led_state |= 1 << i; | ||
| 1143 | picolcd_leds_set(data); | ||
| 1144 | } | ||
| 1145 | break; | ||
| 1146 | } | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev) | ||
| 1150 | { | ||
| 1151 | struct device *dev; | ||
| 1152 | struct hid_device *hdev; | ||
| 1153 | struct picolcd_data *data; | ||
| 1154 | int i, value = 0; | ||
| 1155 | |||
| 1156 | dev = led_cdev->dev->parent; | ||
| 1157 | hdev = container_of(dev, struct hid_device, dev); | ||
| 1158 | data = hid_get_drvdata(hdev); | ||
| 1159 | for (i = 0; i < 8; i++) | ||
| 1160 | if (led_cdev == data->led[i]) { | ||
| 1161 | value = (data->led_state >> i) & 1; | ||
| 1162 | break; | ||
| 1163 | } | ||
| 1164 | return value ? LED_FULL : LED_OFF; | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | static int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report) | ||
| 1168 | { | ||
| 1169 | struct device *dev = &data->hdev->dev; | ||
| 1170 | struct led_classdev *led; | ||
| 1171 | size_t name_sz = strlen(dev_name(dev)) + 8; | ||
| 1172 | char *name; | ||
| 1173 | int i, ret = 0; | ||
| 1174 | |||
| 1175 | if (!report) | ||
| 1176 | return -ENODEV; | ||
| 1177 | if (report->maxfield != 1 || report->field[0]->report_count != 1 || | ||
| 1178 | report->field[0]->report_size != 8) { | ||
| 1179 | dev_err(dev, "unsupported LED_STATE report"); | ||
| 1180 | return -EINVAL; | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | for (i = 0; i < 8; i++) { | ||
| 1184 | led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); | ||
| 1185 | if (!led) { | ||
| 1186 | dev_err(dev, "can't allocate memory for LED %d\n", i); | ||
| 1187 | ret = -ENOMEM; | ||
| 1188 | goto err; | ||
| 1189 | } | ||
| 1190 | name = (void *)(&led[1]); | ||
| 1191 | snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i); | ||
| 1192 | led->name = name; | ||
| 1193 | led->brightness = 0; | ||
| 1194 | led->max_brightness = 1; | ||
| 1195 | led->brightness_get = picolcd_led_get_brightness; | ||
| 1196 | led->brightness_set = picolcd_led_set_brightness; | ||
| 1197 | |||
| 1198 | data->led[i] = led; | ||
| 1199 | ret = led_classdev_register(dev, data->led[i]); | ||
| 1200 | if (ret) { | ||
| 1201 | data->led[i] = NULL; | ||
| 1202 | kfree(led); | ||
| 1203 | dev_err(dev, "can't register LED %d\n", i); | ||
| 1204 | goto err; | ||
| 1205 | } | ||
| 1206 | } | ||
| 1207 | return 0; | ||
| 1208 | err: | ||
| 1209 | for (i = 0; i < 8; i++) | ||
| 1210 | if (data->led[i]) { | ||
| 1211 | led = data->led[i]; | ||
| 1212 | data->led[i] = NULL; | ||
| 1213 | led_classdev_unregister(led); | ||
| 1214 | kfree(led); | ||
| 1215 | } | ||
| 1216 | return ret; | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | static void picolcd_exit_leds(struct picolcd_data *data) | ||
| 1220 | { | ||
| 1221 | struct led_classdev *led; | ||
| 1222 | int i; | ||
| 1223 | |||
| 1224 | for (i = 0; i < 8; i++) { | ||
| 1225 | led = data->led[i]; | ||
| 1226 | data->led[i] = NULL; | ||
| 1227 | if (!led) | ||
| 1228 | continue; | ||
| 1229 | led_classdev_unregister(led); | ||
| 1230 | kfree(led); | ||
| 1231 | } | ||
| 1232 | } | ||
| 1233 | |||
| 1234 | #else | ||
| 1235 | static inline int picolcd_init_leds(struct picolcd_data *data, | ||
| 1236 | struct hid_report *report) | ||
| 1237 | { | ||
| 1238 | return 0; | ||
| 1239 | } | ||
| 1240 | static inline void picolcd_exit_leds(struct picolcd_data *data) | ||
| 1241 | { | ||
| 1242 | } | ||
| 1243 | static inline int picolcd_leds_set(struct picolcd_data *data) | ||
| 1244 | { | ||
| 1245 | return 0; | ||
| 1246 | } | ||
| 1247 | #endif /* CONFIG_HID_PICOLCD_LEDS */ | ||
| 1248 | |||
| 1249 | /* | ||
| 1250 | * input class device | ||
| 1251 | */ | ||
| 1252 | static int picolcd_raw_keypad(struct picolcd_data *data, | ||
| 1253 | struct hid_report *report, u8 *raw_data, int size) | ||
| 1254 | { | ||
| 1255 | /* | ||
| 1256 | * Keypad event | ||
| 1257 | * First and second data bytes list currently pressed keys, | ||
| 1258 | * 0x00 means no key and at most 2 keys may be pressed at same time | ||
| 1259 | */ | ||
| 1260 | int i, j; | ||
| 1261 | |||
| 1262 | /* determine newly pressed keys */ | ||
| 1263 | for (i = 0; i < size; i++) { | ||
| 1264 | unsigned int key_code; | ||
| 1265 | if (raw_data[i] == 0) | ||
| 1266 | continue; | ||
| 1267 | for (j = 0; j < sizeof(data->pressed_keys); j++) | ||
| 1268 | if (data->pressed_keys[j] == raw_data[i]) | ||
| 1269 | goto key_already_down; | ||
| 1270 | for (j = 0; j < sizeof(data->pressed_keys); j++) | ||
| 1271 | if (data->pressed_keys[j] == 0) { | ||
| 1272 | data->pressed_keys[j] = raw_data[i]; | ||
| 1273 | break; | ||
| 1274 | } | ||
| 1275 | input_event(data->input_keys, EV_MSC, MSC_SCAN, raw_data[i]); | ||
| 1276 | if (raw_data[i] < PICOLCD_KEYS) | ||
| 1277 | key_code = data->keycode[raw_data[i]]; | ||
| 1278 | else | ||
| 1279 | key_code = KEY_UNKNOWN; | ||
| 1280 | if (key_code != KEY_UNKNOWN) { | ||
| 1281 | dbg_hid(PICOLCD_NAME " got key press for %u:%d", | ||
| 1282 | raw_data[i], key_code); | ||
| 1283 | input_report_key(data->input_keys, key_code, 1); | ||
| 1284 | } | ||
| 1285 | input_sync(data->input_keys); | ||
| 1286 | key_already_down: | ||
| 1287 | continue; | ||
| 1288 | } | ||
| 1289 | |||
| 1290 | /* determine newly released keys */ | ||
| 1291 | for (j = 0; j < sizeof(data->pressed_keys); j++) { | ||
| 1292 | unsigned int key_code; | ||
| 1293 | if (data->pressed_keys[j] == 0) | ||
| 1294 | continue; | ||
| 1295 | for (i = 0; i < size; i++) | ||
| 1296 | if (data->pressed_keys[j] == raw_data[i]) | ||
| 1297 | goto key_still_down; | ||
| 1298 | input_event(data->input_keys, EV_MSC, MSC_SCAN, data->pressed_keys[j]); | ||
| 1299 | if (data->pressed_keys[j] < PICOLCD_KEYS) | ||
| 1300 | key_code = data->keycode[data->pressed_keys[j]]; | ||
| 1301 | else | ||
| 1302 | key_code = KEY_UNKNOWN; | ||
| 1303 | if (key_code != KEY_UNKNOWN) { | ||
| 1304 | dbg_hid(PICOLCD_NAME " got key release for %u:%d", | ||
| 1305 | data->pressed_keys[j], key_code); | ||
| 1306 | input_report_key(data->input_keys, key_code, 0); | ||
| 1307 | } | ||
| 1308 | input_sync(data->input_keys); | ||
| 1309 | data->pressed_keys[j] = 0; | ||
| 1310 | key_still_down: | ||
| 1311 | continue; | ||
| 1312 | } | ||
| 1313 | return 1; | ||
| 1314 | } | ||
| 1315 | |||
| 1316 | static int picolcd_raw_cir(struct picolcd_data *data, | ||
| 1317 | struct hid_report *report, u8 *raw_data, int size) | ||
| 1318 | { | ||
| 1319 | /* Need understanding of CIR data format to implement ... */ | ||
| 1320 | return 1; | ||
| 1321 | } | ||
| 1322 | |||
| 1323 | static int picolcd_check_version(struct hid_device *hdev) | ||
| 1324 | { | ||
| 1325 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
| 1326 | struct picolcd_pending *verinfo; | ||
| 1327 | int ret = 0; | ||
| 1328 | |||
| 1329 | if (!data) | ||
| 1330 | return -ENODEV; | ||
| 1331 | |||
| 1332 | verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0); | ||
| 1333 | if (!verinfo) { | ||
| 1334 | hid_err(hdev, "no version response from PicoLCD\n"); | ||
| 1335 | return -ENODEV; | ||
| 1336 | } | ||
| 1337 | |||
| 1338 | if (verinfo->raw_size == 2) { | ||
| 1339 | data->version[0] = verinfo->raw_data[1]; | ||
| 1340 | data->version[1] = verinfo->raw_data[0]; | ||
| 1341 | if (data->status & PICOLCD_BOOTLOADER) { | ||
| 1342 | hid_info(hdev, "PicoLCD, bootloader version %d.%d\n", | ||
| 1343 | verinfo->raw_data[1], verinfo->raw_data[0]); | ||
| 1344 | } else { | ||
| 1345 | hid_info(hdev, "PicoLCD, firmware version %d.%d\n", | ||
| 1346 | verinfo->raw_data[1], verinfo->raw_data[0]); | ||
| 1347 | } | ||
| 1348 | } else { | ||
| 1349 | hid_err(hdev, "confused, got unexpected version response from PicoLCD\n"); | ||
| 1350 | ret = -EINVAL; | ||
| 1351 | } | ||
| 1352 | kfree(verinfo); | ||
| 1353 | return ret; | ||
| 1354 | } | ||
| 1355 | |||
| 1356 | /* | ||
| 1357 | * Reset our device and wait for answer to VERSION request | ||
| 1358 | */ | ||
| 1359 | static int picolcd_reset(struct hid_device *hdev) | ||
| 1360 | { | ||
| 1361 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
| 1362 | struct hid_report *report = picolcd_out_report(REPORT_RESET, hdev); | ||
| 1363 | unsigned long flags; | ||
| 1364 | int error; | ||
| 1365 | |||
| 1366 | if (!data || !report || report->maxfield != 1) | ||
| 1367 | return -ENODEV; | ||
| 1368 | |||
| 1369 | spin_lock_irqsave(&data->lock, flags); | ||
| 1370 | if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER) | ||
| 1371 | data->status |= PICOLCD_BOOTLOADER; | ||
| 1372 | |||
| 1373 | /* perform the reset */ | ||
| 1374 | hid_set_field(report->field[0], 0, 1); | ||
| 1375 | usbhid_submit_report(hdev, report, USB_DIR_OUT); | ||
| 1376 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 1377 | |||
| 1378 | error = picolcd_check_version(hdev); | ||
| 1379 | if (error) | ||
| 1380 | return error; | ||
| 1381 | |||
| 1382 | picolcd_resume_lcd(data); | ||
| 1383 | picolcd_resume_backlight(data); | ||
| 1384 | #ifdef CONFIG_HID_PICOLCD_FB | ||
| 1385 | if (data->fb_info) | ||
| 1386 | schedule_delayed_work(&data->fb_info->deferred_work, 0); | ||
| 1387 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
| 1388 | |||
| 1389 | picolcd_leds_set(data); | ||
| 1390 | return 0; | ||
| 1391 | } | ||
| 1392 | |||
| 1393 | /* | ||
| 1394 | * The "operation_mode" sysfs attribute | ||
| 1395 | */ | ||
| 1396 | static ssize_t picolcd_operation_mode_show(struct device *dev, | ||
| 1397 | struct device_attribute *attr, char *buf) | ||
| 1398 | { | ||
| 1399 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
| 1400 | |||
| 1401 | if (data->status & PICOLCD_BOOTLOADER) | ||
| 1402 | return snprintf(buf, PAGE_SIZE, "[bootloader] lcd\n"); | ||
| 1403 | else | ||
| 1404 | return snprintf(buf, PAGE_SIZE, "bootloader [lcd]\n"); | ||
| 1405 | } | ||
| 1406 | |||
| 1407 | static ssize_t picolcd_operation_mode_store(struct device *dev, | ||
| 1408 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 1409 | { | ||
| 1410 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
| 1411 | struct hid_report *report = NULL; | ||
| 1412 | size_t cnt = count; | ||
| 1413 | int timeout = data->opmode_delay; | ||
| 1414 | unsigned long flags; | ||
| 1415 | |||
| 1416 | if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) { | ||
| 1417 | if (data->status & PICOLCD_BOOTLOADER) | ||
| 1418 | report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev); | ||
| 1419 | buf += 3; | ||
| 1420 | cnt -= 3; | ||
| 1421 | } else if (cnt >= 10 && strncmp("bootloader", buf, 10) == 0) { | ||
| 1422 | if (!(data->status & PICOLCD_BOOTLOADER)) | ||
| 1423 | report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev); | ||
| 1424 | buf += 10; | ||
| 1425 | cnt -= 10; | ||
| 1426 | } | ||
| 1427 | if (!report) | ||
| 1428 | return -EINVAL; | ||
| 1429 | |||
| 1430 | while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r')) | ||
| 1431 | cnt--; | ||
| 1432 | if (cnt != 0) | ||
| 1433 | return -EINVAL; | ||
| 1434 | |||
| 1435 | spin_lock_irqsave(&data->lock, flags); | ||
| 1436 | hid_set_field(report->field[0], 0, timeout & 0xff); | ||
| 1437 | hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff); | ||
| 1438 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
| 1439 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 1440 | return count; | ||
| 1441 | } | ||
| 1442 | |||
| 1443 | static DEVICE_ATTR(operation_mode, 0644, picolcd_operation_mode_show, | ||
| 1444 | picolcd_operation_mode_store); | ||
| 1445 | |||
| 1446 | /* | ||
| 1447 | * The "operation_mode_delay" sysfs attribute | ||
| 1448 | */ | ||
| 1449 | static ssize_t picolcd_operation_mode_delay_show(struct device *dev, | ||
| 1450 | struct device_attribute *attr, char *buf) | ||
| 1451 | { | ||
| 1452 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
| 1453 | |||
| 1454 | return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay); | ||
| 1455 | } | ||
| 1456 | |||
| 1457 | static ssize_t picolcd_operation_mode_delay_store(struct device *dev, | ||
| 1458 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 1459 | { | ||
| 1460 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
| 1461 | unsigned u; | ||
| 1462 | if (sscanf(buf, "%u", &u) != 1) | ||
| 1463 | return -EINVAL; | ||
| 1464 | if (u > 30000) | ||
| 1465 | return -EINVAL; | ||
| 1466 | else | ||
| 1467 | data->opmode_delay = u; | ||
| 1468 | return count; | ||
| 1469 | } | ||
| 1470 | |||
| 1471 | static DEVICE_ATTR(operation_mode_delay, 0644, picolcd_operation_mode_delay_show, | ||
| 1472 | picolcd_operation_mode_delay_store); | ||
| 1473 | |||
| 1474 | |||
| 1475 | #ifdef CONFIG_DEBUG_FS | ||
| 1476 | /* | ||
| 1477 | * The "reset" file | ||
| 1478 | */ | ||
| 1479 | static int picolcd_debug_reset_show(struct seq_file *f, void *p) | ||
| 1480 | { | ||
| 1481 | if (picolcd_fbinfo((struct picolcd_data *)f->private)) | ||
| 1482 | seq_printf(f, "all fb\n"); | ||
| 1483 | else | ||
| 1484 | seq_printf(f, "all\n"); | ||
| 1485 | return 0; | ||
| 1486 | } | ||
| 1487 | |||
| 1488 | static int picolcd_debug_reset_open(struct inode *inode, struct file *f) | ||
| 1489 | { | ||
| 1490 | return single_open(f, picolcd_debug_reset_show, inode->i_private); | ||
| 1491 | } | ||
| 1492 | |||
| 1493 | static ssize_t picolcd_debug_reset_write(struct file *f, const char __user *user_buf, | ||
| 1494 | size_t count, loff_t *ppos) | ||
| 1495 | { | ||
| 1496 | struct picolcd_data *data = ((struct seq_file *)f->private_data)->private; | ||
| 1497 | char buf[32]; | ||
| 1498 | size_t cnt = min(count, sizeof(buf)-1); | ||
| 1499 | if (copy_from_user(buf, user_buf, cnt)) | ||
| 1500 | return -EFAULT; | ||
| 1501 | |||
| 1502 | while (cnt > 0 && (buf[cnt-1] == ' ' || buf[cnt-1] == '\n')) | ||
| 1503 | cnt--; | ||
| 1504 | buf[cnt] = '\0'; | ||
| 1505 | if (strcmp(buf, "all") == 0) { | ||
| 1506 | picolcd_reset(data->hdev); | ||
| 1507 | picolcd_fb_reset(data, 1); | ||
| 1508 | } else if (strcmp(buf, "fb") == 0) { | ||
| 1509 | picolcd_fb_reset(data, 1); | ||
| 1510 | } else { | ||
| 1511 | return -EINVAL; | ||
| 1512 | } | ||
| 1513 | return count; | ||
| 1514 | } | ||
| 1515 | |||
| 1516 | static const struct file_operations picolcd_debug_reset_fops = { | ||
| 1517 | .owner = THIS_MODULE, | ||
| 1518 | .open = picolcd_debug_reset_open, | ||
| 1519 | .read = seq_read, | ||
| 1520 | .llseek = seq_lseek, | ||
| 1521 | .write = picolcd_debug_reset_write, | ||
| 1522 | .release = single_release, | ||
| 1523 | }; | ||
| 1524 | |||
| 1525 | /* | ||
| 1526 | * The "eeprom" file | ||
| 1527 | */ | ||
| 1528 | static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u, | ||
| 1529 | size_t s, loff_t *off) | ||
| 1530 | { | ||
| 1531 | struct picolcd_data *data = f->private_data; | ||
| 1532 | struct picolcd_pending *resp; | ||
| 1533 | u8 raw_data[3]; | ||
| 1534 | ssize_t ret = -EIO; | ||
| 1535 | |||
| 1536 | if (s == 0) | ||
| 1537 | return -EINVAL; | ||
| 1538 | if (*off > 0x0ff) | ||
| 1539 | return 0; | ||
| 1540 | |||
| 1541 | /* prepare buffer with info about what we want to read (addr & len) */ | ||
| 1542 | raw_data[0] = *off & 0xff; | ||
| 1543 | raw_data[1] = (*off >> 8) & 0xff; | ||
| 1544 | raw_data[2] = s < 20 ? s : 20; | ||
| 1545 | if (*off + raw_data[2] > 0xff) | ||
| 1546 | raw_data[2] = 0x100 - *off; | ||
| 1547 | resp = picolcd_send_and_wait(data->hdev, REPORT_EE_READ, raw_data, | ||
| 1548 | sizeof(raw_data)); | ||
| 1549 | if (!resp) | ||
| 1550 | return -EIO; | ||
| 1551 | |||
| 1552 | if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) { | ||
| 1553 | /* successful read :) */ | ||
| 1554 | ret = resp->raw_data[2]; | ||
| 1555 | if (ret > s) | ||
| 1556 | ret = s; | ||
| 1557 | if (copy_to_user(u, resp->raw_data+3, ret)) | ||
| 1558 | ret = -EFAULT; | ||
| 1559 | else | ||
| 1560 | *off += ret; | ||
| 1561 | } /* anything else is some kind of IO error */ | ||
| 1562 | |||
| 1563 | kfree(resp); | ||
| 1564 | return ret; | ||
| 1565 | } | ||
| 1566 | |||
| 1567 | static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u, | ||
| 1568 | size_t s, loff_t *off) | ||
| 1569 | { | ||
| 1570 | struct picolcd_data *data = f->private_data; | ||
| 1571 | struct picolcd_pending *resp; | ||
| 1572 | ssize_t ret = -EIO; | ||
| 1573 | u8 raw_data[23]; | ||
| 1574 | |||
| 1575 | if (s == 0) | ||
| 1576 | return -EINVAL; | ||
| 1577 | if (*off > 0x0ff) | ||
| 1578 | return -ENOSPC; | ||
| 1579 | |||
| 1580 | memset(raw_data, 0, sizeof(raw_data)); | ||
| 1581 | raw_data[0] = *off & 0xff; | ||
| 1582 | raw_data[1] = (*off >> 8) & 0xff; | ||
| 1583 | raw_data[2] = min((size_t)20, s); | ||
| 1584 | if (*off + raw_data[2] > 0xff) | ||
| 1585 | raw_data[2] = 0x100 - *off; | ||
| 1586 | |||
| 1587 | if (copy_from_user(raw_data+3, u, min((u8)20, raw_data[2]))) | ||
| 1588 | return -EFAULT; | ||
| 1589 | resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data, | ||
| 1590 | sizeof(raw_data)); | ||
| 1591 | |||
| 1592 | if (!resp) | ||
| 1593 | return -EIO; | ||
| 1594 | |||
| 1595 | if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) { | ||
| 1596 | /* check if written data matches */ | ||
| 1597 | if (memcmp(raw_data, resp->raw_data, 3+raw_data[2]) == 0) { | ||
| 1598 | *off += raw_data[2]; | ||
| 1599 | ret = raw_data[2]; | ||
| 1600 | } | ||
| 1601 | } | ||
| 1602 | kfree(resp); | ||
| 1603 | return ret; | ||
| 1604 | } | ||
| 1605 | |||
| 1606 | /* | ||
| 1607 | * Notes: | ||
| 1608 | * - read/write happens in chunks of at most 20 bytes, it's up to userspace | ||
| 1609 | * to loop in order to get more data. | ||
| 1610 | * - on write errors on otherwise correct write request the bytes | ||
| 1611 | * that should have been written are in undefined state. | ||
| 1612 | */ | ||
| 1613 | static const struct file_operations picolcd_debug_eeprom_fops = { | ||
| 1614 | .owner = THIS_MODULE, | ||
| 1615 | .open = simple_open, | ||
| 1616 | .read = picolcd_debug_eeprom_read, | ||
| 1617 | .write = picolcd_debug_eeprom_write, | ||
| 1618 | .llseek = generic_file_llseek, | ||
| 1619 | }; | ||
| 1620 | |||
| 1621 | /* | ||
| 1622 | * The "flash" file | ||
| 1623 | */ | ||
| 1624 | /* record a flash address to buf (bounds check to be done by caller) */ | ||
| 1625 | static int _picolcd_flash_setaddr(struct picolcd_data *data, u8 *buf, long off) | ||
| 1626 | { | ||
| 1627 | buf[0] = off & 0xff; | ||
| 1628 | buf[1] = (off >> 8) & 0xff; | ||
| 1629 | if (data->addr_sz == 3) | ||
| 1630 | buf[2] = (off >> 16) & 0xff; | ||
| 1631 | return data->addr_sz == 2 ? 2 : 3; | ||
| 1632 | } | ||
| 1633 | |||
| 1634 | /* read a given size of data (bounds check to be done by caller) */ | ||
| 1635 | static ssize_t _picolcd_flash_read(struct picolcd_data *data, int report_id, | ||
| 1636 | char __user *u, size_t s, loff_t *off) | ||
| 1637 | { | ||
| 1638 | struct picolcd_pending *resp; | ||
| 1639 | u8 raw_data[4]; | ||
| 1640 | ssize_t ret = 0; | ||
| 1641 | int len_off, err = -EIO; | ||
| 1642 | |||
| 1643 | while (s > 0) { | ||
| 1644 | err = -EIO; | ||
| 1645 | len_off = _picolcd_flash_setaddr(data, raw_data, *off); | ||
| 1646 | raw_data[len_off] = s > 32 ? 32 : s; | ||
| 1647 | resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off+1); | ||
| 1648 | if (!resp || !resp->in_report) | ||
| 1649 | goto skip; | ||
| 1650 | if (resp->in_report->id == REPORT_MEMORY || | ||
| 1651 | resp->in_report->id == REPORT_BL_READ_MEMORY) { | ||
| 1652 | if (memcmp(raw_data, resp->raw_data, len_off+1) != 0) | ||
| 1653 | goto skip; | ||
| 1654 | if (copy_to_user(u+ret, resp->raw_data+len_off+1, raw_data[len_off])) { | ||
| 1655 | err = -EFAULT; | ||
| 1656 | goto skip; | ||
| 1657 | } | ||
| 1658 | *off += raw_data[len_off]; | ||
| 1659 | s -= raw_data[len_off]; | ||
| 1660 | ret += raw_data[len_off]; | ||
| 1661 | err = 0; | ||
| 1662 | } | ||
| 1663 | skip: | ||
| 1664 | kfree(resp); | ||
| 1665 | if (err) | ||
| 1666 | return ret > 0 ? ret : err; | ||
| 1667 | } | ||
| 1668 | return ret; | ||
| 1669 | } | ||
| 1670 | |||
| 1671 | static ssize_t picolcd_debug_flash_read(struct file *f, char __user *u, | ||
| 1672 | size_t s, loff_t *off) | ||
| 1673 | { | ||
| 1674 | struct picolcd_data *data = f->private_data; | ||
| 1675 | |||
| 1676 | if (s == 0) | ||
| 1677 | return -EINVAL; | ||
| 1678 | if (*off > 0x05fff) | ||
| 1679 | return 0; | ||
| 1680 | if (*off + s > 0x05fff) | ||
| 1681 | s = 0x06000 - *off; | ||
| 1682 | |||
| 1683 | if (data->status & PICOLCD_BOOTLOADER) | ||
| 1684 | return _picolcd_flash_read(data, REPORT_BL_READ_MEMORY, u, s, off); | ||
| 1685 | else | ||
| 1686 | return _picolcd_flash_read(data, REPORT_READ_MEMORY, u, s, off); | ||
| 1687 | } | ||
| 1688 | |||
| 1689 | /* erase block aligned to 64bytes boundary */ | ||
| 1690 | static ssize_t _picolcd_flash_erase64(struct picolcd_data *data, int report_id, | ||
| 1691 | loff_t *off) | ||
| 1692 | { | ||
| 1693 | struct picolcd_pending *resp; | ||
| 1694 | u8 raw_data[3]; | ||
| 1695 | int len_off; | ||
| 1696 | ssize_t ret = -EIO; | ||
| 1697 | |||
| 1698 | if (*off & 0x3f) | ||
| 1699 | return -EINVAL; | ||
| 1700 | |||
| 1701 | len_off = _picolcd_flash_setaddr(data, raw_data, *off); | ||
| 1702 | resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off); | ||
| 1703 | if (!resp || !resp->in_report) | ||
| 1704 | goto skip; | ||
| 1705 | if (resp->in_report->id == REPORT_MEMORY || | ||
| 1706 | resp->in_report->id == REPORT_BL_ERASE_MEMORY) { | ||
| 1707 | if (memcmp(raw_data, resp->raw_data, len_off) != 0) | ||
| 1708 | goto skip; | ||
| 1709 | ret = 0; | ||
| 1710 | } | ||
| 1711 | skip: | ||
| 1712 | kfree(resp); | ||
| 1713 | return ret; | ||
| 1714 | } | ||
| 1715 | |||
| 1716 | /* write a given size of data (bounds check to be done by caller) */ | ||
| 1717 | static ssize_t _picolcd_flash_write(struct picolcd_data *data, int report_id, | ||
| 1718 | const char __user *u, size_t s, loff_t *off) | ||
| 1719 | { | ||
| 1720 | struct picolcd_pending *resp; | ||
| 1721 | u8 raw_data[36]; | ||
| 1722 | ssize_t ret = 0; | ||
| 1723 | int len_off, err = -EIO; | ||
| 1724 | |||
| 1725 | while (s > 0) { | ||
| 1726 | err = -EIO; | ||
| 1727 | len_off = _picolcd_flash_setaddr(data, raw_data, *off); | ||
| 1728 | raw_data[len_off] = s > 32 ? 32 : s; | ||
| 1729 | if (copy_from_user(raw_data+len_off+1, u, raw_data[len_off])) { | ||
| 1730 | err = -EFAULT; | ||
| 1731 | break; | ||
| 1732 | } | ||
| 1733 | resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, | ||
| 1734 | len_off+1+raw_data[len_off]); | ||
| 1735 | if (!resp || !resp->in_report) | ||
| 1736 | goto skip; | ||
| 1737 | if (resp->in_report->id == REPORT_MEMORY || | ||
| 1738 | resp->in_report->id == REPORT_BL_WRITE_MEMORY) { | ||
| 1739 | if (memcmp(raw_data, resp->raw_data, len_off+1+raw_data[len_off]) != 0) | ||
| 1740 | goto skip; | ||
| 1741 | *off += raw_data[len_off]; | ||
| 1742 | s -= raw_data[len_off]; | ||
| 1743 | ret += raw_data[len_off]; | ||
| 1744 | err = 0; | ||
| 1745 | } | ||
| 1746 | skip: | ||
| 1747 | kfree(resp); | ||
| 1748 | if (err) | ||
| 1749 | break; | ||
| 1750 | } | ||
| 1751 | return ret > 0 ? ret : err; | ||
| 1752 | } | ||
| 1753 | |||
| 1754 | static ssize_t picolcd_debug_flash_write(struct file *f, const char __user *u, | ||
| 1755 | size_t s, loff_t *off) | ||
| 1756 | { | ||
| 1757 | struct picolcd_data *data = f->private_data; | ||
| 1758 | ssize_t err, ret = 0; | ||
| 1759 | int report_erase, report_write; | ||
| 1760 | |||
| 1761 | if (s == 0) | ||
| 1762 | return -EINVAL; | ||
| 1763 | if (*off > 0x5fff) | ||
| 1764 | return -ENOSPC; | ||
| 1765 | if (s & 0x3f) | ||
| 1766 | return -EINVAL; | ||
| 1767 | if (*off & 0x3f) | ||
| 1768 | return -EINVAL; | ||
| 1769 | |||
| 1770 | if (data->status & PICOLCD_BOOTLOADER) { | ||
| 1771 | report_erase = REPORT_BL_ERASE_MEMORY; | ||
| 1772 | report_write = REPORT_BL_WRITE_MEMORY; | ||
| 1773 | } else { | ||
| 1774 | report_erase = REPORT_ERASE_MEMORY; | ||
| 1775 | report_write = REPORT_WRITE_MEMORY; | ||
| 1776 | } | ||
| 1777 | mutex_lock(&data->mutex_flash); | ||
| 1778 | while (s > 0) { | ||
| 1779 | err = _picolcd_flash_erase64(data, report_erase, off); | ||
| 1780 | if (err) | ||
| 1781 | break; | ||
| 1782 | err = _picolcd_flash_write(data, report_write, u, 64, off); | ||
| 1783 | if (err < 0) | ||
| 1784 | break; | ||
| 1785 | ret += err; | ||
| 1786 | *off += err; | ||
| 1787 | s -= err; | ||
| 1788 | if (err != 64) | ||
| 1789 | break; | ||
| 1790 | } | ||
| 1791 | mutex_unlock(&data->mutex_flash); | ||
| 1792 | return ret > 0 ? ret : err; | ||
| 1793 | } | ||
| 1794 | |||
| 1795 | /* | ||
| 1796 | * Notes: | ||
| 1797 | * - concurrent writing is prevented by mutex and all writes must be | ||
| 1798 | * n*64 bytes and 64-byte aligned, each write being preceded by an | ||
| 1799 | * ERASE which erases a 64byte block. | ||
| 1800 | * If less than requested was written or an error is returned for an | ||
| 1801 | * otherwise correct write request the next 64-byte block which should | ||
| 1802 | * have been written is in undefined state (mostly: original, erased, | ||
| 1803 | * (half-)written with write error) | ||
| 1804 | * - reading can happen without special restriction | ||
| 1805 | */ | ||
| 1806 | static const struct file_operations picolcd_debug_flash_fops = { | ||
| 1807 | .owner = THIS_MODULE, | ||
| 1808 | .open = simple_open, | ||
| 1809 | .read = picolcd_debug_flash_read, | ||
| 1810 | .write = picolcd_debug_flash_write, | ||
| 1811 | .llseek = generic_file_llseek, | ||
| 1812 | }; | ||
| 1813 | |||
| 1814 | |||
| 1815 | /* | ||
| 1816 | * Helper code for HID report level dumping/debugging | ||
| 1817 | */ | ||
| 1818 | static const char *error_codes[] = { | ||
| 1819 | "success", "parameter missing", "data_missing", "block readonly", | ||
| 1820 | "block not erasable", "block too big", "section overflow", | ||
| 1821 | "invalid command length", "invalid data length", | ||
| 1822 | }; | ||
| 1823 | |||
| 1824 | static void dump_buff_as_hex(char *dst, size_t dst_sz, const u8 *data, | ||
| 1825 | const size_t data_len) | ||
| 1826 | { | ||
| 1827 | int i, j; | ||
| 1828 | for (i = j = 0; i < data_len && j + 3 < dst_sz; i++) { | ||
| 1829 | dst[j++] = hex_asc[(data[i] >> 4) & 0x0f]; | ||
| 1830 | dst[j++] = hex_asc[data[i] & 0x0f]; | ||
| 1831 | dst[j++] = ' '; | ||
| 1832 | } | ||
| 1833 | if (j < dst_sz) { | ||
| 1834 | dst[j--] = '\0'; | ||
| 1835 | dst[j] = '\n'; | ||
| 1836 | } else | ||
| 1837 | dst[j] = '\0'; | ||
| 1838 | } | ||
| 1839 | |||
| 1840 | static void picolcd_debug_out_report(struct picolcd_data *data, | ||
| 1841 | struct hid_device *hdev, struct hid_report *report) | ||
| 1842 | { | ||
| 1843 | u8 raw_data[70]; | ||
| 1844 | int raw_size = (report->size >> 3) + 1; | ||
| 1845 | char *buff; | ||
| 1846 | #define BUFF_SZ 256 | ||
| 1847 | |||
| 1848 | /* Avoid unnecessary overhead if debugfs is disabled */ | ||
| 1849 | if (list_empty(&hdev->debug_list)) | ||
| 1850 | return; | ||
| 1851 | |||
| 1852 | buff = kmalloc(BUFF_SZ, GFP_ATOMIC); | ||
| 1853 | if (!buff) | ||
| 1854 | return; | ||
| 1855 | |||
| 1856 | snprintf(buff, BUFF_SZ, "\nout report %d (size %d) = ", | ||
| 1857 | report->id, raw_size); | ||
| 1858 | hid_debug_event(hdev, buff); | ||
| 1859 | if (raw_size + 5 > sizeof(raw_data)) { | ||
| 1860 | kfree(buff); | ||
| 1861 | hid_debug_event(hdev, " TOO BIG\n"); | ||
| 1862 | return; | ||
| 1863 | } else { | ||
| 1864 | raw_data[0] = report->id; | ||
| 1865 | hid_output_report(report, raw_data); | ||
| 1866 | dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size); | ||
| 1867 | hid_debug_event(hdev, buff); | ||
| 1868 | } | ||
| 1869 | |||
| 1870 | switch (report->id) { | ||
| 1871 | case REPORT_LED_STATE: | ||
| 1872 | /* 1 data byte with GPO state */ | ||
| 1873 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 1874 | "REPORT_LED_STATE", report->id, raw_size-1); | ||
| 1875 | hid_debug_event(hdev, buff); | ||
| 1876 | snprintf(buff, BUFF_SZ, "\tGPO state: 0x%02x\n", raw_data[1]); | ||
| 1877 | hid_debug_event(hdev, buff); | ||
| 1878 | break; | ||
| 1879 | case REPORT_BRIGHTNESS: | ||
| 1880 | /* 1 data byte with brightness */ | ||
| 1881 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 1882 | "REPORT_BRIGHTNESS", report->id, raw_size-1); | ||
| 1883 | hid_debug_event(hdev, buff); | ||
| 1884 | snprintf(buff, BUFF_SZ, "\tBrightness: 0x%02x\n", raw_data[1]); | ||
| 1885 | hid_debug_event(hdev, buff); | ||
| 1886 | break; | ||
| 1887 | case REPORT_CONTRAST: | ||
| 1888 | /* 1 data byte with contrast */ | ||
| 1889 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 1890 | "REPORT_CONTRAST", report->id, raw_size-1); | ||
| 1891 | hid_debug_event(hdev, buff); | ||
| 1892 | snprintf(buff, BUFF_SZ, "\tContrast: 0x%02x\n", raw_data[1]); | ||
| 1893 | hid_debug_event(hdev, buff); | ||
| 1894 | break; | ||
| 1895 | case REPORT_RESET: | ||
| 1896 | /* 2 data bytes with reset duration in ms */ | ||
| 1897 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 1898 | "REPORT_RESET", report->id, raw_size-1); | ||
| 1899 | hid_debug_event(hdev, buff); | ||
| 1900 | snprintf(buff, BUFF_SZ, "\tDuration: 0x%02x%02x (%dms)\n", | ||
| 1901 | raw_data[2], raw_data[1], raw_data[2] << 8 | raw_data[1]); | ||
| 1902 | hid_debug_event(hdev, buff); | ||
| 1903 | break; | ||
| 1904 | case REPORT_LCD_CMD: | ||
| 1905 | /* 63 data bytes with LCD commands */ | ||
| 1906 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 1907 | "REPORT_LCD_CMD", report->id, raw_size-1); | ||
| 1908 | hid_debug_event(hdev, buff); | ||
| 1909 | /* TODO: format decoding */ | ||
| 1910 | break; | ||
| 1911 | case REPORT_LCD_DATA: | ||
| 1912 | /* 63 data bytes with LCD data */ | ||
| 1913 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 1914 | "REPORT_LCD_CMD", report->id, raw_size-1); | ||
| 1915 | /* TODO: format decoding */ | ||
| 1916 | hid_debug_event(hdev, buff); | ||
| 1917 | break; | ||
| 1918 | case REPORT_LCD_CMD_DATA: | ||
| 1919 | /* 63 data bytes with LCD commands and data */ | ||
| 1920 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 1921 | "REPORT_LCD_CMD", report->id, raw_size-1); | ||
| 1922 | /* TODO: format decoding */ | ||
| 1923 | hid_debug_event(hdev, buff); | ||
| 1924 | break; | ||
| 1925 | case REPORT_EE_READ: | ||
| 1926 | /* 3 data bytes with read area description */ | ||
| 1927 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 1928 | "REPORT_EE_READ", report->id, raw_size-1); | ||
| 1929 | hid_debug_event(hdev, buff); | ||
| 1930 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
| 1931 | raw_data[2], raw_data[1]); | ||
| 1932 | hid_debug_event(hdev, buff); | ||
| 1933 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
| 1934 | hid_debug_event(hdev, buff); | ||
| 1935 | break; | ||
| 1936 | case REPORT_EE_WRITE: | ||
| 1937 | /* 3+1..20 data bytes with write area description */ | ||
| 1938 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 1939 | "REPORT_EE_WRITE", report->id, raw_size-1); | ||
| 1940 | hid_debug_event(hdev, buff); | ||
| 1941 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
| 1942 | raw_data[2], raw_data[1]); | ||
| 1943 | hid_debug_event(hdev, buff); | ||
| 1944 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
| 1945 | hid_debug_event(hdev, buff); | ||
| 1946 | if (raw_data[3] == 0) { | ||
| 1947 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
| 1948 | } else if (raw_data[3] + 4 <= raw_size) { | ||
| 1949 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
| 1950 | hid_debug_event(hdev, buff); | ||
| 1951 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
| 1952 | } else { | ||
| 1953 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
| 1954 | } | ||
| 1955 | hid_debug_event(hdev, buff); | ||
| 1956 | break; | ||
| 1957 | case REPORT_ERASE_MEMORY: | ||
| 1958 | case REPORT_BL_ERASE_MEMORY: | ||
| 1959 | /* 3 data bytes with pointer inside erase block */ | ||
| 1960 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 1961 | "REPORT_ERASE_MEMORY", report->id, raw_size-1); | ||
| 1962 | hid_debug_event(hdev, buff); | ||
| 1963 | switch (data->addr_sz) { | ||
| 1964 | case 2: | ||
| 1965 | snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x\n", | ||
| 1966 | raw_data[2], raw_data[1]); | ||
| 1967 | break; | ||
| 1968 | case 3: | ||
| 1969 | snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x%02x\n", | ||
| 1970 | raw_data[3], raw_data[2], raw_data[1]); | ||
| 1971 | break; | ||
| 1972 | default: | ||
| 1973 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
| 1974 | } | ||
| 1975 | hid_debug_event(hdev, buff); | ||
| 1976 | break; | ||
| 1977 | case REPORT_READ_MEMORY: | ||
| 1978 | case REPORT_BL_READ_MEMORY: | ||
| 1979 | /* 4 data bytes with read area description */ | ||
| 1980 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 1981 | "REPORT_READ_MEMORY", report->id, raw_size-1); | ||
| 1982 | hid_debug_event(hdev, buff); | ||
| 1983 | switch (data->addr_sz) { | ||
| 1984 | case 2: | ||
| 1985 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
| 1986 | raw_data[2], raw_data[1]); | ||
| 1987 | hid_debug_event(hdev, buff); | ||
| 1988 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
| 1989 | break; | ||
| 1990 | case 3: | ||
| 1991 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n", | ||
| 1992 | raw_data[3], raw_data[2], raw_data[1]); | ||
| 1993 | hid_debug_event(hdev, buff); | ||
| 1994 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]); | ||
| 1995 | break; | ||
| 1996 | default: | ||
| 1997 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
| 1998 | } | ||
| 1999 | hid_debug_event(hdev, buff); | ||
| 2000 | break; | ||
| 2001 | case REPORT_WRITE_MEMORY: | ||
| 2002 | case REPORT_BL_WRITE_MEMORY: | ||
| 2003 | /* 4+1..32 data bytes with write adrea description */ | ||
| 2004 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 2005 | "REPORT_WRITE_MEMORY", report->id, raw_size-1); | ||
| 2006 | hid_debug_event(hdev, buff); | ||
| 2007 | switch (data->addr_sz) { | ||
| 2008 | case 2: | ||
| 2009 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
| 2010 | raw_data[2], raw_data[1]); | ||
| 2011 | hid_debug_event(hdev, buff); | ||
| 2012 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
| 2013 | hid_debug_event(hdev, buff); | ||
| 2014 | if (raw_data[3] == 0) { | ||
| 2015 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
| 2016 | } else if (raw_data[3] + 4 <= raw_size) { | ||
| 2017 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
| 2018 | hid_debug_event(hdev, buff); | ||
| 2019 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
| 2020 | } else { | ||
| 2021 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
| 2022 | } | ||
| 2023 | break; | ||
| 2024 | case 3: | ||
| 2025 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n", | ||
| 2026 | raw_data[3], raw_data[2], raw_data[1]); | ||
| 2027 | hid_debug_event(hdev, buff); | ||
| 2028 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]); | ||
| 2029 | hid_debug_event(hdev, buff); | ||
| 2030 | if (raw_data[4] == 0) { | ||
| 2031 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
| 2032 | } else if (raw_data[4] + 5 <= raw_size) { | ||
| 2033 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
| 2034 | hid_debug_event(hdev, buff); | ||
| 2035 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]); | ||
| 2036 | } else { | ||
| 2037 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
| 2038 | } | ||
| 2039 | break; | ||
| 2040 | default: | ||
| 2041 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
| 2042 | } | ||
| 2043 | hid_debug_event(hdev, buff); | ||
| 2044 | break; | ||
| 2045 | case REPORT_SPLASH_RESTART: | ||
| 2046 | /* TODO */ | ||
| 2047 | break; | ||
| 2048 | case REPORT_EXIT_KEYBOARD: | ||
| 2049 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 2050 | "REPORT_EXIT_KEYBOARD", report->id, raw_size-1); | ||
| 2051 | hid_debug_event(hdev, buff); | ||
| 2052 | snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n", | ||
| 2053 | raw_data[1] | (raw_data[2] << 8), | ||
| 2054 | raw_data[2], raw_data[1]); | ||
| 2055 | hid_debug_event(hdev, buff); | ||
| 2056 | break; | ||
| 2057 | case REPORT_VERSION: | ||
| 2058 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 2059 | "REPORT_VERSION", report->id, raw_size-1); | ||
| 2060 | hid_debug_event(hdev, buff); | ||
| 2061 | break; | ||
| 2062 | case REPORT_DEVID: | ||
| 2063 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 2064 | "REPORT_DEVID", report->id, raw_size-1); | ||
| 2065 | hid_debug_event(hdev, buff); | ||
| 2066 | break; | ||
| 2067 | case REPORT_SPLASH_SIZE: | ||
| 2068 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 2069 | "REPORT_SPLASH_SIZE", report->id, raw_size-1); | ||
| 2070 | hid_debug_event(hdev, buff); | ||
| 2071 | break; | ||
| 2072 | case REPORT_HOOK_VERSION: | ||
| 2073 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 2074 | "REPORT_HOOK_VERSION", report->id, raw_size-1); | ||
| 2075 | hid_debug_event(hdev, buff); | ||
| 2076 | break; | ||
| 2077 | case REPORT_EXIT_FLASHER: | ||
| 2078 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 2079 | "REPORT_VERSION", report->id, raw_size-1); | ||
| 2080 | hid_debug_event(hdev, buff); | ||
| 2081 | snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n", | ||
| 2082 | raw_data[1] | (raw_data[2] << 8), | ||
| 2083 | raw_data[2], raw_data[1]); | ||
| 2084 | hid_debug_event(hdev, buff); | ||
| 2085 | break; | ||
| 2086 | default: | ||
| 2087 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 2088 | "<unknown>", report->id, raw_size-1); | ||
| 2089 | hid_debug_event(hdev, buff); | ||
| 2090 | break; | ||
| 2091 | } | ||
| 2092 | wake_up_interruptible(&hdev->debug_wait); | ||
| 2093 | kfree(buff); | ||
| 2094 | } | ||
| 2095 | |||
| 2096 | static void picolcd_debug_raw_event(struct picolcd_data *data, | ||
| 2097 | struct hid_device *hdev, struct hid_report *report, | ||
| 2098 | u8 *raw_data, int size) | ||
| 2099 | { | ||
| 2100 | char *buff; | ||
| 2101 | |||
| 2102 | #define BUFF_SZ 256 | ||
| 2103 | /* Avoid unnecessary overhead if debugfs is disabled */ | ||
| 2104 | if (!hdev->debug_events) | ||
| 2105 | return; | ||
| 2106 | |||
| 2107 | buff = kmalloc(BUFF_SZ, GFP_ATOMIC); | ||
| 2108 | if (!buff) | ||
| 2109 | return; | ||
| 2110 | |||
| 2111 | switch (report->id) { | ||
| 2112 | case REPORT_ERROR_CODE: | ||
| 2113 | /* 2 data bytes with affected report and error code */ | ||
| 2114 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 2115 | "REPORT_ERROR_CODE", report->id, size-1); | ||
| 2116 | hid_debug_event(hdev, buff); | ||
| 2117 | if (raw_data[2] < ARRAY_SIZE(error_codes)) | ||
| 2118 | snprintf(buff, BUFF_SZ, "\tError code 0x%02x (%s) in reply to report 0x%02x\n", | ||
| 2119 | raw_data[2], error_codes[raw_data[2]], raw_data[1]); | ||
| 2120 | else | ||
| 2121 | snprintf(buff, BUFF_SZ, "\tError code 0x%02x in reply to report 0x%02x\n", | ||
| 2122 | raw_data[2], raw_data[1]); | ||
| 2123 | hid_debug_event(hdev, buff); | ||
| 2124 | break; | ||
| 2125 | case REPORT_KEY_STATE: | ||
| 2126 | /* 2 data bytes with key state */ | ||
| 2127 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 2128 | "REPORT_KEY_STATE", report->id, size-1); | ||
| 2129 | hid_debug_event(hdev, buff); | ||
| 2130 | if (raw_data[1] == 0) | ||
| 2131 | snprintf(buff, BUFF_SZ, "\tNo key pressed\n"); | ||
| 2132 | else if (raw_data[2] == 0) | ||
| 2133 | snprintf(buff, BUFF_SZ, "\tOne key pressed: 0x%02x (%d)\n", | ||
| 2134 | raw_data[1], raw_data[1]); | ||
| 2135 | else | ||
| 2136 | snprintf(buff, BUFF_SZ, "\tTwo keys pressed: 0x%02x (%d), 0x%02x (%d)\n", | ||
| 2137 | raw_data[1], raw_data[1], raw_data[2], raw_data[2]); | ||
| 2138 | hid_debug_event(hdev, buff); | ||
| 2139 | break; | ||
| 2140 | case REPORT_IR_DATA: | ||
| 2141 | /* Up to 20 byes of IR scancode data */ | ||
| 2142 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 2143 | "REPORT_IR_DATA", report->id, size-1); | ||
| 2144 | hid_debug_event(hdev, buff); | ||
| 2145 | if (raw_data[1] == 0) { | ||
| 2146 | snprintf(buff, BUFF_SZ, "\tUnexpectedly 0 data length\n"); | ||
| 2147 | hid_debug_event(hdev, buff); | ||
| 2148 | } else if (raw_data[1] + 1 <= size) { | ||
| 2149 | snprintf(buff, BUFF_SZ, "\tData length: %d\n\tIR Data: ", | ||
| 2150 | raw_data[1]-1); | ||
| 2151 | hid_debug_event(hdev, buff); | ||
| 2152 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+2, raw_data[1]-1); | ||
| 2153 | hid_debug_event(hdev, buff); | ||
| 2154 | } else { | ||
| 2155 | snprintf(buff, BUFF_SZ, "\tOverflowing data length: %d\n", | ||
| 2156 | raw_data[1]-1); | ||
| 2157 | hid_debug_event(hdev, buff); | ||
| 2158 | } | ||
| 2159 | break; | ||
| 2160 | case REPORT_EE_DATA: | ||
| 2161 | /* Data buffer in response to REPORT_EE_READ or REPORT_EE_WRITE */ | ||
| 2162 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 2163 | "REPORT_EE_DATA", report->id, size-1); | ||
| 2164 | hid_debug_event(hdev, buff); | ||
| 2165 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
| 2166 | raw_data[2], raw_data[1]); | ||
| 2167 | hid_debug_event(hdev, buff); | ||
| 2168 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
| 2169 | hid_debug_event(hdev, buff); | ||
| 2170 | if (raw_data[3] == 0) { | ||
| 2171 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
| 2172 | hid_debug_event(hdev, buff); | ||
| 2173 | } else if (raw_data[3] + 4 <= size) { | ||
| 2174 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
| 2175 | hid_debug_event(hdev, buff); | ||
| 2176 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
| 2177 | hid_debug_event(hdev, buff); | ||
| 2178 | } else { | ||
| 2179 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
| 2180 | hid_debug_event(hdev, buff); | ||
| 2181 | } | ||
| 2182 | break; | ||
| 2183 | case REPORT_MEMORY: | ||
| 2184 | /* Data buffer in response to REPORT_READ_MEMORY or REPORT_WRTIE_MEMORY */ | ||
| 2185 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 2186 | "REPORT_MEMORY", report->id, size-1); | ||
| 2187 | hid_debug_event(hdev, buff); | ||
| 2188 | switch (data->addr_sz) { | ||
| 2189 | case 2: | ||
| 2190 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
| 2191 | raw_data[2], raw_data[1]); | ||
| 2192 | hid_debug_event(hdev, buff); | ||
| 2193 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
| 2194 | hid_debug_event(hdev, buff); | ||
| 2195 | if (raw_data[3] == 0) { | ||
| 2196 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
| 2197 | } else if (raw_data[3] + 4 <= size) { | ||
| 2198 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
| 2199 | hid_debug_event(hdev, buff); | ||
| 2200 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
| 2201 | } else { | ||
| 2202 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
| 2203 | } | ||
| 2204 | break; | ||
| 2205 | case 3: | ||
| 2206 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n", | ||
| 2207 | raw_data[3], raw_data[2], raw_data[1]); | ||
| 2208 | hid_debug_event(hdev, buff); | ||
| 2209 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]); | ||
| 2210 | hid_debug_event(hdev, buff); | ||
| 2211 | if (raw_data[4] == 0) { | ||
| 2212 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
| 2213 | } else if (raw_data[4] + 5 <= size) { | ||
| 2214 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
| 2215 | hid_debug_event(hdev, buff); | ||
| 2216 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]); | ||
| 2217 | } else { | ||
| 2218 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
| 2219 | } | ||
| 2220 | break; | ||
| 2221 | default: | ||
| 2222 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
| 2223 | } | ||
| 2224 | hid_debug_event(hdev, buff); | ||
| 2225 | break; | ||
| 2226 | case REPORT_VERSION: | ||
| 2227 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 2228 | "REPORT_VERSION", report->id, size-1); | ||
| 2229 | hid_debug_event(hdev, buff); | ||
| 2230 | snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n", | ||
| 2231 | raw_data[2], raw_data[1]); | ||
| 2232 | hid_debug_event(hdev, buff); | ||
| 2233 | break; | ||
| 2234 | case REPORT_BL_ERASE_MEMORY: | ||
| 2235 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 2236 | "REPORT_BL_ERASE_MEMORY", report->id, size-1); | ||
| 2237 | hid_debug_event(hdev, buff); | ||
| 2238 | /* TODO */ | ||
| 2239 | break; | ||
| 2240 | case REPORT_BL_READ_MEMORY: | ||
| 2241 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 2242 | "REPORT_BL_READ_MEMORY", report->id, size-1); | ||
| 2243 | hid_debug_event(hdev, buff); | ||
| 2244 | /* TODO */ | ||
| 2245 | break; | ||
| 2246 | case REPORT_BL_WRITE_MEMORY: | ||
| 2247 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 2248 | "REPORT_BL_WRITE_MEMORY", report->id, size-1); | ||
| 2249 | hid_debug_event(hdev, buff); | ||
| 2250 | /* TODO */ | ||
| 2251 | break; | ||
| 2252 | case REPORT_DEVID: | ||
| 2253 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 2254 | "REPORT_DEVID", report->id, size-1); | ||
| 2255 | hid_debug_event(hdev, buff); | ||
| 2256 | snprintf(buff, BUFF_SZ, "\tSerial: 0x%02x%02x%02x%02x\n", | ||
| 2257 | raw_data[1], raw_data[2], raw_data[3], raw_data[4]); | ||
| 2258 | hid_debug_event(hdev, buff); | ||
| 2259 | snprintf(buff, BUFF_SZ, "\tType: 0x%02x\n", | ||
| 2260 | raw_data[5]); | ||
| 2261 | hid_debug_event(hdev, buff); | ||
| 2262 | break; | ||
| 2263 | case REPORT_SPLASH_SIZE: | ||
| 2264 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 2265 | "REPORT_SPLASH_SIZE", report->id, size-1); | ||
| 2266 | hid_debug_event(hdev, buff); | ||
| 2267 | snprintf(buff, BUFF_SZ, "\tTotal splash space: %d\n", | ||
| 2268 | (raw_data[2] << 8) | raw_data[1]); | ||
| 2269 | hid_debug_event(hdev, buff); | ||
| 2270 | snprintf(buff, BUFF_SZ, "\tUsed splash space: %d\n", | ||
| 2271 | (raw_data[4] << 8) | raw_data[3]); | ||
| 2272 | hid_debug_event(hdev, buff); | ||
| 2273 | break; | ||
| 2274 | case REPORT_HOOK_VERSION: | ||
| 2275 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 2276 | "REPORT_HOOK_VERSION", report->id, size-1); | ||
| 2277 | hid_debug_event(hdev, buff); | ||
| 2278 | snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n", | ||
| 2279 | raw_data[1], raw_data[2]); | ||
| 2280 | hid_debug_event(hdev, buff); | ||
| 2281 | break; | ||
| 2282 | default: | ||
| 2283 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 2284 | "<unknown>", report->id, size-1); | ||
| 2285 | hid_debug_event(hdev, buff); | ||
| 2286 | break; | ||
| 2287 | } | ||
| 2288 | wake_up_interruptible(&hdev->debug_wait); | ||
| 2289 | kfree(buff); | ||
| 2290 | } | ||
| 2291 | |||
| 2292 | static void picolcd_init_devfs(struct picolcd_data *data, | ||
| 2293 | struct hid_report *eeprom_r, struct hid_report *eeprom_w, | ||
| 2294 | struct hid_report *flash_r, struct hid_report *flash_w, | ||
| 2295 | struct hid_report *reset) | ||
| 2296 | { | ||
| 2297 | struct hid_device *hdev = data->hdev; | ||
| 2298 | |||
| 2299 | mutex_init(&data->mutex_flash); | ||
| 2300 | |||
| 2301 | /* reset */ | ||
| 2302 | if (reset) | ||
| 2303 | data->debug_reset = debugfs_create_file("reset", 0600, | ||
| 2304 | hdev->debug_dir, data, &picolcd_debug_reset_fops); | ||
| 2305 | |||
| 2306 | /* eeprom */ | ||
| 2307 | if (eeprom_r || eeprom_w) | ||
| 2308 | data->debug_eeprom = debugfs_create_file("eeprom", | ||
| 2309 | (eeprom_w ? S_IWUSR : 0) | (eeprom_r ? S_IRUSR : 0), | ||
| 2310 | hdev->debug_dir, data, &picolcd_debug_eeprom_fops); | ||
| 2311 | |||
| 2312 | /* flash */ | ||
| 2313 | if (flash_r && flash_r->maxfield == 1 && flash_r->field[0]->report_size == 8) | ||
| 2314 | data->addr_sz = flash_r->field[0]->report_count - 1; | ||
| 2315 | else | ||
| 2316 | data->addr_sz = -1; | ||
| 2317 | if (data->addr_sz == 2 || data->addr_sz == 3) { | ||
| 2318 | data->debug_flash = debugfs_create_file("flash", | ||
| 2319 | (flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0), | ||
| 2320 | hdev->debug_dir, data, &picolcd_debug_flash_fops); | ||
| 2321 | } else if (flash_r || flash_w) | ||
| 2322 | hid_warn(hdev, "Unexpected FLASH access reports, please submit rdesc for review\n"); | ||
| 2323 | } | ||
| 2324 | |||
| 2325 | static void picolcd_exit_devfs(struct picolcd_data *data) | ||
| 2326 | { | ||
| 2327 | struct dentry *dent; | ||
| 2328 | |||
| 2329 | dent = data->debug_reset; | ||
| 2330 | data->debug_reset = NULL; | ||
| 2331 | if (dent) | ||
| 2332 | debugfs_remove(dent); | ||
| 2333 | dent = data->debug_eeprom; | ||
| 2334 | data->debug_eeprom = NULL; | ||
| 2335 | if (dent) | ||
| 2336 | debugfs_remove(dent); | ||
| 2337 | dent = data->debug_flash; | ||
| 2338 | data->debug_flash = NULL; | ||
| 2339 | if (dent) | ||
| 2340 | debugfs_remove(dent); | ||
| 2341 | mutex_destroy(&data->mutex_flash); | ||
| 2342 | } | ||
| 2343 | #else | ||
| 2344 | static inline void picolcd_debug_raw_event(struct picolcd_data *data, | ||
| 2345 | struct hid_device *hdev, struct hid_report *report, | ||
| 2346 | u8 *raw_data, int size) | ||
| 2347 | { | ||
| 2348 | } | ||
| 2349 | static inline void picolcd_init_devfs(struct picolcd_data *data, | ||
| 2350 | struct hid_report *eeprom_r, struct hid_report *eeprom_w, | ||
| 2351 | struct hid_report *flash_r, struct hid_report *flash_w, | ||
| 2352 | struct hid_report *reset) | ||
| 2353 | { | ||
| 2354 | } | ||
| 2355 | static inline void picolcd_exit_devfs(struct picolcd_data *data) | ||
| 2356 | { | ||
| 2357 | } | ||
| 2358 | #endif /* CONFIG_DEBUG_FS */ | ||
| 2359 | |||
| 2360 | /* | ||
| 2361 | * Handle raw report as sent by device | ||
| 2362 | */ | ||
| 2363 | static int picolcd_raw_event(struct hid_device *hdev, | ||
| 2364 | struct hid_report *report, u8 *raw_data, int size) | ||
| 2365 | { | ||
| 2366 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
| 2367 | unsigned long flags; | ||
| 2368 | int ret = 0; | ||
| 2369 | |||
| 2370 | if (!data) | ||
| 2371 | return 1; | ||
| 2372 | |||
| 2373 | if (report->id == REPORT_KEY_STATE) { | ||
| 2374 | if (data->input_keys) | ||
| 2375 | ret = picolcd_raw_keypad(data, report, raw_data+1, size-1); | ||
| 2376 | } else if (report->id == REPORT_IR_DATA) { | ||
| 2377 | if (data->input_cir) | ||
| 2378 | ret = picolcd_raw_cir(data, report, raw_data+1, size-1); | ||
| 2379 | } else { | ||
| 2380 | spin_lock_irqsave(&data->lock, flags); | ||
| 2381 | /* | ||
| 2382 | * We let the caller of picolcd_send_and_wait() check if the | ||
| 2383 | * report we got is one of the expected ones or not. | ||
| 2384 | */ | ||
| 2385 | if (data->pending) { | ||
| 2386 | memcpy(data->pending->raw_data, raw_data+1, size-1); | ||
| 2387 | data->pending->raw_size = size-1; | ||
| 2388 | data->pending->in_report = report; | ||
| 2389 | complete(&data->pending->ready); | ||
| 2390 | } | ||
| 2391 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 2392 | } | ||
| 2393 | |||
| 2394 | picolcd_debug_raw_event(data, hdev, report, raw_data, size); | ||
| 2395 | return 1; | ||
| 2396 | } | ||
| 2397 | |||
| 2398 | #ifdef CONFIG_PM | ||
| 2399 | static int picolcd_suspend(struct hid_device *hdev, pm_message_t message) | ||
| 2400 | { | ||
| 2401 | if (PMSG_IS_AUTO(message)) | ||
| 2402 | return 0; | ||
| 2403 | |||
| 2404 | picolcd_suspend_backlight(hid_get_drvdata(hdev)); | ||
| 2405 | dbg_hid(PICOLCD_NAME " device ready for suspend\n"); | ||
| 2406 | return 0; | ||
| 2407 | } | ||
| 2408 | |||
| 2409 | static int picolcd_resume(struct hid_device *hdev) | ||
| 2410 | { | ||
| 2411 | int ret; | ||
| 2412 | ret = picolcd_resume_backlight(hid_get_drvdata(hdev)); | ||
| 2413 | if (ret) | ||
| 2414 | dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret); | ||
| 2415 | return 0; | ||
| 2416 | } | ||
| 2417 | |||
| 2418 | static int picolcd_reset_resume(struct hid_device *hdev) | ||
| 2419 | { | ||
| 2420 | int ret; | ||
| 2421 | ret = picolcd_reset(hdev); | ||
| 2422 | if (ret) | ||
| 2423 | dbg_hid(PICOLCD_NAME " resetting our device failed: %d\n", ret); | ||
| 2424 | ret = picolcd_fb_reset(hid_get_drvdata(hdev), 0); | ||
| 2425 | if (ret) | ||
| 2426 | dbg_hid(PICOLCD_NAME " restoring framebuffer content failed: %d\n", ret); | ||
| 2427 | ret = picolcd_resume_lcd(hid_get_drvdata(hdev)); | ||
| 2428 | if (ret) | ||
| 2429 | dbg_hid(PICOLCD_NAME " restoring lcd failed: %d\n", ret); | ||
| 2430 | ret = picolcd_resume_backlight(hid_get_drvdata(hdev)); | ||
| 2431 | if (ret) | ||
| 2432 | dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret); | ||
| 2433 | picolcd_leds_set(hid_get_drvdata(hdev)); | ||
| 2434 | return 0; | ||
| 2435 | } | ||
| 2436 | #endif | ||
| 2437 | |||
| 2438 | /* initialize keypad input device */ | ||
| 2439 | static int picolcd_init_keys(struct picolcd_data *data, | ||
| 2440 | struct hid_report *report) | ||
| 2441 | { | ||
| 2442 | struct hid_device *hdev = data->hdev; | ||
| 2443 | struct input_dev *idev; | ||
| 2444 | int error, i; | ||
| 2445 | |||
| 2446 | if (!report) | ||
| 2447 | return -ENODEV; | ||
| 2448 | if (report->maxfield != 1 || report->field[0]->report_count != 2 || | ||
| 2449 | report->field[0]->report_size != 8) { | ||
| 2450 | hid_err(hdev, "unsupported KEY_STATE report\n"); | ||
| 2451 | return -EINVAL; | ||
| 2452 | } | ||
| 2453 | |||
| 2454 | idev = input_allocate_device(); | ||
| 2455 | if (idev == NULL) { | ||
| 2456 | hid_err(hdev, "failed to allocate input device\n"); | ||
| 2457 | return -ENOMEM; | ||
| 2458 | } | ||
| 2459 | input_set_drvdata(idev, hdev); | ||
| 2460 | memcpy(data->keycode, def_keymap, sizeof(def_keymap)); | ||
| 2461 | idev->name = hdev->name; | ||
| 2462 | idev->phys = hdev->phys; | ||
| 2463 | idev->uniq = hdev->uniq; | ||
| 2464 | idev->id.bustype = hdev->bus; | ||
| 2465 | idev->id.vendor = hdev->vendor; | ||
| 2466 | idev->id.product = hdev->product; | ||
| 2467 | idev->id.version = hdev->version; | ||
| 2468 | idev->dev.parent = hdev->dev.parent; | ||
| 2469 | idev->keycode = &data->keycode; | ||
| 2470 | idev->keycodemax = PICOLCD_KEYS; | ||
| 2471 | idev->keycodesize = sizeof(data->keycode[0]); | ||
| 2472 | input_set_capability(idev, EV_MSC, MSC_SCAN); | ||
| 2473 | set_bit(EV_REP, idev->evbit); | ||
| 2474 | for (i = 0; i < PICOLCD_KEYS; i++) | ||
| 2475 | input_set_capability(idev, EV_KEY, data->keycode[i]); | ||
| 2476 | error = input_register_device(idev); | ||
| 2477 | if (error) { | ||
| 2478 | hid_err(hdev, "error registering the input device\n"); | ||
| 2479 | input_free_device(idev); | ||
| 2480 | return error; | ||
| 2481 | } | ||
| 2482 | data->input_keys = idev; | ||
| 2483 | return 0; | ||
| 2484 | } | ||
| 2485 | |||
| 2486 | static void picolcd_exit_keys(struct picolcd_data *data) | ||
| 2487 | { | ||
| 2488 | struct input_dev *idev = data->input_keys; | ||
| 2489 | |||
| 2490 | data->input_keys = NULL; | ||
| 2491 | if (idev) | ||
| 2492 | input_unregister_device(idev); | ||
| 2493 | } | ||
| 2494 | |||
| 2495 | /* initialize CIR input device */ | ||
| 2496 | static inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report) | ||
| 2497 | { | ||
| 2498 | /* support not implemented yet */ | ||
| 2499 | return 0; | ||
| 2500 | } | ||
| 2501 | |||
| 2502 | static inline void picolcd_exit_cir(struct picolcd_data *data) | ||
| 2503 | { | ||
| 2504 | } | ||
| 2505 | |||
| 2506 | static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data) | ||
| 2507 | { | ||
| 2508 | int error; | ||
| 2509 | |||
| 2510 | error = picolcd_check_version(hdev); | ||
| 2511 | if (error) | ||
| 2512 | return error; | ||
| 2513 | |||
| 2514 | if (data->version[0] != 0 && data->version[1] != 3) | ||
| 2515 | hid_info(hdev, "Device with untested firmware revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n", | ||
| 2516 | dev_name(&hdev->dev)); | ||
| 2517 | |||
| 2518 | /* Setup keypad input device */ | ||
| 2519 | error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev)); | ||
| 2520 | if (error) | ||
| 2521 | goto err; | ||
| 2522 | |||
| 2523 | /* Setup CIR input device */ | ||
| 2524 | error = picolcd_init_cir(data, picolcd_in_report(REPORT_IR_DATA, hdev)); | ||
| 2525 | if (error) | ||
| 2526 | goto err; | ||
| 2527 | |||
| 2528 | /* Set up the framebuffer device */ | ||
| 2529 | error = picolcd_init_framebuffer(data); | ||
| 2530 | if (error) | ||
| 2531 | goto err; | ||
| 2532 | |||
| 2533 | /* Setup lcd class device */ | ||
| 2534 | error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev)); | ||
| 2535 | if (error) | ||
| 2536 | goto err; | ||
| 2537 | |||
| 2538 | /* Setup backlight class device */ | ||
| 2539 | error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev)); | ||
| 2540 | if (error) | ||
| 2541 | goto err; | ||
| 2542 | |||
| 2543 | /* Setup the LED class devices */ | ||
| 2544 | error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev)); | ||
| 2545 | if (error) | ||
| 2546 | goto err; | ||
| 2547 | |||
| 2548 | picolcd_init_devfs(data, picolcd_out_report(REPORT_EE_READ, hdev), | ||
| 2549 | picolcd_out_report(REPORT_EE_WRITE, hdev), | ||
| 2550 | picolcd_out_report(REPORT_READ_MEMORY, hdev), | ||
| 2551 | picolcd_out_report(REPORT_WRITE_MEMORY, hdev), | ||
| 2552 | picolcd_out_report(REPORT_RESET, hdev)); | ||
| 2553 | return 0; | ||
| 2554 | err: | ||
| 2555 | picolcd_exit_leds(data); | ||
| 2556 | picolcd_exit_backlight(data); | ||
| 2557 | picolcd_exit_lcd(data); | ||
| 2558 | picolcd_exit_framebuffer(data); | ||
| 2559 | picolcd_exit_cir(data); | ||
| 2560 | picolcd_exit_keys(data); | ||
| 2561 | return error; | ||
| 2562 | } | ||
| 2563 | |||
| 2564 | static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data *data) | ||
| 2565 | { | ||
| 2566 | int error; | ||
| 2567 | |||
| 2568 | error = picolcd_check_version(hdev); | ||
| 2569 | if (error) | ||
| 2570 | return error; | ||
| 2571 | |||
| 2572 | if (data->version[0] != 1 && data->version[1] != 0) | ||
| 2573 | hid_info(hdev, "Device with untested bootloader revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n", | ||
| 2574 | dev_name(&hdev->dev)); | ||
| 2575 | |||
| 2576 | picolcd_init_devfs(data, NULL, NULL, | ||
| 2577 | picolcd_out_report(REPORT_BL_READ_MEMORY, hdev), | ||
| 2578 | picolcd_out_report(REPORT_BL_WRITE_MEMORY, hdev), NULL); | ||
| 2579 | return 0; | ||
| 2580 | } | ||
| 2581 | |||
| 2582 | static int picolcd_probe(struct hid_device *hdev, | ||
| 2583 | const struct hid_device_id *id) | ||
| 2584 | { | ||
| 2585 | struct picolcd_data *data; | ||
| 2586 | int error = -ENOMEM; | ||
| 2587 | |||
| 2588 | dbg_hid(PICOLCD_NAME " hardware probe...\n"); | ||
| 2589 | |||
| 2590 | /* | ||
| 2591 | * Let's allocate the picolcd data structure, set some reasonable | ||
| 2592 | * defaults, and associate it with the device | ||
| 2593 | */ | ||
| 2594 | data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL); | ||
| 2595 | if (data == NULL) { | ||
| 2596 | hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n"); | ||
| 2597 | error = -ENOMEM; | ||
| 2598 | goto err_no_cleanup; | ||
| 2599 | } | ||
| 2600 | |||
| 2601 | spin_lock_init(&data->lock); | ||
| 2602 | mutex_init(&data->mutex); | ||
| 2603 | data->hdev = hdev; | ||
| 2604 | data->opmode_delay = 5000; | ||
| 2605 | if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER) | ||
| 2606 | data->status |= PICOLCD_BOOTLOADER; | ||
| 2607 | hid_set_drvdata(hdev, data); | ||
| 2608 | |||
| 2609 | /* Parse the device reports and start it up */ | ||
| 2610 | error = hid_parse(hdev); | ||
| 2611 | if (error) { | ||
| 2612 | hid_err(hdev, "device report parse failed\n"); | ||
| 2613 | goto err_cleanup_data; | ||
| 2614 | } | ||
| 2615 | |||
| 2616 | error = hid_hw_start(hdev, 0); | ||
| 2617 | if (error) { | ||
| 2618 | hid_err(hdev, "hardware start failed\n"); | ||
| 2619 | goto err_cleanup_data; | ||
| 2620 | } | ||
| 2621 | |||
| 2622 | error = hid_hw_open(hdev); | ||
| 2623 | if (error) { | ||
| 2624 | hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n"); | ||
| 2625 | goto err_cleanup_hid_hw; | ||
| 2626 | } | ||
| 2627 | |||
| 2628 | error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay); | ||
| 2629 | if (error) { | ||
| 2630 | hid_err(hdev, "failed to create sysfs attributes\n"); | ||
| 2631 | goto err_cleanup_hid_ll; | ||
| 2632 | } | ||
| 2633 | |||
| 2634 | error = device_create_file(&hdev->dev, &dev_attr_operation_mode); | ||
| 2635 | if (error) { | ||
| 2636 | hid_err(hdev, "failed to create sysfs attributes\n"); | ||
| 2637 | goto err_cleanup_sysfs1; | ||
| 2638 | } | ||
| 2639 | |||
| 2640 | if (data->status & PICOLCD_BOOTLOADER) | ||
| 2641 | error = picolcd_probe_bootloader(hdev, data); | ||
| 2642 | else | ||
| 2643 | error = picolcd_probe_lcd(hdev, data); | ||
| 2644 | if (error) | ||
| 2645 | goto err_cleanup_sysfs2; | ||
| 2646 | |||
| 2647 | dbg_hid(PICOLCD_NAME " activated and initialized\n"); | ||
| 2648 | return 0; | ||
| 2649 | |||
| 2650 | err_cleanup_sysfs2: | ||
| 2651 | device_remove_file(&hdev->dev, &dev_attr_operation_mode); | ||
| 2652 | err_cleanup_sysfs1: | ||
| 2653 | device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay); | ||
| 2654 | err_cleanup_hid_ll: | ||
| 2655 | hid_hw_close(hdev); | ||
| 2656 | err_cleanup_hid_hw: | ||
| 2657 | hid_hw_stop(hdev); | ||
| 2658 | err_cleanup_data: | ||
| 2659 | kfree(data); | ||
| 2660 | err_no_cleanup: | ||
| 2661 | hid_set_drvdata(hdev, NULL); | ||
| 2662 | |||
| 2663 | return error; | ||
| 2664 | } | ||
| 2665 | |||
| 2666 | static void picolcd_remove(struct hid_device *hdev) | ||
| 2667 | { | ||
| 2668 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
| 2669 | unsigned long flags; | ||
| 2670 | |||
| 2671 | dbg_hid(PICOLCD_NAME " hardware remove...\n"); | ||
| 2672 | spin_lock_irqsave(&data->lock, flags); | ||
| 2673 | data->status |= PICOLCD_FAILED; | ||
| 2674 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 2675 | #ifdef CONFIG_HID_PICOLCD_FB | ||
| 2676 | /* short-circuit FB as early as possible in order to | ||
| 2677 | * avoid long delays if we host console. | ||
| 2678 | */ | ||
| 2679 | if (data->fb_info) | ||
| 2680 | data->fb_info->par = NULL; | ||
| 2681 | #endif | ||
| 2682 | |||
| 2683 | picolcd_exit_devfs(data); | ||
| 2684 | device_remove_file(&hdev->dev, &dev_attr_operation_mode); | ||
| 2685 | device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay); | ||
| 2686 | hid_hw_close(hdev); | ||
| 2687 | hid_hw_stop(hdev); | ||
| 2688 | hid_set_drvdata(hdev, NULL); | ||
| 2689 | |||
| 2690 | /* Shortcut potential pending reply that will never arrive */ | ||
| 2691 | spin_lock_irqsave(&data->lock, flags); | ||
| 2692 | if (data->pending) | ||
| 2693 | complete(&data->pending->ready); | ||
| 2694 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 2695 | |||
| 2696 | /* Cleanup LED */ | ||
| 2697 | picolcd_exit_leds(data); | ||
| 2698 | /* Clean up the framebuffer */ | ||
| 2699 | picolcd_exit_backlight(data); | ||
| 2700 | picolcd_exit_lcd(data); | ||
| 2701 | picolcd_exit_framebuffer(data); | ||
| 2702 | /* Cleanup input */ | ||
| 2703 | picolcd_exit_cir(data); | ||
| 2704 | picolcd_exit_keys(data); | ||
| 2705 | |||
| 2706 | mutex_destroy(&data->mutex); | ||
| 2707 | /* Finally, clean up the picolcd data itself */ | ||
| 2708 | kfree(data); | ||
| 2709 | } | ||
| 2710 | |||
| 2711 | static const struct hid_device_id picolcd_devices[] = { | ||
| 2712 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) }, | ||
| 2713 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) }, | ||
| 2714 | { } | ||
| 2715 | }; | ||
| 2716 | MODULE_DEVICE_TABLE(hid, picolcd_devices); | ||
| 2717 | |||
| 2718 | static struct hid_driver picolcd_driver = { | ||
| 2719 | .name = "hid-picolcd", | ||
| 2720 | .id_table = picolcd_devices, | ||
| 2721 | .probe = picolcd_probe, | ||
| 2722 | .remove = picolcd_remove, | ||
| 2723 | .raw_event = picolcd_raw_event, | ||
| 2724 | #ifdef CONFIG_PM | ||
| 2725 | .suspend = picolcd_suspend, | ||
| 2726 | .resume = picolcd_resume, | ||
| 2727 | .reset_resume = picolcd_reset_resume, | ||
| 2728 | #endif | ||
| 2729 | }; | ||
| 2730 | |||
| 2731 | static int __init picolcd_init(void) | ||
| 2732 | { | ||
| 2733 | return hid_register_driver(&picolcd_driver); | ||
| 2734 | } | ||
| 2735 | |||
| 2736 | static void __exit picolcd_exit(void) | ||
| 2737 | { | ||
| 2738 | hid_unregister_driver(&picolcd_driver); | ||
| 2739 | #ifdef CONFIG_HID_PICOLCD_FB | ||
| 2740 | flush_work_sync(&picolcd_fb_cleanup); | ||
| 2741 | WARN_ON(fb_pending); | ||
| 2742 | #endif | ||
| 2743 | } | ||
| 2744 | |||
| 2745 | module_init(picolcd_init); | ||
| 2746 | module_exit(picolcd_exit); | ||
| 2747 | MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver"); | ||
| 2748 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/hid/hid-picolcd.h b/drivers/hid/hid-picolcd.h new file mode 100644 index 000000000000..020cef69f6a1 --- /dev/null +++ b/drivers/hid/hid-picolcd.h | |||
| @@ -0,0 +1,309 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> * | ||
| 3 | * * | ||
| 4 | * Based on Logitech G13 driver (v0.4) * | ||
| 5 | * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * | ||
| 6 | * * | ||
| 7 | * This program is free software: you can redistribute it and/or modify * | ||
| 8 | * it under the terms of the GNU General Public License as published by * | ||
| 9 | * the Free Software Foundation, version 2 of the License. * | ||
| 10 | * * | ||
| 11 | * This driver is distributed in the hope that it will be useful, but * | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * | ||
| 14 | * General Public License for more details. * | ||
| 15 | * * | ||
| 16 | * You should have received a copy of the GNU General Public License * | ||
| 17 | * along with this software. If not see <http://www.gnu.org/licenses/>. * | ||
| 18 | ***************************************************************************/ | ||
| 19 | |||
| 20 | #define PICOLCD_NAME "PicoLCD (graphic)" | ||
| 21 | |||
| 22 | /* Report numbers */ | ||
| 23 | #define REPORT_ERROR_CODE 0x10 /* LCD: IN[16] */ | ||
| 24 | #define ERR_SUCCESS 0x00 | ||
| 25 | #define ERR_PARAMETER_MISSING 0x01 | ||
| 26 | #define ERR_DATA_MISSING 0x02 | ||
| 27 | #define ERR_BLOCK_READ_ONLY 0x03 | ||
| 28 | #define ERR_BLOCK_NOT_ERASABLE 0x04 | ||
| 29 | #define ERR_BLOCK_TOO_BIG 0x05 | ||
| 30 | #define ERR_SECTION_OVERFLOW 0x06 | ||
| 31 | #define ERR_INVALID_CMD_LEN 0x07 | ||
| 32 | #define ERR_INVALID_DATA_LEN 0x08 | ||
| 33 | #define REPORT_KEY_STATE 0x11 /* LCD: IN[2] */ | ||
| 34 | #define REPORT_IR_DATA 0x21 /* LCD: IN[63] */ | ||
| 35 | #define REPORT_EE_DATA 0x32 /* LCD: IN[63] */ | ||
| 36 | #define REPORT_MEMORY 0x41 /* LCD: IN[63] */ | ||
| 37 | #define REPORT_LED_STATE 0x81 /* LCD: OUT[1] */ | ||
| 38 | #define REPORT_BRIGHTNESS 0x91 /* LCD: OUT[1] */ | ||
| 39 | #define REPORT_CONTRAST 0x92 /* LCD: OUT[1] */ | ||
| 40 | #define REPORT_RESET 0x93 /* LCD: OUT[2] */ | ||
| 41 | #define REPORT_LCD_CMD 0x94 /* LCD: OUT[63] */ | ||
| 42 | #define REPORT_LCD_DATA 0x95 /* LCD: OUT[63] */ | ||
| 43 | #define REPORT_LCD_CMD_DATA 0x96 /* LCD: OUT[63] */ | ||
| 44 | #define REPORT_EE_READ 0xa3 /* LCD: OUT[63] */ | ||
| 45 | #define REPORT_EE_WRITE 0xa4 /* LCD: OUT[63] */ | ||
| 46 | #define REPORT_ERASE_MEMORY 0xb2 /* LCD: OUT[2] */ | ||
| 47 | #define REPORT_READ_MEMORY 0xb3 /* LCD: OUT[3] */ | ||
| 48 | #define REPORT_WRITE_MEMORY 0xb4 /* LCD: OUT[63] */ | ||
| 49 | #define REPORT_SPLASH_RESTART 0xc1 /* LCD: OUT[1] */ | ||
| 50 | #define REPORT_EXIT_KEYBOARD 0xef /* LCD: OUT[2] */ | ||
| 51 | #define REPORT_VERSION 0xf1 /* LCD: IN[2],OUT[1] Bootloader: IN[2],OUT[1] */ | ||
| 52 | #define REPORT_BL_ERASE_MEMORY 0xf2 /* Bootloader: IN[36],OUT[4] */ | ||
| 53 | #define REPORT_BL_READ_MEMORY 0xf3 /* Bootloader: IN[36],OUT[4] */ | ||
| 54 | #define REPORT_BL_WRITE_MEMORY 0xf4 /* Bootloader: IN[36],OUT[36] */ | ||
| 55 | #define REPORT_DEVID 0xf5 /* LCD: IN[5], OUT[1] Bootloader: IN[5],OUT[1] */ | ||
| 56 | #define REPORT_SPLASH_SIZE 0xf6 /* LCD: IN[4], OUT[1] */ | ||
| 57 | #define REPORT_HOOK_VERSION 0xf7 /* LCD: IN[2], OUT[1] */ | ||
| 58 | #define REPORT_EXIT_FLASHER 0xff /* Bootloader: OUT[2] */ | ||
| 59 | |||
| 60 | /* Description of in-progress IO operation, used for operations | ||
| 61 | * that trigger response from device */ | ||
| 62 | struct picolcd_pending { | ||
| 63 | struct hid_report *out_report; | ||
| 64 | struct hid_report *in_report; | ||
| 65 | struct completion ready; | ||
| 66 | int raw_size; | ||
| 67 | u8 raw_data[64]; | ||
| 68 | }; | ||
| 69 | |||
| 70 | |||
| 71 | #define PICOLCD_KEYS 17 | ||
| 72 | |||
| 73 | /* Per device data structure */ | ||
| 74 | struct picolcd_data { | ||
| 75 | struct hid_device *hdev; | ||
| 76 | #ifdef CONFIG_DEBUG_FS | ||
| 77 | struct dentry *debug_reset; | ||
| 78 | struct dentry *debug_eeprom; | ||
| 79 | struct dentry *debug_flash; | ||
| 80 | struct mutex mutex_flash; | ||
| 81 | int addr_sz; | ||
| 82 | #endif | ||
| 83 | u8 version[2]; | ||
| 84 | unsigned short opmode_delay; | ||
| 85 | /* input stuff */ | ||
| 86 | u8 pressed_keys[2]; | ||
| 87 | struct input_dev *input_keys; | ||
| 88 | #ifdef CONFIG_HID_PICOLCD_CIR | ||
| 89 | struct rc_dev *rc_dev; | ||
| 90 | #endif | ||
| 91 | unsigned short keycode[PICOLCD_KEYS]; | ||
| 92 | |||
| 93 | #ifdef CONFIG_HID_PICOLCD_FB | ||
| 94 | /* Framebuffer stuff */ | ||
| 95 | struct fb_info *fb_info; | ||
| 96 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
| 97 | #ifdef CONFIG_HID_PICOLCD_LCD | ||
| 98 | struct lcd_device *lcd; | ||
| 99 | u8 lcd_contrast; | ||
| 100 | #endif /* CONFIG_HID_PICOLCD_LCD */ | ||
| 101 | #ifdef CONFIG_HID_PICOLCD_BACKLIGHT | ||
| 102 | struct backlight_device *backlight; | ||
| 103 | u8 lcd_brightness; | ||
| 104 | u8 lcd_power; | ||
| 105 | #endif /* CONFIG_HID_PICOLCD_BACKLIGHT */ | ||
| 106 | #ifdef CONFIG_HID_PICOLCD_LEDS | ||
| 107 | /* LED stuff */ | ||
| 108 | u8 led_state; | ||
| 109 | struct led_classdev *led[8]; | ||
| 110 | #endif /* CONFIG_HID_PICOLCD_LEDS */ | ||
| 111 | |||
| 112 | /* Housekeeping stuff */ | ||
| 113 | spinlock_t lock; | ||
| 114 | struct mutex mutex; | ||
| 115 | struct picolcd_pending *pending; | ||
| 116 | int status; | ||
| 117 | #define PICOLCD_BOOTLOADER 1 | ||
| 118 | #define PICOLCD_FAILED 2 | ||
| 119 | #define PICOLCD_CIR_SHUN 4 | ||
| 120 | }; | ||
| 121 | |||
| 122 | #ifdef CONFIG_HID_PICOLCD_FB | ||
| 123 | struct picolcd_fb_data { | ||
| 124 | /* Framebuffer stuff */ | ||
| 125 | spinlock_t lock; | ||
| 126 | struct picolcd_data *picolcd; | ||
| 127 | u8 update_rate; | ||
| 128 | u8 bpp; | ||
| 129 | u8 force; | ||
| 130 | u8 ready; | ||
| 131 | u8 *vbitmap; /* local copy of what was sent to PicoLCD */ | ||
| 132 | u8 *bitmap; /* framebuffer */ | ||
| 133 | }; | ||
| 134 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
| 135 | |||
| 136 | /* Find a given report */ | ||
| 137 | #define picolcd_in_report(id, dev) picolcd_report(id, dev, HID_INPUT_REPORT) | ||
| 138 | #define picolcd_out_report(id, dev) picolcd_report(id, dev, HID_OUTPUT_REPORT) | ||
| 139 | |||
| 140 | struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir); | ||
| 141 | |||
| 142 | #ifdef CONFIG_DEBUG_FS | ||
| 143 | void picolcd_debug_out_report(struct picolcd_data *data, | ||
| 144 | struct hid_device *hdev, struct hid_report *report); | ||
| 145 | #define usbhid_submit_report(a, b, c) \ | ||
| 146 | do { \ | ||
| 147 | picolcd_debug_out_report(hid_get_drvdata(a), a, b); \ | ||
| 148 | usbhid_submit_report(a, b, c); \ | ||
| 149 | } while (0) | ||
| 150 | |||
| 151 | void picolcd_debug_raw_event(struct picolcd_data *data, | ||
| 152 | struct hid_device *hdev, struct hid_report *report, | ||
| 153 | u8 *raw_data, int size); | ||
| 154 | |||
| 155 | void picolcd_init_devfs(struct picolcd_data *data, | ||
| 156 | struct hid_report *eeprom_r, struct hid_report *eeprom_w, | ||
| 157 | struct hid_report *flash_r, struct hid_report *flash_w, | ||
| 158 | struct hid_report *reset); | ||
| 159 | |||
| 160 | void picolcd_exit_devfs(struct picolcd_data *data); | ||
| 161 | #else | ||
| 162 | static inline void picolcd_debug_out_report(struct picolcd_data *data, | ||
| 163 | struct hid_device *hdev, struct hid_report *report) | ||
| 164 | { | ||
| 165 | } | ||
| 166 | static inline void picolcd_debug_raw_event(struct picolcd_data *data, | ||
| 167 | struct hid_device *hdev, struct hid_report *report, | ||
| 168 | u8 *raw_data, int size) | ||
| 169 | { | ||
| 170 | } | ||
| 171 | static inline void picolcd_init_devfs(struct picolcd_data *data, | ||
| 172 | struct hid_report *eeprom_r, struct hid_report *eeprom_w, | ||
| 173 | struct hid_report *flash_r, struct hid_report *flash_w, | ||
| 174 | struct hid_report *reset) | ||
| 175 | { | ||
| 176 | } | ||
| 177 | static inline void picolcd_exit_devfs(struct picolcd_data *data) | ||
| 178 | { | ||
| 179 | } | ||
| 180 | #endif /* CONFIG_DEBUG_FS */ | ||
| 181 | |||
| 182 | |||
| 183 | #ifdef CONFIG_HID_PICOLCD_FB | ||
| 184 | int picolcd_fb_reset(struct picolcd_data *data, int clear); | ||
| 185 | |||
| 186 | int picolcd_init_framebuffer(struct picolcd_data *data); | ||
| 187 | |||
| 188 | void picolcd_exit_framebuffer(struct picolcd_data *data); | ||
| 189 | |||
| 190 | void picolcd_fb_refresh(struct picolcd_data *data); | ||
| 191 | #define picolcd_fbinfo(d) ((d)->fb_info) | ||
| 192 | #else | ||
| 193 | static inline int picolcd_fb_reset(struct picolcd_data *data, int clear) | ||
| 194 | { | ||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | static inline int picolcd_init_framebuffer(struct picolcd_data *data) | ||
| 198 | { | ||
| 199 | return 0; | ||
| 200 | } | ||
| 201 | static inline void picolcd_exit_framebuffer(struct picolcd_data *data) | ||
| 202 | { | ||
| 203 | } | ||
| 204 | static inline void picolcd_fb_refresh(struct picolcd_data *data) | ||
| 205 | { | ||
| 206 | } | ||
| 207 | #define picolcd_fbinfo(d) NULL | ||
| 208 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
| 209 | |||
| 210 | |||
| 211 | #ifdef CONFIG_HID_PICOLCD_BACKLIGHT | ||
| 212 | int picolcd_init_backlight(struct picolcd_data *data, | ||
| 213 | struct hid_report *report); | ||
| 214 | |||
| 215 | void picolcd_exit_backlight(struct picolcd_data *data); | ||
| 216 | |||
| 217 | int picolcd_resume_backlight(struct picolcd_data *data); | ||
| 218 | |||
| 219 | void picolcd_suspend_backlight(struct picolcd_data *data); | ||
| 220 | #else | ||
| 221 | static inline int picolcd_init_backlight(struct picolcd_data *data, | ||
| 222 | struct hid_report *report) | ||
| 223 | { | ||
| 224 | return 0; | ||
| 225 | } | ||
| 226 | static inline void picolcd_exit_backlight(struct picolcd_data *data) | ||
| 227 | { | ||
| 228 | } | ||
| 229 | static inline int picolcd_resume_backlight(struct picolcd_data *data) | ||
| 230 | { | ||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | static inline void picolcd_suspend_backlight(struct picolcd_data *data) | ||
| 234 | { | ||
| 235 | } | ||
| 236 | |||
| 237 | #endif /* CONFIG_HID_PICOLCD_BACKLIGHT */ | ||
| 238 | |||
| 239 | |||
| 240 | #ifdef CONFIG_HID_PICOLCD_LCD | ||
| 241 | int picolcd_init_lcd(struct picolcd_data *data, | ||
| 242 | struct hid_report *report); | ||
| 243 | |||
| 244 | void picolcd_exit_lcd(struct picolcd_data *data); | ||
| 245 | |||
| 246 | int picolcd_resume_lcd(struct picolcd_data *data); | ||
| 247 | #else | ||
| 248 | static inline int picolcd_init_lcd(struct picolcd_data *data, | ||
| 249 | struct hid_report *report) | ||
| 250 | { | ||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | static inline void picolcd_exit_lcd(struct picolcd_data *data) | ||
| 254 | { | ||
| 255 | } | ||
| 256 | static inline int picolcd_resume_lcd(struct picolcd_data *data) | ||
| 257 | { | ||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | #endif /* CONFIG_HID_PICOLCD_LCD */ | ||
| 261 | |||
| 262 | |||
| 263 | #ifdef CONFIG_HID_PICOLCD_LEDS | ||
| 264 | int picolcd_init_leds(struct picolcd_data *data, | ||
| 265 | struct hid_report *report); | ||
| 266 | |||
| 267 | void picolcd_exit_leds(struct picolcd_data *data); | ||
| 268 | |||
| 269 | void picolcd_leds_set(struct picolcd_data *data); | ||
| 270 | #else | ||
| 271 | static inline int picolcd_init_leds(struct picolcd_data *data, | ||
| 272 | struct hid_report *report) | ||
| 273 | { | ||
| 274 | return 0; | ||
| 275 | } | ||
| 276 | static inline void picolcd_exit_leds(struct picolcd_data *data) | ||
| 277 | { | ||
| 278 | } | ||
| 279 | static inline void picolcd_leds_set(struct picolcd_data *data) | ||
| 280 | { | ||
| 281 | } | ||
| 282 | #endif /* CONFIG_HID_PICOLCD_LEDS */ | ||
| 283 | |||
| 284 | |||
| 285 | #ifdef CONFIG_HID_PICOLCD_CIR | ||
| 286 | int picolcd_raw_cir(struct picolcd_data *data, | ||
| 287 | struct hid_report *report, u8 *raw_data, int size); | ||
| 288 | |||
| 289 | int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report); | ||
| 290 | |||
| 291 | void picolcd_exit_cir(struct picolcd_data *data); | ||
| 292 | #else | ||
| 293 | static inline int picolcd_raw_cir(struct picolcd_data *data, | ||
| 294 | struct hid_report *report, u8 *raw_data, int size) | ||
| 295 | { | ||
| 296 | return 1; | ||
| 297 | } | ||
| 298 | static inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report) | ||
| 299 | { | ||
| 300 | return 0; | ||
| 301 | } | ||
| 302 | static inline void picolcd_exit_cir(struct picolcd_data *data) | ||
| 303 | { | ||
| 304 | } | ||
| 305 | #endif /* CONFIG_HID_PICOLCD_LIRC */ | ||
| 306 | |||
| 307 | int picolcd_reset(struct hid_device *hdev); | ||
| 308 | struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev, | ||
| 309 | int report_id, const u8 *raw_data, int size); | ||
diff --git a/drivers/hid/hid-picolcd_backlight.c b/drivers/hid/hid-picolcd_backlight.c new file mode 100644 index 000000000000..b91f30945f9c --- /dev/null +++ b/drivers/hid/hid-picolcd_backlight.c | |||
| @@ -0,0 +1,122 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> * | ||
| 3 | * * | ||
| 4 | * Based on Logitech G13 driver (v0.4) * | ||
| 5 | * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * | ||
| 6 | * * | ||
| 7 | * This program is free software: you can redistribute it and/or modify * | ||
| 8 | * it under the terms of the GNU General Public License as published by * | ||
| 9 | * the Free Software Foundation, version 2 of the License. * | ||
| 10 | * * | ||
| 11 | * This driver is distributed in the hope that it will be useful, but * | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * | ||
| 14 | * General Public License for more details. * | ||
| 15 | * * | ||
| 16 | * You should have received a copy of the GNU General Public License * | ||
| 17 | * along with this software. If not see <http://www.gnu.org/licenses/>. * | ||
| 18 | ***************************************************************************/ | ||
| 19 | |||
| 20 | #include <linux/hid.h> | ||
| 21 | #include "usbhid/usbhid.h" | ||
| 22 | #include <linux/usb.h> | ||
| 23 | |||
| 24 | #include <linux/fb.h> | ||
| 25 | #include <linux/backlight.h> | ||
| 26 | |||
| 27 | #include "hid-picolcd.h" | ||
| 28 | |||
| 29 | static int picolcd_get_brightness(struct backlight_device *bdev) | ||
| 30 | { | ||
| 31 | struct picolcd_data *data = bl_get_data(bdev); | ||
| 32 | return data->lcd_brightness; | ||
| 33 | } | ||
| 34 | |||
| 35 | static int picolcd_set_brightness(struct backlight_device *bdev) | ||
| 36 | { | ||
| 37 | struct picolcd_data *data = bl_get_data(bdev); | ||
| 38 | struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev); | ||
| 39 | unsigned long flags; | ||
| 40 | |||
| 41 | if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) | ||
| 42 | return -ENODEV; | ||
| 43 | |||
| 44 | data->lcd_brightness = bdev->props.brightness & 0x0ff; | ||
| 45 | data->lcd_power = bdev->props.power; | ||
| 46 | spin_lock_irqsave(&data->lock, flags); | ||
| 47 | hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0); | ||
| 48 | if (!(data->status & PICOLCD_FAILED)) | ||
| 49 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
| 50 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 51 | return 0; | ||
| 52 | } | ||
| 53 | |||
| 54 | static int picolcd_check_bl_fb(struct backlight_device *bdev, struct fb_info *fb) | ||
| 55 | { | ||
| 56 | return fb && fb == picolcd_fbinfo((struct picolcd_data *)bl_get_data(bdev)); | ||
| 57 | } | ||
| 58 | |||
| 59 | static const struct backlight_ops picolcd_blops = { | ||
| 60 | .update_status = picolcd_set_brightness, | ||
| 61 | .get_brightness = picolcd_get_brightness, | ||
| 62 | .check_fb = picolcd_check_bl_fb, | ||
| 63 | }; | ||
| 64 | |||
| 65 | int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report) | ||
| 66 | { | ||
| 67 | struct device *dev = &data->hdev->dev; | ||
| 68 | struct backlight_device *bdev; | ||
| 69 | struct backlight_properties props; | ||
| 70 | if (!report) | ||
| 71 | return -ENODEV; | ||
| 72 | if (report->maxfield != 1 || report->field[0]->report_count != 1 || | ||
| 73 | report->field[0]->report_size != 8) { | ||
| 74 | dev_err(dev, "unsupported BRIGHTNESS report"); | ||
| 75 | return -EINVAL; | ||
| 76 | } | ||
| 77 | |||
| 78 | memset(&props, 0, sizeof(props)); | ||
| 79 | props.type = BACKLIGHT_RAW; | ||
| 80 | props.max_brightness = 0xff; | ||
| 81 | bdev = backlight_device_register(dev_name(dev), dev, data, | ||
| 82 | &picolcd_blops, &props); | ||
| 83 | if (IS_ERR(bdev)) { | ||
| 84 | dev_err(dev, "failed to register backlight\n"); | ||
| 85 | return PTR_ERR(bdev); | ||
| 86 | } | ||
| 87 | bdev->props.brightness = 0xff; | ||
| 88 | data->lcd_brightness = 0xff; | ||
| 89 | data->backlight = bdev; | ||
| 90 | picolcd_set_brightness(bdev); | ||
| 91 | return 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | void picolcd_exit_backlight(struct picolcd_data *data) | ||
| 95 | { | ||
| 96 | struct backlight_device *bdev = data->backlight; | ||
| 97 | |||
| 98 | data->backlight = NULL; | ||
| 99 | if (bdev) | ||
| 100 | backlight_device_unregister(bdev); | ||
| 101 | } | ||
| 102 | |||
| 103 | int picolcd_resume_backlight(struct picolcd_data *data) | ||
| 104 | { | ||
| 105 | if (!data->backlight) | ||
| 106 | return 0; | ||
| 107 | return picolcd_set_brightness(data->backlight); | ||
| 108 | } | ||
| 109 | |||
| 110 | #ifdef CONFIG_PM | ||
| 111 | void picolcd_suspend_backlight(struct picolcd_data *data) | ||
| 112 | { | ||
| 113 | int bl_power = data->lcd_power; | ||
| 114 | if (!data->backlight) | ||
| 115 | return; | ||
| 116 | |||
| 117 | data->backlight->props.power = FB_BLANK_POWERDOWN; | ||
| 118 | picolcd_set_brightness(data->backlight); | ||
| 119 | data->lcd_power = data->backlight->props.power = bl_power; | ||
| 120 | } | ||
| 121 | #endif /* CONFIG_PM */ | ||
| 122 | |||
diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c new file mode 100644 index 000000000000..13ca9191b630 --- /dev/null +++ b/drivers/hid/hid-picolcd_cir.c | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> * | ||
| 3 | * * | ||
| 4 | * Based on Logitech G13 driver (v0.4) * | ||
| 5 | * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * | ||
| 6 | * * | ||
| 7 | * This program is free software: you can redistribute it and/or modify * | ||
| 8 | * it under the terms of the GNU General Public License as published by * | ||
| 9 | * the Free Software Foundation, version 2 of the License. * | ||
| 10 | * * | ||
| 11 | * This driver is distributed in the hope that it will be useful, but * | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * | ||
| 14 | * General Public License for more details. * | ||
| 15 | * * | ||
| 16 | * You should have received a copy of the GNU General Public License * | ||
| 17 | * along with this software. If not see <http://www.gnu.org/licenses/>. * | ||
| 18 | ***************************************************************************/ | ||
| 19 | |||
| 20 | #include <linux/hid.h> | ||
| 21 | #include <linux/hid-debug.h> | ||
| 22 | #include <linux/input.h> | ||
| 23 | #include "hid-ids.h" | ||
| 24 | #include "usbhid/usbhid.h" | ||
| 25 | #include <linux/usb.h> | ||
| 26 | |||
| 27 | #include <linux/fb.h> | ||
| 28 | #include <linux/vmalloc.h> | ||
| 29 | #include <linux/backlight.h> | ||
| 30 | #include <linux/lcd.h> | ||
| 31 | |||
| 32 | #include <linux/leds.h> | ||
| 33 | |||
| 34 | #include <linux/seq_file.h> | ||
| 35 | #include <linux/debugfs.h> | ||
| 36 | |||
| 37 | #include <linux/completion.h> | ||
| 38 | #include <linux/uaccess.h> | ||
| 39 | #include <linux/module.h> | ||
| 40 | #include <media/rc-core.h> | ||
| 41 | |||
| 42 | #include "hid-picolcd.h" | ||
| 43 | |||
| 44 | |||
| 45 | int picolcd_raw_cir(struct picolcd_data *data, | ||
| 46 | struct hid_report *report, u8 *raw_data, int size) | ||
| 47 | { | ||
| 48 | unsigned long flags; | ||
| 49 | int i, w, sz; | ||
| 50 | DEFINE_IR_RAW_EVENT(rawir); | ||
| 51 | |||
| 52 | /* ignore if rc_dev is NULL or status is shunned */ | ||
| 53 | spin_lock_irqsave(&data->lock, flags); | ||
| 54 | if (!data->rc_dev || (data->status & PICOLCD_CIR_SHUN)) { | ||
| 55 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 56 | return 1; | ||
| 57 | } | ||
| 58 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 59 | |||
| 60 | /* PicoLCD USB packets contain 16-bit intervals in network order, | ||
| 61 | * with value negated for pulse. Intervals are in microseconds. | ||
| 62 | * | ||
| 63 | * Note: some userspace LIRC code for PicoLCD says negated values | ||
| 64 | * for space - is it a matter of IR chip? (pulse for my TSOP2236) | ||
| 65 | * | ||
| 66 | * In addition, the first interval seems to be around 15000 + base | ||
| 67 | * interval for non-first report of IR data - thus the quirk below | ||
| 68 | * to get RC_CODE to understand Sony and JVC remotes I have at hand | ||
| 69 | */ | ||
| 70 | sz = size > 0 ? min((int)raw_data[0], size-1) : 0; | ||
| 71 | for (i = 0; i+1 < sz; i += 2) { | ||
| 72 | init_ir_raw_event(&rawir); | ||
| 73 | w = (raw_data[i] << 8) | (raw_data[i+1]); | ||
| 74 | rawir.pulse = !!(w & 0x8000); | ||
| 75 | rawir.duration = US_TO_NS(rawir.pulse ? (65536 - w) : w); | ||
| 76 | /* Quirk!! - see above */ | ||
| 77 | if (i == 0 && rawir.duration > 15000000) | ||
| 78 | rawir.duration -= 15000000; | ||
| 79 | ir_raw_event_store(data->rc_dev, &rawir); | ||
| 80 | } | ||
| 81 | ir_raw_event_handle(data->rc_dev); | ||
| 82 | |||
| 83 | return 1; | ||
| 84 | } | ||
| 85 | |||
| 86 | static int picolcd_cir_open(struct rc_dev *dev) | ||
| 87 | { | ||
| 88 | struct picolcd_data *data = dev->priv; | ||
| 89 | unsigned long flags; | ||
| 90 | |||
| 91 | spin_lock_irqsave(&data->lock, flags); | ||
| 92 | data->status &= ~PICOLCD_CIR_SHUN; | ||
| 93 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | static void picolcd_cir_close(struct rc_dev *dev) | ||
| 98 | { | ||
| 99 | struct picolcd_data *data = dev->priv; | ||
| 100 | unsigned long flags; | ||
| 101 | |||
| 102 | spin_lock_irqsave(&data->lock, flags); | ||
| 103 | data->status |= PICOLCD_CIR_SHUN; | ||
| 104 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 105 | } | ||
| 106 | |||
| 107 | /* initialize CIR input device */ | ||
| 108 | int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report) | ||
| 109 | { | ||
| 110 | struct rc_dev *rdev; | ||
| 111 | int ret = 0; | ||
| 112 | |||
| 113 | rdev = rc_allocate_device(); | ||
| 114 | if (!rdev) | ||
| 115 | return -ENOMEM; | ||
| 116 | |||
| 117 | rdev->priv = data; | ||
| 118 | rdev->driver_type = RC_DRIVER_IR_RAW; | ||
| 119 | rdev->allowed_protos = RC_TYPE_ALL; | ||
| 120 | rdev->open = picolcd_cir_open; | ||
| 121 | rdev->close = picolcd_cir_close; | ||
| 122 | rdev->input_name = data->hdev->name; | ||
| 123 | rdev->input_phys = data->hdev->phys; | ||
| 124 | rdev->input_id.bustype = data->hdev->bus; | ||
| 125 | rdev->input_id.vendor = data->hdev->vendor; | ||
| 126 | rdev->input_id.product = data->hdev->product; | ||
| 127 | rdev->input_id.version = data->hdev->version; | ||
| 128 | rdev->dev.parent = &data->hdev->dev; | ||
| 129 | rdev->driver_name = PICOLCD_NAME; | ||
| 130 | rdev->map_name = RC_MAP_RC6_MCE; | ||
| 131 | rdev->timeout = MS_TO_NS(100); | ||
| 132 | rdev->rx_resolution = US_TO_NS(1); | ||
| 133 | |||
| 134 | ret = rc_register_device(rdev); | ||
| 135 | if (ret) | ||
| 136 | goto err; | ||
| 137 | data->rc_dev = rdev; | ||
| 138 | return 0; | ||
| 139 | |||
| 140 | err: | ||
| 141 | rc_free_device(rdev); | ||
| 142 | return ret; | ||
| 143 | } | ||
| 144 | |||
| 145 | void picolcd_exit_cir(struct picolcd_data *data) | ||
| 146 | { | ||
| 147 | struct rc_dev *rdev = data->rc_dev; | ||
| 148 | |||
| 149 | data->rc_dev = NULL; | ||
| 150 | rc_unregister_device(rdev); | ||
| 151 | } | ||
| 152 | |||
diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c new file mode 100644 index 000000000000..86df26e58aba --- /dev/null +++ b/drivers/hid/hid-picolcd_core.c | |||
| @@ -0,0 +1,689 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> * | ||
| 3 | * * | ||
| 4 | * Based on Logitech G13 driver (v0.4) * | ||
| 5 | * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * | ||
| 6 | * * | ||
| 7 | * This program is free software: you can redistribute it and/or modify * | ||
| 8 | * it under the terms of the GNU General Public License as published by * | ||
| 9 | * the Free Software Foundation, version 2 of the License. * | ||
| 10 | * * | ||
| 11 | * This driver is distributed in the hope that it will be useful, but * | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * | ||
| 14 | * General Public License for more details. * | ||
| 15 | * * | ||
| 16 | * You should have received a copy of the GNU General Public License * | ||
| 17 | * along with this software. If not see <http://www.gnu.org/licenses/>. * | ||
| 18 | ***************************************************************************/ | ||
| 19 | |||
| 20 | #include <linux/hid.h> | ||
| 21 | #include <linux/hid-debug.h> | ||
| 22 | #include <linux/input.h> | ||
| 23 | #include "hid-ids.h" | ||
| 24 | #include "usbhid/usbhid.h" | ||
| 25 | #include <linux/usb.h> | ||
| 26 | |||
| 27 | #include <linux/fb.h> | ||
| 28 | #include <linux/vmalloc.h> | ||
| 29 | |||
| 30 | #include <linux/completion.h> | ||
| 31 | #include <linux/uaccess.h> | ||
| 32 | #include <linux/module.h> | ||
| 33 | |||
| 34 | #include "hid-picolcd.h" | ||
| 35 | |||
| 36 | |||
| 37 | /* Input device | ||
| 38 | * | ||
| 39 | * The PicoLCD has an IR receiver header, a built-in keypad with 5 keys | ||
| 40 | * and header for 4x4 key matrix. The built-in keys are part of the matrix. | ||
| 41 | */ | ||
| 42 | static const unsigned short def_keymap[PICOLCD_KEYS] = { | ||
| 43 | KEY_RESERVED, /* none */ | ||
| 44 | KEY_BACK, /* col 4 + row 1 */ | ||
| 45 | KEY_HOMEPAGE, /* col 3 + row 1 */ | ||
| 46 | KEY_RESERVED, /* col 2 + row 1 */ | ||
| 47 | KEY_RESERVED, /* col 1 + row 1 */ | ||
| 48 | KEY_SCROLLUP, /* col 4 + row 2 */ | ||
| 49 | KEY_OK, /* col 3 + row 2 */ | ||
| 50 | KEY_SCROLLDOWN, /* col 2 + row 2 */ | ||
| 51 | KEY_RESERVED, /* col 1 + row 2 */ | ||
| 52 | KEY_RESERVED, /* col 4 + row 3 */ | ||
| 53 | KEY_RESERVED, /* col 3 + row 3 */ | ||
| 54 | KEY_RESERVED, /* col 2 + row 3 */ | ||
| 55 | KEY_RESERVED, /* col 1 + row 3 */ | ||
| 56 | KEY_RESERVED, /* col 4 + row 4 */ | ||
| 57 | KEY_RESERVED, /* col 3 + row 4 */ | ||
| 58 | KEY_RESERVED, /* col 2 + row 4 */ | ||
| 59 | KEY_RESERVED, /* col 1 + row 4 */ | ||
| 60 | }; | ||
| 61 | |||
| 62 | |||
| 63 | /* Find a given report */ | ||
| 64 | struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir) | ||
| 65 | { | ||
| 66 | struct list_head *feature_report_list = &hdev->report_enum[dir].report_list; | ||
| 67 | struct hid_report *report = NULL; | ||
| 68 | |||
| 69 | list_for_each_entry(report, feature_report_list, list) { | ||
| 70 | if (report->id == id) | ||
| 71 | return report; | ||
| 72 | } | ||
| 73 | hid_warn(hdev, "No report with id 0x%x found\n", id); | ||
| 74 | return NULL; | ||
| 75 | } | ||
| 76 | |||
| 77 | /* Submit a report and wait for a reply from device - if device fades away | ||
| 78 | * or does not respond in time, return NULL */ | ||
| 79 | struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev, | ||
| 80 | int report_id, const u8 *raw_data, int size) | ||
| 81 | { | ||
| 82 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
| 83 | struct picolcd_pending *work; | ||
| 84 | struct hid_report *report = picolcd_out_report(report_id, hdev); | ||
| 85 | unsigned long flags; | ||
| 86 | int i, j, k; | ||
| 87 | |||
| 88 | if (!report || !data) | ||
| 89 | return NULL; | ||
| 90 | if (data->status & PICOLCD_FAILED) | ||
| 91 | return NULL; | ||
| 92 | work = kzalloc(sizeof(*work), GFP_KERNEL); | ||
| 93 | if (!work) | ||
| 94 | return NULL; | ||
| 95 | |||
| 96 | init_completion(&work->ready); | ||
| 97 | work->out_report = report; | ||
| 98 | work->in_report = NULL; | ||
| 99 | work->raw_size = 0; | ||
| 100 | |||
| 101 | mutex_lock(&data->mutex); | ||
| 102 | spin_lock_irqsave(&data->lock, flags); | ||
| 103 | for (i = k = 0; i < report->maxfield; i++) | ||
| 104 | for (j = 0; j < report->field[i]->report_count; j++) { | ||
| 105 | hid_set_field(report->field[i], j, k < size ? raw_data[k] : 0); | ||
| 106 | k++; | ||
| 107 | } | ||
| 108 | if (data->status & PICOLCD_FAILED) { | ||
| 109 | kfree(work); | ||
| 110 | work = NULL; | ||
| 111 | } else { | ||
| 112 | data->pending = work; | ||
| 113 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
| 114 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 115 | wait_for_completion_interruptible_timeout(&work->ready, HZ*2); | ||
| 116 | spin_lock_irqsave(&data->lock, flags); | ||
| 117 | data->pending = NULL; | ||
| 118 | } | ||
| 119 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 120 | mutex_unlock(&data->mutex); | ||
| 121 | return work; | ||
| 122 | } | ||
| 123 | |||
| 124 | /* | ||
| 125 | * input class device | ||
| 126 | */ | ||
| 127 | static int picolcd_raw_keypad(struct picolcd_data *data, | ||
| 128 | struct hid_report *report, u8 *raw_data, int size) | ||
| 129 | { | ||
| 130 | /* | ||
| 131 | * Keypad event | ||
| 132 | * First and second data bytes list currently pressed keys, | ||
| 133 | * 0x00 means no key and at most 2 keys may be pressed at same time | ||
| 134 | */ | ||
| 135 | int i, j; | ||
| 136 | |||
| 137 | /* determine newly pressed keys */ | ||
| 138 | for (i = 0; i < size; i++) { | ||
| 139 | unsigned int key_code; | ||
| 140 | if (raw_data[i] == 0) | ||
| 141 | continue; | ||
| 142 | for (j = 0; j < sizeof(data->pressed_keys); j++) | ||
| 143 | if (data->pressed_keys[j] == raw_data[i]) | ||
| 144 | goto key_already_down; | ||
| 145 | for (j = 0; j < sizeof(data->pressed_keys); j++) | ||
| 146 | if (data->pressed_keys[j] == 0) { | ||
| 147 | data->pressed_keys[j] = raw_data[i]; | ||
| 148 | break; | ||
| 149 | } | ||
| 150 | input_event(data->input_keys, EV_MSC, MSC_SCAN, raw_data[i]); | ||
| 151 | if (raw_data[i] < PICOLCD_KEYS) | ||
| 152 | key_code = data->keycode[raw_data[i]]; | ||
| 153 | else | ||
| 154 | key_code = KEY_UNKNOWN; | ||
| 155 | if (key_code != KEY_UNKNOWN) { | ||
| 156 | dbg_hid(PICOLCD_NAME " got key press for %u:%d", | ||
| 157 | raw_data[i], key_code); | ||
| 158 | input_report_key(data->input_keys, key_code, 1); | ||
| 159 | } | ||
| 160 | input_sync(data->input_keys); | ||
| 161 | key_already_down: | ||
| 162 | continue; | ||
| 163 | } | ||
| 164 | |||
| 165 | /* determine newly released keys */ | ||
| 166 | for (j = 0; j < sizeof(data->pressed_keys); j++) { | ||
| 167 | unsigned int key_code; | ||
| 168 | if (data->pressed_keys[j] == 0) | ||
| 169 | continue; | ||
| 170 | for (i = 0; i < size; i++) | ||
| 171 | if (data->pressed_keys[j] == raw_data[i]) | ||
| 172 | goto key_still_down; | ||
| 173 | input_event(data->input_keys, EV_MSC, MSC_SCAN, data->pressed_keys[j]); | ||
| 174 | if (data->pressed_keys[j] < PICOLCD_KEYS) | ||
| 175 | key_code = data->keycode[data->pressed_keys[j]]; | ||
| 176 | else | ||
| 177 | key_code = KEY_UNKNOWN; | ||
| 178 | if (key_code != KEY_UNKNOWN) { | ||
| 179 | dbg_hid(PICOLCD_NAME " got key release for %u:%d", | ||
| 180 | data->pressed_keys[j], key_code); | ||
| 181 | input_report_key(data->input_keys, key_code, 0); | ||
| 182 | } | ||
| 183 | input_sync(data->input_keys); | ||
| 184 | data->pressed_keys[j] = 0; | ||
| 185 | key_still_down: | ||
| 186 | continue; | ||
| 187 | } | ||
| 188 | return 1; | ||
| 189 | } | ||
| 190 | |||
| 191 | static int picolcd_check_version(struct hid_device *hdev) | ||
| 192 | { | ||
| 193 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
| 194 | struct picolcd_pending *verinfo; | ||
| 195 | int ret = 0; | ||
| 196 | |||
| 197 | if (!data) | ||
| 198 | return -ENODEV; | ||
| 199 | |||
| 200 | verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0); | ||
| 201 | if (!verinfo) { | ||
| 202 | hid_err(hdev, "no version response from PicoLCD\n"); | ||
| 203 | return -ENODEV; | ||
| 204 | } | ||
| 205 | |||
| 206 | if (verinfo->raw_size == 2) { | ||
| 207 | data->version[0] = verinfo->raw_data[1]; | ||
| 208 | data->version[1] = verinfo->raw_data[0]; | ||
| 209 | if (data->status & PICOLCD_BOOTLOADER) { | ||
| 210 | hid_info(hdev, "PicoLCD, bootloader version %d.%d\n", | ||
| 211 | verinfo->raw_data[1], verinfo->raw_data[0]); | ||
| 212 | } else { | ||
| 213 | hid_info(hdev, "PicoLCD, firmware version %d.%d\n", | ||
| 214 | verinfo->raw_data[1], verinfo->raw_data[0]); | ||
| 215 | } | ||
| 216 | } else { | ||
| 217 | hid_err(hdev, "confused, got unexpected version response from PicoLCD\n"); | ||
| 218 | ret = -EINVAL; | ||
| 219 | } | ||
| 220 | kfree(verinfo); | ||
| 221 | return ret; | ||
| 222 | } | ||
| 223 | |||
| 224 | /* | ||
| 225 | * Reset our device and wait for answer to VERSION request | ||
| 226 | */ | ||
| 227 | int picolcd_reset(struct hid_device *hdev) | ||
| 228 | { | ||
| 229 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
| 230 | struct hid_report *report = picolcd_out_report(REPORT_RESET, hdev); | ||
| 231 | unsigned long flags; | ||
| 232 | int error; | ||
| 233 | |||
| 234 | if (!data || !report || report->maxfield != 1) | ||
| 235 | return -ENODEV; | ||
| 236 | |||
| 237 | spin_lock_irqsave(&data->lock, flags); | ||
| 238 | if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER) | ||
| 239 | data->status |= PICOLCD_BOOTLOADER; | ||
| 240 | |||
| 241 | /* perform the reset */ | ||
| 242 | hid_set_field(report->field[0], 0, 1); | ||
| 243 | if (data->status & PICOLCD_FAILED) { | ||
| 244 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 245 | return -ENODEV; | ||
| 246 | } | ||
| 247 | usbhid_submit_report(hdev, report, USB_DIR_OUT); | ||
| 248 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 249 | |||
| 250 | error = picolcd_check_version(hdev); | ||
| 251 | if (error) | ||
| 252 | return error; | ||
| 253 | |||
| 254 | picolcd_resume_lcd(data); | ||
| 255 | picolcd_resume_backlight(data); | ||
| 256 | picolcd_fb_refresh(data); | ||
| 257 | picolcd_leds_set(data); | ||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | |||
| 261 | /* | ||
| 262 | * The "operation_mode" sysfs attribute | ||
| 263 | */ | ||
| 264 | static ssize_t picolcd_operation_mode_show(struct device *dev, | ||
| 265 | struct device_attribute *attr, char *buf) | ||
| 266 | { | ||
| 267 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
| 268 | |||
| 269 | if (data->status & PICOLCD_BOOTLOADER) | ||
| 270 | return snprintf(buf, PAGE_SIZE, "[bootloader] lcd\n"); | ||
| 271 | else | ||
| 272 | return snprintf(buf, PAGE_SIZE, "bootloader [lcd]\n"); | ||
| 273 | } | ||
| 274 | |||
| 275 | static ssize_t picolcd_operation_mode_store(struct device *dev, | ||
| 276 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 277 | { | ||
| 278 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
| 279 | struct hid_report *report = NULL; | ||
| 280 | size_t cnt = count; | ||
| 281 | int timeout = data->opmode_delay; | ||
| 282 | unsigned long flags; | ||
| 283 | |||
| 284 | if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) { | ||
| 285 | if (data->status & PICOLCD_BOOTLOADER) | ||
| 286 | report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev); | ||
| 287 | buf += 3; | ||
| 288 | cnt -= 3; | ||
| 289 | } else if (cnt >= 10 && strncmp("bootloader", buf, 10) == 0) { | ||
| 290 | if (!(data->status & PICOLCD_BOOTLOADER)) | ||
| 291 | report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev); | ||
| 292 | buf += 10; | ||
| 293 | cnt -= 10; | ||
| 294 | } | ||
| 295 | if (!report) | ||
| 296 | return -EINVAL; | ||
| 297 | |||
| 298 | while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r')) | ||
| 299 | cnt--; | ||
| 300 | if (cnt != 0) | ||
| 301 | return -EINVAL; | ||
| 302 | |||
| 303 | spin_lock_irqsave(&data->lock, flags); | ||
| 304 | hid_set_field(report->field[0], 0, timeout & 0xff); | ||
| 305 | hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff); | ||
| 306 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
| 307 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 308 | return count; | ||
| 309 | } | ||
| 310 | |||
| 311 | static DEVICE_ATTR(operation_mode, 0644, picolcd_operation_mode_show, | ||
| 312 | picolcd_operation_mode_store); | ||
| 313 | |||
| 314 | /* | ||
| 315 | * The "operation_mode_delay" sysfs attribute | ||
| 316 | */ | ||
| 317 | static ssize_t picolcd_operation_mode_delay_show(struct device *dev, | ||
| 318 | struct device_attribute *attr, char *buf) | ||
| 319 | { | ||
| 320 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
| 321 | |||
| 322 | return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay); | ||
| 323 | } | ||
| 324 | |||
| 325 | static ssize_t picolcd_operation_mode_delay_store(struct device *dev, | ||
| 326 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 327 | { | ||
| 328 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
| 329 | unsigned u; | ||
| 330 | if (sscanf(buf, "%u", &u) != 1) | ||
| 331 | return -EINVAL; | ||
| 332 | if (u > 30000) | ||
| 333 | return -EINVAL; | ||
| 334 | else | ||
| 335 | data->opmode_delay = u; | ||
| 336 | return count; | ||
| 337 | } | ||
| 338 | |||
| 339 | static DEVICE_ATTR(operation_mode_delay, 0644, picolcd_operation_mode_delay_show, | ||
| 340 | picolcd_operation_mode_delay_store); | ||
| 341 | |||
| 342 | /* | ||
| 343 | * Handle raw report as sent by device | ||
| 344 | */ | ||
| 345 | static int picolcd_raw_event(struct hid_device *hdev, | ||
| 346 | struct hid_report *report, u8 *raw_data, int size) | ||
| 347 | { | ||
| 348 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
| 349 | unsigned long flags; | ||
| 350 | int ret = 0; | ||
| 351 | |||
| 352 | if (!data) | ||
| 353 | return 1; | ||
| 354 | |||
| 355 | if (report->id == REPORT_KEY_STATE) { | ||
| 356 | if (data->input_keys) | ||
| 357 | ret = picolcd_raw_keypad(data, report, raw_data+1, size-1); | ||
| 358 | } else if (report->id == REPORT_IR_DATA) { | ||
| 359 | ret = picolcd_raw_cir(data, report, raw_data+1, size-1); | ||
| 360 | } else { | ||
| 361 | spin_lock_irqsave(&data->lock, flags); | ||
| 362 | /* | ||
| 363 | * We let the caller of picolcd_send_and_wait() check if the | ||
| 364 | * report we got is one of the expected ones or not. | ||
| 365 | */ | ||
| 366 | if (data->pending) { | ||
| 367 | memcpy(data->pending->raw_data, raw_data+1, size-1); | ||
| 368 | data->pending->raw_size = size-1; | ||
| 369 | data->pending->in_report = report; | ||
| 370 | complete(&data->pending->ready); | ||
| 371 | } | ||
| 372 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 373 | } | ||
| 374 | |||
| 375 | picolcd_debug_raw_event(data, hdev, report, raw_data, size); | ||
| 376 | return 1; | ||
| 377 | } | ||
| 378 | |||
| 379 | #ifdef CONFIG_PM | ||
| 380 | static int picolcd_suspend(struct hid_device *hdev, pm_message_t message) | ||
| 381 | { | ||
| 382 | if (PMSG_IS_AUTO(message)) | ||
| 383 | return 0; | ||
| 384 | |||
| 385 | picolcd_suspend_backlight(hid_get_drvdata(hdev)); | ||
| 386 | dbg_hid(PICOLCD_NAME " device ready for suspend\n"); | ||
| 387 | return 0; | ||
| 388 | } | ||
| 389 | |||
| 390 | static int picolcd_resume(struct hid_device *hdev) | ||
| 391 | { | ||
| 392 | int ret; | ||
| 393 | ret = picolcd_resume_backlight(hid_get_drvdata(hdev)); | ||
| 394 | if (ret) | ||
| 395 | dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret); | ||
| 396 | return 0; | ||
| 397 | } | ||
| 398 | |||
| 399 | static int picolcd_reset_resume(struct hid_device *hdev) | ||
| 400 | { | ||
| 401 | int ret; | ||
| 402 | ret = picolcd_reset(hdev); | ||
| 403 | if (ret) | ||
| 404 | dbg_hid(PICOLCD_NAME " resetting our device failed: %d\n", ret); | ||
| 405 | ret = picolcd_fb_reset(hid_get_drvdata(hdev), 0); | ||
| 406 | if (ret) | ||
| 407 | dbg_hid(PICOLCD_NAME " restoring framebuffer content failed: %d\n", ret); | ||
| 408 | ret = picolcd_resume_lcd(hid_get_drvdata(hdev)); | ||
| 409 | if (ret) | ||
| 410 | dbg_hid(PICOLCD_NAME " restoring lcd failed: %d\n", ret); | ||
| 411 | ret = picolcd_resume_backlight(hid_get_drvdata(hdev)); | ||
| 412 | if (ret) | ||
| 413 | dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret); | ||
| 414 | picolcd_leds_set(hid_get_drvdata(hdev)); | ||
| 415 | return 0; | ||
| 416 | } | ||
| 417 | #endif | ||
| 418 | |||
| 419 | /* initialize keypad input device */ | ||
| 420 | static int picolcd_init_keys(struct picolcd_data *data, | ||
| 421 | struct hid_report *report) | ||
| 422 | { | ||
| 423 | struct hid_device *hdev = data->hdev; | ||
| 424 | struct input_dev *idev; | ||
| 425 | int error, i; | ||
| 426 | |||
| 427 | if (!report) | ||
| 428 | return -ENODEV; | ||
| 429 | if (report->maxfield != 1 || report->field[0]->report_count != 2 || | ||
| 430 | report->field[0]->report_size != 8) { | ||
| 431 | hid_err(hdev, "unsupported KEY_STATE report\n"); | ||
| 432 | return -EINVAL; | ||
| 433 | } | ||
| 434 | |||
| 435 | idev = input_allocate_device(); | ||
| 436 | if (idev == NULL) { | ||
| 437 | hid_err(hdev, "failed to allocate input device\n"); | ||
| 438 | return -ENOMEM; | ||
| 439 | } | ||
| 440 | input_set_drvdata(idev, hdev); | ||
| 441 | memcpy(data->keycode, def_keymap, sizeof(def_keymap)); | ||
| 442 | idev->name = hdev->name; | ||
| 443 | idev->phys = hdev->phys; | ||
| 444 | idev->uniq = hdev->uniq; | ||
| 445 | idev->id.bustype = hdev->bus; | ||
| 446 | idev->id.vendor = hdev->vendor; | ||
| 447 | idev->id.product = hdev->product; | ||
| 448 | idev->id.version = hdev->version; | ||
| 449 | idev->dev.parent = &hdev->dev; | ||
| 450 | idev->keycode = &data->keycode; | ||
| 451 | idev->keycodemax = PICOLCD_KEYS; | ||
| 452 | idev->keycodesize = sizeof(data->keycode[0]); | ||
| 453 | input_set_capability(idev, EV_MSC, MSC_SCAN); | ||
| 454 | set_bit(EV_REP, idev->evbit); | ||
| 455 | for (i = 0; i < PICOLCD_KEYS; i++) | ||
| 456 | input_set_capability(idev, EV_KEY, data->keycode[i]); | ||
| 457 | error = input_register_device(idev); | ||
| 458 | if (error) { | ||
| 459 | hid_err(hdev, "error registering the input device\n"); | ||
| 460 | input_free_device(idev); | ||
| 461 | return error; | ||
| 462 | } | ||
| 463 | data->input_keys = idev; | ||
| 464 | return 0; | ||
| 465 | } | ||
| 466 | |||
| 467 | static void picolcd_exit_keys(struct picolcd_data *data) | ||
| 468 | { | ||
| 469 | struct input_dev *idev = data->input_keys; | ||
| 470 | |||
| 471 | data->input_keys = NULL; | ||
| 472 | if (idev) | ||
| 473 | input_unregister_device(idev); | ||
| 474 | } | ||
| 475 | |||
| 476 | static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data) | ||
| 477 | { | ||
| 478 | int error; | ||
| 479 | |||
| 480 | /* Setup keypad input device */ | ||
| 481 | error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev)); | ||
| 482 | if (error) | ||
| 483 | goto err; | ||
| 484 | |||
| 485 | /* Setup CIR input device */ | ||
| 486 | error = picolcd_init_cir(data, picolcd_in_report(REPORT_IR_DATA, hdev)); | ||
| 487 | if (error) | ||
| 488 | goto err; | ||
| 489 | |||
| 490 | /* Set up the framebuffer device */ | ||
| 491 | error = picolcd_init_framebuffer(data); | ||
| 492 | if (error) | ||
| 493 | goto err; | ||
| 494 | |||
| 495 | /* Setup lcd class device */ | ||
| 496 | error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev)); | ||
| 497 | if (error) | ||
| 498 | goto err; | ||
| 499 | |||
| 500 | /* Setup backlight class device */ | ||
| 501 | error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev)); | ||
| 502 | if (error) | ||
| 503 | goto err; | ||
| 504 | |||
| 505 | /* Setup the LED class devices */ | ||
| 506 | error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev)); | ||
| 507 | if (error) | ||
| 508 | goto err; | ||
| 509 | |||
| 510 | picolcd_init_devfs(data, picolcd_out_report(REPORT_EE_READ, hdev), | ||
| 511 | picolcd_out_report(REPORT_EE_WRITE, hdev), | ||
| 512 | picolcd_out_report(REPORT_READ_MEMORY, hdev), | ||
| 513 | picolcd_out_report(REPORT_WRITE_MEMORY, hdev), | ||
| 514 | picolcd_out_report(REPORT_RESET, hdev)); | ||
| 515 | return 0; | ||
| 516 | err: | ||
| 517 | picolcd_exit_leds(data); | ||
| 518 | picolcd_exit_backlight(data); | ||
| 519 | picolcd_exit_lcd(data); | ||
| 520 | picolcd_exit_framebuffer(data); | ||
| 521 | picolcd_exit_cir(data); | ||
| 522 | picolcd_exit_keys(data); | ||
| 523 | return error; | ||
| 524 | } | ||
| 525 | |||
| 526 | static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data *data) | ||
| 527 | { | ||
| 528 | picolcd_init_devfs(data, NULL, NULL, | ||
| 529 | picolcd_out_report(REPORT_BL_READ_MEMORY, hdev), | ||
| 530 | picolcd_out_report(REPORT_BL_WRITE_MEMORY, hdev), NULL); | ||
| 531 | return 0; | ||
| 532 | } | ||
| 533 | |||
| 534 | static int picolcd_probe(struct hid_device *hdev, | ||
| 535 | const struct hid_device_id *id) | ||
| 536 | { | ||
| 537 | struct picolcd_data *data; | ||
| 538 | int error = -ENOMEM; | ||
| 539 | |||
| 540 | dbg_hid(PICOLCD_NAME " hardware probe...\n"); | ||
| 541 | |||
| 542 | /* | ||
| 543 | * Let's allocate the picolcd data structure, set some reasonable | ||
| 544 | * defaults, and associate it with the device | ||
| 545 | */ | ||
| 546 | data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL); | ||
| 547 | if (data == NULL) { | ||
| 548 | hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n"); | ||
| 549 | error = -ENOMEM; | ||
| 550 | goto err_no_cleanup; | ||
| 551 | } | ||
| 552 | |||
| 553 | spin_lock_init(&data->lock); | ||
| 554 | mutex_init(&data->mutex); | ||
| 555 | data->hdev = hdev; | ||
| 556 | data->opmode_delay = 5000; | ||
| 557 | if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER) | ||
| 558 | data->status |= PICOLCD_BOOTLOADER; | ||
| 559 | hid_set_drvdata(hdev, data); | ||
| 560 | |||
| 561 | /* Parse the device reports and start it up */ | ||
| 562 | error = hid_parse(hdev); | ||
| 563 | if (error) { | ||
| 564 | hid_err(hdev, "device report parse failed\n"); | ||
| 565 | goto err_cleanup_data; | ||
| 566 | } | ||
| 567 | |||
| 568 | error = hid_hw_start(hdev, 0); | ||
| 569 | if (error) { | ||
| 570 | hid_err(hdev, "hardware start failed\n"); | ||
| 571 | goto err_cleanup_data; | ||
| 572 | } | ||
| 573 | |||
| 574 | error = hid_hw_open(hdev); | ||
| 575 | if (error) { | ||
| 576 | hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n"); | ||
| 577 | goto err_cleanup_hid_hw; | ||
| 578 | } | ||
| 579 | |||
| 580 | error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay); | ||
| 581 | if (error) { | ||
| 582 | hid_err(hdev, "failed to create sysfs attributes\n"); | ||
| 583 | goto err_cleanup_hid_ll; | ||
| 584 | } | ||
| 585 | |||
| 586 | error = device_create_file(&hdev->dev, &dev_attr_operation_mode); | ||
| 587 | if (error) { | ||
| 588 | hid_err(hdev, "failed to create sysfs attributes\n"); | ||
| 589 | goto err_cleanup_sysfs1; | ||
| 590 | } | ||
| 591 | |||
| 592 | if (data->status & PICOLCD_BOOTLOADER) | ||
| 593 | error = picolcd_probe_bootloader(hdev, data); | ||
| 594 | else | ||
| 595 | error = picolcd_probe_lcd(hdev, data); | ||
| 596 | if (error) | ||
| 597 | goto err_cleanup_sysfs2; | ||
| 598 | |||
| 599 | dbg_hid(PICOLCD_NAME " activated and initialized\n"); | ||
| 600 | return 0; | ||
| 601 | |||
| 602 | err_cleanup_sysfs2: | ||
| 603 | device_remove_file(&hdev->dev, &dev_attr_operation_mode); | ||
| 604 | err_cleanup_sysfs1: | ||
| 605 | device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay); | ||
| 606 | err_cleanup_hid_ll: | ||
| 607 | hid_hw_close(hdev); | ||
| 608 | err_cleanup_hid_hw: | ||
| 609 | hid_hw_stop(hdev); | ||
| 610 | err_cleanup_data: | ||
| 611 | kfree(data); | ||
| 612 | err_no_cleanup: | ||
| 613 | hid_set_drvdata(hdev, NULL); | ||
| 614 | |||
| 615 | return error; | ||
| 616 | } | ||
| 617 | |||
| 618 | static void picolcd_remove(struct hid_device *hdev) | ||
| 619 | { | ||
| 620 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
| 621 | unsigned long flags; | ||
| 622 | |||
| 623 | dbg_hid(PICOLCD_NAME " hardware remove...\n"); | ||
| 624 | spin_lock_irqsave(&data->lock, flags); | ||
| 625 | data->status |= PICOLCD_FAILED; | ||
| 626 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 627 | |||
| 628 | picolcd_exit_devfs(data); | ||
| 629 | device_remove_file(&hdev->dev, &dev_attr_operation_mode); | ||
| 630 | device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay); | ||
| 631 | hid_hw_close(hdev); | ||
| 632 | hid_hw_stop(hdev); | ||
| 633 | |||
| 634 | /* Shortcut potential pending reply that will never arrive */ | ||
| 635 | spin_lock_irqsave(&data->lock, flags); | ||
| 636 | if (data->pending) | ||
| 637 | complete(&data->pending->ready); | ||
| 638 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 639 | |||
| 640 | /* Cleanup LED */ | ||
| 641 | picolcd_exit_leds(data); | ||
| 642 | /* Clean up the framebuffer */ | ||
| 643 | picolcd_exit_backlight(data); | ||
| 644 | picolcd_exit_lcd(data); | ||
| 645 | picolcd_exit_framebuffer(data); | ||
| 646 | /* Cleanup input */ | ||
| 647 | picolcd_exit_cir(data); | ||
| 648 | picolcd_exit_keys(data); | ||
| 649 | |||
| 650 | hid_set_drvdata(hdev, NULL); | ||
| 651 | mutex_destroy(&data->mutex); | ||
| 652 | /* Finally, clean up the picolcd data itself */ | ||
| 653 | kfree(data); | ||
| 654 | } | ||
| 655 | |||
| 656 | static const struct hid_device_id picolcd_devices[] = { | ||
| 657 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) }, | ||
| 658 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) }, | ||
| 659 | { } | ||
| 660 | }; | ||
| 661 | MODULE_DEVICE_TABLE(hid, picolcd_devices); | ||
| 662 | |||
| 663 | static struct hid_driver picolcd_driver = { | ||
| 664 | .name = "hid-picolcd", | ||
| 665 | .id_table = picolcd_devices, | ||
| 666 | .probe = picolcd_probe, | ||
| 667 | .remove = picolcd_remove, | ||
| 668 | .raw_event = picolcd_raw_event, | ||
| 669 | #ifdef CONFIG_PM | ||
| 670 | .suspend = picolcd_suspend, | ||
| 671 | .resume = picolcd_resume, | ||
| 672 | .reset_resume = picolcd_reset_resume, | ||
| 673 | #endif | ||
| 674 | }; | ||
| 675 | |||
| 676 | static int __init picolcd_init(void) | ||
| 677 | { | ||
| 678 | return hid_register_driver(&picolcd_driver); | ||
| 679 | } | ||
| 680 | |||
| 681 | static void __exit picolcd_exit(void) | ||
| 682 | { | ||
| 683 | hid_unregister_driver(&picolcd_driver); | ||
| 684 | } | ||
| 685 | |||
| 686 | module_init(picolcd_init); | ||
| 687 | module_exit(picolcd_exit); | ||
| 688 | MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver"); | ||
| 689 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/hid/hid-picolcd_debugfs.c b/drivers/hid/hid-picolcd_debugfs.c new file mode 100644 index 000000000000..4809aa1bdb9c --- /dev/null +++ b/drivers/hid/hid-picolcd_debugfs.c | |||
| @@ -0,0 +1,899 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> * | ||
| 3 | * * | ||
| 4 | * Based on Logitech G13 driver (v0.4) * | ||
| 5 | * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * | ||
| 6 | * * | ||
| 7 | * This program is free software: you can redistribute it and/or modify * | ||
| 8 | * it under the terms of the GNU General Public License as published by * | ||
| 9 | * the Free Software Foundation, version 2 of the License. * | ||
| 10 | * * | ||
| 11 | * This driver is distributed in the hope that it will be useful, but * | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * | ||
| 14 | * General Public License for more details. * | ||
| 15 | * * | ||
| 16 | * You should have received a copy of the GNU General Public License * | ||
| 17 | * along with this software. If not see <http://www.gnu.org/licenses/>. * | ||
| 18 | ***************************************************************************/ | ||
| 19 | |||
| 20 | #include <linux/hid.h> | ||
| 21 | #include <linux/hid-debug.h> | ||
| 22 | #include "usbhid/usbhid.h" | ||
| 23 | #include <linux/usb.h> | ||
| 24 | |||
| 25 | #include <linux/fb.h> | ||
| 26 | #include <linux/seq_file.h> | ||
| 27 | #include <linux/debugfs.h> | ||
| 28 | |||
| 29 | #include <linux/module.h> | ||
| 30 | #include <linux/uaccess.h> | ||
| 31 | |||
| 32 | #include "hid-picolcd.h" | ||
| 33 | |||
| 34 | |||
| 35 | static int picolcd_debug_reset_show(struct seq_file *f, void *p) | ||
| 36 | { | ||
| 37 | if (picolcd_fbinfo((struct picolcd_data *)f->private)) | ||
| 38 | seq_printf(f, "all fb\n"); | ||
| 39 | else | ||
| 40 | seq_printf(f, "all\n"); | ||
| 41 | return 0; | ||
| 42 | } | ||
| 43 | |||
| 44 | static int picolcd_debug_reset_open(struct inode *inode, struct file *f) | ||
| 45 | { | ||
| 46 | return single_open(f, picolcd_debug_reset_show, inode->i_private); | ||
| 47 | } | ||
| 48 | |||
| 49 | static ssize_t picolcd_debug_reset_write(struct file *f, const char __user *user_buf, | ||
| 50 | size_t count, loff_t *ppos) | ||
| 51 | { | ||
| 52 | struct picolcd_data *data = ((struct seq_file *)f->private_data)->private; | ||
| 53 | char buf[32]; | ||
| 54 | size_t cnt = min(count, sizeof(buf)-1); | ||
| 55 | if (copy_from_user(buf, user_buf, cnt)) | ||
| 56 | return -EFAULT; | ||
| 57 | |||
| 58 | while (cnt > 0 && (buf[cnt-1] == ' ' || buf[cnt-1] == '\n')) | ||
| 59 | cnt--; | ||
| 60 | buf[cnt] = '\0'; | ||
| 61 | if (strcmp(buf, "all") == 0) { | ||
| 62 | picolcd_reset(data->hdev); | ||
| 63 | picolcd_fb_reset(data, 1); | ||
| 64 | } else if (strcmp(buf, "fb") == 0) { | ||
| 65 | picolcd_fb_reset(data, 1); | ||
| 66 | } else { | ||
| 67 | return -EINVAL; | ||
| 68 | } | ||
| 69 | return count; | ||
| 70 | } | ||
| 71 | |||
| 72 | static const struct file_operations picolcd_debug_reset_fops = { | ||
| 73 | .owner = THIS_MODULE, | ||
| 74 | .open = picolcd_debug_reset_open, | ||
| 75 | .read = seq_read, | ||
| 76 | .llseek = seq_lseek, | ||
| 77 | .write = picolcd_debug_reset_write, | ||
| 78 | .release = single_release, | ||
| 79 | }; | ||
| 80 | |||
| 81 | /* | ||
| 82 | * The "eeprom" file | ||
| 83 | */ | ||
| 84 | static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u, | ||
| 85 | size_t s, loff_t *off) | ||
| 86 | { | ||
| 87 | struct picolcd_data *data = f->private_data; | ||
| 88 | struct picolcd_pending *resp; | ||
| 89 | u8 raw_data[3]; | ||
| 90 | ssize_t ret = -EIO; | ||
| 91 | |||
| 92 | if (s == 0) | ||
| 93 | return -EINVAL; | ||
| 94 | if (*off > 0x0ff) | ||
| 95 | return 0; | ||
| 96 | |||
| 97 | /* prepare buffer with info about what we want to read (addr & len) */ | ||
| 98 | raw_data[0] = *off & 0xff; | ||
| 99 | raw_data[1] = (*off >> 8) & 0xff; | ||
| 100 | raw_data[2] = s < 20 ? s : 20; | ||
| 101 | if (*off + raw_data[2] > 0xff) | ||
| 102 | raw_data[2] = 0x100 - *off; | ||
| 103 | resp = picolcd_send_and_wait(data->hdev, REPORT_EE_READ, raw_data, | ||
| 104 | sizeof(raw_data)); | ||
| 105 | if (!resp) | ||
| 106 | return -EIO; | ||
| 107 | |||
| 108 | if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) { | ||
| 109 | /* successful read :) */ | ||
| 110 | ret = resp->raw_data[2]; | ||
| 111 | if (ret > s) | ||
| 112 | ret = s; | ||
| 113 | if (copy_to_user(u, resp->raw_data+3, ret)) | ||
| 114 | ret = -EFAULT; | ||
| 115 | else | ||
| 116 | *off += ret; | ||
| 117 | } /* anything else is some kind of IO error */ | ||
| 118 | |||
| 119 | kfree(resp); | ||
| 120 | return ret; | ||
| 121 | } | ||
| 122 | |||
| 123 | static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u, | ||
| 124 | size_t s, loff_t *off) | ||
| 125 | { | ||
| 126 | struct picolcd_data *data = f->private_data; | ||
| 127 | struct picolcd_pending *resp; | ||
| 128 | ssize_t ret = -EIO; | ||
| 129 | u8 raw_data[23]; | ||
| 130 | |||
| 131 | if (s == 0) | ||
| 132 | return -EINVAL; | ||
| 133 | if (*off > 0x0ff) | ||
| 134 | return -ENOSPC; | ||
| 135 | |||
| 136 | memset(raw_data, 0, sizeof(raw_data)); | ||
| 137 | raw_data[0] = *off & 0xff; | ||
| 138 | raw_data[1] = (*off >> 8) & 0xff; | ||
| 139 | raw_data[2] = min_t(size_t, 20, s); | ||
| 140 | if (*off + raw_data[2] > 0xff) | ||
| 141 | raw_data[2] = 0x100 - *off; | ||
| 142 | |||
| 143 | if (copy_from_user(raw_data+3, u, min((u8)20, raw_data[2]))) | ||
| 144 | return -EFAULT; | ||
| 145 | resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data, | ||
| 146 | sizeof(raw_data)); | ||
| 147 | |||
| 148 | if (!resp) | ||
| 149 | return -EIO; | ||
| 150 | |||
| 151 | if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) { | ||
| 152 | /* check if written data matches */ | ||
| 153 | if (memcmp(raw_data, resp->raw_data, 3+raw_data[2]) == 0) { | ||
| 154 | *off += raw_data[2]; | ||
| 155 | ret = raw_data[2]; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | kfree(resp); | ||
| 159 | return ret; | ||
| 160 | } | ||
| 161 | |||
| 162 | /* | ||
| 163 | * Notes: | ||
| 164 | * - read/write happens in chunks of at most 20 bytes, it's up to userspace | ||
| 165 | * to loop in order to get more data. | ||
| 166 | * - on write errors on otherwise correct write request the bytes | ||
| 167 | * that should have been written are in undefined state. | ||
| 168 | */ | ||
| 169 | static const struct file_operations picolcd_debug_eeprom_fops = { | ||
| 170 | .owner = THIS_MODULE, | ||
| 171 | .open = simple_open, | ||
| 172 | .read = picolcd_debug_eeprom_read, | ||
| 173 | .write = picolcd_debug_eeprom_write, | ||
| 174 | .llseek = generic_file_llseek, | ||
| 175 | }; | ||
| 176 | |||
| 177 | /* | ||
| 178 | * The "flash" file | ||
| 179 | */ | ||
| 180 | /* record a flash address to buf (bounds check to be done by caller) */ | ||
| 181 | static int _picolcd_flash_setaddr(struct picolcd_data *data, u8 *buf, long off) | ||
| 182 | { | ||
| 183 | buf[0] = off & 0xff; | ||
| 184 | buf[1] = (off >> 8) & 0xff; | ||
| 185 | if (data->addr_sz == 3) | ||
| 186 | buf[2] = (off >> 16) & 0xff; | ||
| 187 | return data->addr_sz == 2 ? 2 : 3; | ||
| 188 | } | ||
| 189 | |||
| 190 | /* read a given size of data (bounds check to be done by caller) */ | ||
| 191 | static ssize_t _picolcd_flash_read(struct picolcd_data *data, int report_id, | ||
| 192 | char __user *u, size_t s, loff_t *off) | ||
| 193 | { | ||
| 194 | struct picolcd_pending *resp; | ||
| 195 | u8 raw_data[4]; | ||
| 196 | ssize_t ret = 0; | ||
| 197 | int len_off, err = -EIO; | ||
| 198 | |||
| 199 | while (s > 0) { | ||
| 200 | err = -EIO; | ||
| 201 | len_off = _picolcd_flash_setaddr(data, raw_data, *off); | ||
| 202 | raw_data[len_off] = s > 32 ? 32 : s; | ||
| 203 | resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off+1); | ||
| 204 | if (!resp || !resp->in_report) | ||
| 205 | goto skip; | ||
| 206 | if (resp->in_report->id == REPORT_MEMORY || | ||
| 207 | resp->in_report->id == REPORT_BL_READ_MEMORY) { | ||
| 208 | if (memcmp(raw_data, resp->raw_data, len_off+1) != 0) | ||
| 209 | goto skip; | ||
| 210 | if (copy_to_user(u+ret, resp->raw_data+len_off+1, raw_data[len_off])) { | ||
| 211 | err = -EFAULT; | ||
| 212 | goto skip; | ||
| 213 | } | ||
| 214 | *off += raw_data[len_off]; | ||
| 215 | s -= raw_data[len_off]; | ||
| 216 | ret += raw_data[len_off]; | ||
| 217 | err = 0; | ||
| 218 | } | ||
| 219 | skip: | ||
| 220 | kfree(resp); | ||
| 221 | if (err) | ||
| 222 | return ret > 0 ? ret : err; | ||
| 223 | } | ||
| 224 | return ret; | ||
| 225 | } | ||
| 226 | |||
| 227 | static ssize_t picolcd_debug_flash_read(struct file *f, char __user *u, | ||
| 228 | size_t s, loff_t *off) | ||
| 229 | { | ||
| 230 | struct picolcd_data *data = f->private_data; | ||
| 231 | |||
| 232 | if (s == 0) | ||
| 233 | return -EINVAL; | ||
| 234 | if (*off > 0x05fff) | ||
| 235 | return 0; | ||
| 236 | if (*off + s > 0x05fff) | ||
| 237 | s = 0x06000 - *off; | ||
| 238 | |||
| 239 | if (data->status & PICOLCD_BOOTLOADER) | ||
| 240 | return _picolcd_flash_read(data, REPORT_BL_READ_MEMORY, u, s, off); | ||
| 241 | else | ||
| 242 | return _picolcd_flash_read(data, REPORT_READ_MEMORY, u, s, off); | ||
| 243 | } | ||
| 244 | |||
| 245 | /* erase block aligned to 64bytes boundary */ | ||
| 246 | static ssize_t _picolcd_flash_erase64(struct picolcd_data *data, int report_id, | ||
| 247 | loff_t *off) | ||
| 248 | { | ||
| 249 | struct picolcd_pending *resp; | ||
| 250 | u8 raw_data[3]; | ||
| 251 | int len_off; | ||
| 252 | ssize_t ret = -EIO; | ||
| 253 | |||
| 254 | if (*off & 0x3f) | ||
| 255 | return -EINVAL; | ||
| 256 | |||
| 257 | len_off = _picolcd_flash_setaddr(data, raw_data, *off); | ||
| 258 | resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off); | ||
| 259 | if (!resp || !resp->in_report) | ||
| 260 | goto skip; | ||
| 261 | if (resp->in_report->id == REPORT_MEMORY || | ||
| 262 | resp->in_report->id == REPORT_BL_ERASE_MEMORY) { | ||
| 263 | if (memcmp(raw_data, resp->raw_data, len_off) != 0) | ||
| 264 | goto skip; | ||
| 265 | ret = 0; | ||
| 266 | } | ||
| 267 | skip: | ||
| 268 | kfree(resp); | ||
| 269 | return ret; | ||
| 270 | } | ||
| 271 | |||
| 272 | /* write a given size of data (bounds check to be done by caller) */ | ||
| 273 | static ssize_t _picolcd_flash_write(struct picolcd_data *data, int report_id, | ||
| 274 | const char __user *u, size_t s, loff_t *off) | ||
| 275 | { | ||
| 276 | struct picolcd_pending *resp; | ||
| 277 | u8 raw_data[36]; | ||
| 278 | ssize_t ret = 0; | ||
| 279 | int len_off, err = -EIO; | ||
| 280 | |||
| 281 | while (s > 0) { | ||
| 282 | err = -EIO; | ||
| 283 | len_off = _picolcd_flash_setaddr(data, raw_data, *off); | ||
| 284 | raw_data[len_off] = s > 32 ? 32 : s; | ||
| 285 | if (copy_from_user(raw_data+len_off+1, u, raw_data[len_off])) { | ||
| 286 | err = -EFAULT; | ||
| 287 | break; | ||
| 288 | } | ||
| 289 | resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, | ||
| 290 | len_off+1+raw_data[len_off]); | ||
| 291 | if (!resp || !resp->in_report) | ||
| 292 | goto skip; | ||
| 293 | if (resp->in_report->id == REPORT_MEMORY || | ||
| 294 | resp->in_report->id == REPORT_BL_WRITE_MEMORY) { | ||
| 295 | if (memcmp(raw_data, resp->raw_data, len_off+1+raw_data[len_off]) != 0) | ||
| 296 | goto skip; | ||
| 297 | *off += raw_data[len_off]; | ||
| 298 | s -= raw_data[len_off]; | ||
| 299 | ret += raw_data[len_off]; | ||
| 300 | err = 0; | ||
| 301 | } | ||
| 302 | skip: | ||
| 303 | kfree(resp); | ||
| 304 | if (err) | ||
| 305 | break; | ||
| 306 | } | ||
| 307 | return ret > 0 ? ret : err; | ||
| 308 | } | ||
| 309 | |||
| 310 | static ssize_t picolcd_debug_flash_write(struct file *f, const char __user *u, | ||
| 311 | size_t s, loff_t *off) | ||
| 312 | { | ||
| 313 | struct picolcd_data *data = f->private_data; | ||
| 314 | ssize_t err, ret = 0; | ||
| 315 | int report_erase, report_write; | ||
| 316 | |||
| 317 | if (s == 0) | ||
| 318 | return -EINVAL; | ||
| 319 | if (*off > 0x5fff) | ||
| 320 | return -ENOSPC; | ||
| 321 | if (s & 0x3f) | ||
| 322 | return -EINVAL; | ||
| 323 | if (*off & 0x3f) | ||
| 324 | return -EINVAL; | ||
| 325 | |||
| 326 | if (data->status & PICOLCD_BOOTLOADER) { | ||
| 327 | report_erase = REPORT_BL_ERASE_MEMORY; | ||
| 328 | report_write = REPORT_BL_WRITE_MEMORY; | ||
| 329 | } else { | ||
| 330 | report_erase = REPORT_ERASE_MEMORY; | ||
| 331 | report_write = REPORT_WRITE_MEMORY; | ||
| 332 | } | ||
| 333 | mutex_lock(&data->mutex_flash); | ||
| 334 | while (s > 0) { | ||
| 335 | err = _picolcd_flash_erase64(data, report_erase, off); | ||
| 336 | if (err) | ||
| 337 | break; | ||
| 338 | err = _picolcd_flash_write(data, report_write, u, 64, off); | ||
| 339 | if (err < 0) | ||
| 340 | break; | ||
| 341 | ret += err; | ||
| 342 | *off += err; | ||
| 343 | s -= err; | ||
| 344 | if (err != 64) | ||
| 345 | break; | ||
| 346 | } | ||
| 347 | mutex_unlock(&data->mutex_flash); | ||
| 348 | return ret > 0 ? ret : err; | ||
| 349 | } | ||
| 350 | |||
| 351 | /* | ||
| 352 | * Notes: | ||
| 353 | * - concurrent writing is prevented by mutex and all writes must be | ||
| 354 | * n*64 bytes and 64-byte aligned, each write being preceded by an | ||
| 355 | * ERASE which erases a 64byte block. | ||
| 356 | * If less than requested was written or an error is returned for an | ||
| 357 | * otherwise correct write request the next 64-byte block which should | ||
| 358 | * have been written is in undefined state (mostly: original, erased, | ||
| 359 | * (half-)written with write error) | ||
| 360 | * - reading can happen without special restriction | ||
| 361 | */ | ||
| 362 | static const struct file_operations picolcd_debug_flash_fops = { | ||
| 363 | .owner = THIS_MODULE, | ||
| 364 | .open = simple_open, | ||
| 365 | .read = picolcd_debug_flash_read, | ||
| 366 | .write = picolcd_debug_flash_write, | ||
| 367 | .llseek = generic_file_llseek, | ||
| 368 | }; | ||
| 369 | |||
| 370 | |||
| 371 | /* | ||
| 372 | * Helper code for HID report level dumping/debugging | ||
| 373 | */ | ||
| 374 | static const char * const error_codes[] = { | ||
| 375 | "success", "parameter missing", "data_missing", "block readonly", | ||
| 376 | "block not erasable", "block too big", "section overflow", | ||
| 377 | "invalid command length", "invalid data length", | ||
| 378 | }; | ||
| 379 | |||
| 380 | static void dump_buff_as_hex(char *dst, size_t dst_sz, const u8 *data, | ||
| 381 | const size_t data_len) | ||
| 382 | { | ||
| 383 | int i, j; | ||
| 384 | for (i = j = 0; i < data_len && j + 4 < dst_sz; i++) { | ||
| 385 | dst[j++] = hex_asc[(data[i] >> 4) & 0x0f]; | ||
| 386 | dst[j++] = hex_asc[data[i] & 0x0f]; | ||
| 387 | dst[j++] = ' '; | ||
| 388 | } | ||
| 389 | dst[j] = '\0'; | ||
| 390 | if (j > 0) | ||
| 391 | dst[j-1] = '\n'; | ||
| 392 | if (i < data_len && j > 2) | ||
| 393 | dst[j-2] = dst[j-3] = '.'; | ||
| 394 | } | ||
| 395 | |||
| 396 | void picolcd_debug_out_report(struct picolcd_data *data, | ||
| 397 | struct hid_device *hdev, struct hid_report *report) | ||
| 398 | { | ||
| 399 | u8 raw_data[70]; | ||
| 400 | int raw_size = (report->size >> 3) + 1; | ||
| 401 | char *buff; | ||
| 402 | #define BUFF_SZ 256 | ||
| 403 | |||
| 404 | /* Avoid unnecessary overhead if debugfs is disabled */ | ||
| 405 | if (list_empty(&hdev->debug_list)) | ||
| 406 | return; | ||
| 407 | |||
| 408 | buff = kmalloc(BUFF_SZ, GFP_ATOMIC); | ||
| 409 | if (!buff) | ||
| 410 | return; | ||
| 411 | |||
| 412 | snprintf(buff, BUFF_SZ, "\nout report %d (size %d) = ", | ||
| 413 | report->id, raw_size); | ||
| 414 | hid_debug_event(hdev, buff); | ||
| 415 | if (raw_size + 5 > sizeof(raw_data)) { | ||
| 416 | kfree(buff); | ||
| 417 | hid_debug_event(hdev, " TOO BIG\n"); | ||
| 418 | return; | ||
| 419 | } else { | ||
| 420 | raw_data[0] = report->id; | ||
| 421 | hid_output_report(report, raw_data); | ||
| 422 | dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size); | ||
| 423 | hid_debug_event(hdev, buff); | ||
| 424 | } | ||
| 425 | |||
| 426 | switch (report->id) { | ||
| 427 | case REPORT_LED_STATE: | ||
| 428 | /* 1 data byte with GPO state */ | ||
| 429 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 430 | "REPORT_LED_STATE", report->id, raw_size-1); | ||
| 431 | hid_debug_event(hdev, buff); | ||
| 432 | snprintf(buff, BUFF_SZ, "\tGPO state: 0x%02x\n", raw_data[1]); | ||
| 433 | hid_debug_event(hdev, buff); | ||
| 434 | break; | ||
| 435 | case REPORT_BRIGHTNESS: | ||
| 436 | /* 1 data byte with brightness */ | ||
| 437 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 438 | "REPORT_BRIGHTNESS", report->id, raw_size-1); | ||
| 439 | hid_debug_event(hdev, buff); | ||
| 440 | snprintf(buff, BUFF_SZ, "\tBrightness: 0x%02x\n", raw_data[1]); | ||
| 441 | hid_debug_event(hdev, buff); | ||
| 442 | break; | ||
| 443 | case REPORT_CONTRAST: | ||
| 444 | /* 1 data byte with contrast */ | ||
| 445 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 446 | "REPORT_CONTRAST", report->id, raw_size-1); | ||
| 447 | hid_debug_event(hdev, buff); | ||
| 448 | snprintf(buff, BUFF_SZ, "\tContrast: 0x%02x\n", raw_data[1]); | ||
| 449 | hid_debug_event(hdev, buff); | ||
| 450 | break; | ||
| 451 | case REPORT_RESET: | ||
| 452 | /* 2 data bytes with reset duration in ms */ | ||
| 453 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 454 | "REPORT_RESET", report->id, raw_size-1); | ||
| 455 | hid_debug_event(hdev, buff); | ||
| 456 | snprintf(buff, BUFF_SZ, "\tDuration: 0x%02x%02x (%dms)\n", | ||
| 457 | raw_data[2], raw_data[1], raw_data[2] << 8 | raw_data[1]); | ||
| 458 | hid_debug_event(hdev, buff); | ||
| 459 | break; | ||
| 460 | case REPORT_LCD_CMD: | ||
| 461 | /* 63 data bytes with LCD commands */ | ||
| 462 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 463 | "REPORT_LCD_CMD", report->id, raw_size-1); | ||
| 464 | hid_debug_event(hdev, buff); | ||
| 465 | /* TODO: format decoding */ | ||
| 466 | break; | ||
| 467 | case REPORT_LCD_DATA: | ||
| 468 | /* 63 data bytes with LCD data */ | ||
| 469 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 470 | "REPORT_LCD_CMD", report->id, raw_size-1); | ||
| 471 | /* TODO: format decoding */ | ||
| 472 | hid_debug_event(hdev, buff); | ||
| 473 | break; | ||
| 474 | case REPORT_LCD_CMD_DATA: | ||
| 475 | /* 63 data bytes with LCD commands and data */ | ||
| 476 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 477 | "REPORT_LCD_CMD", report->id, raw_size-1); | ||
| 478 | /* TODO: format decoding */ | ||
| 479 | hid_debug_event(hdev, buff); | ||
| 480 | break; | ||
| 481 | case REPORT_EE_READ: | ||
| 482 | /* 3 data bytes with read area description */ | ||
| 483 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 484 | "REPORT_EE_READ", report->id, raw_size-1); | ||
| 485 | hid_debug_event(hdev, buff); | ||
| 486 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
| 487 | raw_data[2], raw_data[1]); | ||
| 488 | hid_debug_event(hdev, buff); | ||
| 489 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
| 490 | hid_debug_event(hdev, buff); | ||
| 491 | break; | ||
| 492 | case REPORT_EE_WRITE: | ||
| 493 | /* 3+1..20 data bytes with write area description */ | ||
| 494 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 495 | "REPORT_EE_WRITE", report->id, raw_size-1); | ||
| 496 | hid_debug_event(hdev, buff); | ||
| 497 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
| 498 | raw_data[2], raw_data[1]); | ||
| 499 | hid_debug_event(hdev, buff); | ||
| 500 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
| 501 | hid_debug_event(hdev, buff); | ||
| 502 | if (raw_data[3] == 0) { | ||
| 503 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
| 504 | } else if (raw_data[3] + 4 <= raw_size) { | ||
| 505 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
| 506 | hid_debug_event(hdev, buff); | ||
| 507 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
| 508 | } else { | ||
| 509 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
| 510 | } | ||
| 511 | hid_debug_event(hdev, buff); | ||
| 512 | break; | ||
| 513 | case REPORT_ERASE_MEMORY: | ||
| 514 | case REPORT_BL_ERASE_MEMORY: | ||
| 515 | /* 3 data bytes with pointer inside erase block */ | ||
| 516 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 517 | "REPORT_ERASE_MEMORY", report->id, raw_size-1); | ||
| 518 | hid_debug_event(hdev, buff); | ||
| 519 | switch (data->addr_sz) { | ||
| 520 | case 2: | ||
| 521 | snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x\n", | ||
| 522 | raw_data[2], raw_data[1]); | ||
| 523 | break; | ||
| 524 | case 3: | ||
| 525 | snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x%02x\n", | ||
| 526 | raw_data[3], raw_data[2], raw_data[1]); | ||
| 527 | break; | ||
| 528 | default: | ||
| 529 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
| 530 | } | ||
| 531 | hid_debug_event(hdev, buff); | ||
| 532 | break; | ||
| 533 | case REPORT_READ_MEMORY: | ||
| 534 | case REPORT_BL_READ_MEMORY: | ||
| 535 | /* 4 data bytes with read area description */ | ||
| 536 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 537 | "REPORT_READ_MEMORY", report->id, raw_size-1); | ||
| 538 | hid_debug_event(hdev, buff); | ||
| 539 | switch (data->addr_sz) { | ||
| 540 | case 2: | ||
| 541 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
| 542 | raw_data[2], raw_data[1]); | ||
| 543 | hid_debug_event(hdev, buff); | ||
| 544 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
| 545 | break; | ||
| 546 | case 3: | ||
| 547 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n", | ||
| 548 | raw_data[3], raw_data[2], raw_data[1]); | ||
| 549 | hid_debug_event(hdev, buff); | ||
| 550 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]); | ||
| 551 | break; | ||
| 552 | default: | ||
| 553 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
| 554 | } | ||
| 555 | hid_debug_event(hdev, buff); | ||
| 556 | break; | ||
| 557 | case REPORT_WRITE_MEMORY: | ||
| 558 | case REPORT_BL_WRITE_MEMORY: | ||
| 559 | /* 4+1..32 data bytes with write adrea description */ | ||
| 560 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 561 | "REPORT_WRITE_MEMORY", report->id, raw_size-1); | ||
| 562 | hid_debug_event(hdev, buff); | ||
| 563 | switch (data->addr_sz) { | ||
| 564 | case 2: | ||
| 565 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
| 566 | raw_data[2], raw_data[1]); | ||
| 567 | hid_debug_event(hdev, buff); | ||
| 568 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
| 569 | hid_debug_event(hdev, buff); | ||
| 570 | if (raw_data[3] == 0) { | ||
| 571 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
| 572 | } else if (raw_data[3] + 4 <= raw_size) { | ||
| 573 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
| 574 | hid_debug_event(hdev, buff); | ||
| 575 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
| 576 | } else { | ||
| 577 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
| 578 | } | ||
| 579 | break; | ||
| 580 | case 3: | ||
| 581 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n", | ||
| 582 | raw_data[3], raw_data[2], raw_data[1]); | ||
| 583 | hid_debug_event(hdev, buff); | ||
| 584 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]); | ||
| 585 | hid_debug_event(hdev, buff); | ||
| 586 | if (raw_data[4] == 0) { | ||
| 587 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
| 588 | } else if (raw_data[4] + 5 <= raw_size) { | ||
| 589 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
| 590 | hid_debug_event(hdev, buff); | ||
| 591 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]); | ||
| 592 | } else { | ||
| 593 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
| 594 | } | ||
| 595 | break; | ||
| 596 | default: | ||
| 597 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
| 598 | } | ||
| 599 | hid_debug_event(hdev, buff); | ||
| 600 | break; | ||
| 601 | case REPORT_SPLASH_RESTART: | ||
| 602 | /* TODO */ | ||
| 603 | break; | ||
| 604 | case REPORT_EXIT_KEYBOARD: | ||
| 605 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 606 | "REPORT_EXIT_KEYBOARD", report->id, raw_size-1); | ||
| 607 | hid_debug_event(hdev, buff); | ||
| 608 | snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n", | ||
| 609 | raw_data[1] | (raw_data[2] << 8), | ||
| 610 | raw_data[2], raw_data[1]); | ||
| 611 | hid_debug_event(hdev, buff); | ||
| 612 | break; | ||
| 613 | case REPORT_VERSION: | ||
| 614 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 615 | "REPORT_VERSION", report->id, raw_size-1); | ||
| 616 | hid_debug_event(hdev, buff); | ||
| 617 | break; | ||
| 618 | case REPORT_DEVID: | ||
| 619 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 620 | "REPORT_DEVID", report->id, raw_size-1); | ||
| 621 | hid_debug_event(hdev, buff); | ||
| 622 | break; | ||
| 623 | case REPORT_SPLASH_SIZE: | ||
| 624 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 625 | "REPORT_SPLASH_SIZE", report->id, raw_size-1); | ||
| 626 | hid_debug_event(hdev, buff); | ||
| 627 | break; | ||
| 628 | case REPORT_HOOK_VERSION: | ||
| 629 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 630 | "REPORT_HOOK_VERSION", report->id, raw_size-1); | ||
| 631 | hid_debug_event(hdev, buff); | ||
| 632 | break; | ||
| 633 | case REPORT_EXIT_FLASHER: | ||
| 634 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 635 | "REPORT_VERSION", report->id, raw_size-1); | ||
| 636 | hid_debug_event(hdev, buff); | ||
| 637 | snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n", | ||
| 638 | raw_data[1] | (raw_data[2] << 8), | ||
| 639 | raw_data[2], raw_data[1]); | ||
| 640 | hid_debug_event(hdev, buff); | ||
| 641 | break; | ||
| 642 | default: | ||
| 643 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
| 644 | "<unknown>", report->id, raw_size-1); | ||
| 645 | hid_debug_event(hdev, buff); | ||
| 646 | break; | ||
| 647 | } | ||
| 648 | wake_up_interruptible(&hdev->debug_wait); | ||
| 649 | kfree(buff); | ||
| 650 | } | ||
| 651 | |||
| 652 | void picolcd_debug_raw_event(struct picolcd_data *data, | ||
| 653 | struct hid_device *hdev, struct hid_report *report, | ||
| 654 | u8 *raw_data, int size) | ||
| 655 | { | ||
| 656 | char *buff; | ||
| 657 | |||
| 658 | #define BUFF_SZ 256 | ||
| 659 | /* Avoid unnecessary overhead if debugfs is disabled */ | ||
| 660 | if (list_empty(&hdev->debug_list)) | ||
| 661 | return; | ||
| 662 | |||
| 663 | buff = kmalloc(BUFF_SZ, GFP_ATOMIC); | ||
| 664 | if (!buff) | ||
| 665 | return; | ||
| 666 | |||
| 667 | switch (report->id) { | ||
| 668 | case REPORT_ERROR_CODE: | ||
| 669 | /* 2 data bytes with affected report and error code */ | ||
| 670 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 671 | "REPORT_ERROR_CODE", report->id, size-1); | ||
| 672 | hid_debug_event(hdev, buff); | ||
| 673 | if (raw_data[2] < ARRAY_SIZE(error_codes)) | ||
| 674 | snprintf(buff, BUFF_SZ, "\tError code 0x%02x (%s) in reply to report 0x%02x\n", | ||
| 675 | raw_data[2], error_codes[raw_data[2]], raw_data[1]); | ||
| 676 | else | ||
| 677 | snprintf(buff, BUFF_SZ, "\tError code 0x%02x in reply to report 0x%02x\n", | ||
| 678 | raw_data[2], raw_data[1]); | ||
| 679 | hid_debug_event(hdev, buff); | ||
| 680 | break; | ||
| 681 | case REPORT_KEY_STATE: | ||
| 682 | /* 2 data bytes with key state */ | ||
| 683 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 684 | "REPORT_KEY_STATE", report->id, size-1); | ||
| 685 | hid_debug_event(hdev, buff); | ||
| 686 | if (raw_data[1] == 0) | ||
| 687 | snprintf(buff, BUFF_SZ, "\tNo key pressed\n"); | ||
| 688 | else if (raw_data[2] == 0) | ||
| 689 | snprintf(buff, BUFF_SZ, "\tOne key pressed: 0x%02x (%d)\n", | ||
| 690 | raw_data[1], raw_data[1]); | ||
| 691 | else | ||
| 692 | snprintf(buff, BUFF_SZ, "\tTwo keys pressed: 0x%02x (%d), 0x%02x (%d)\n", | ||
| 693 | raw_data[1], raw_data[1], raw_data[2], raw_data[2]); | ||
| 694 | hid_debug_event(hdev, buff); | ||
| 695 | break; | ||
| 696 | case REPORT_IR_DATA: | ||
| 697 | /* Up to 20 byes of IR scancode data */ | ||
| 698 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 699 | "REPORT_IR_DATA", report->id, size-1); | ||
| 700 | hid_debug_event(hdev, buff); | ||
| 701 | if (raw_data[1] == 0) { | ||
| 702 | snprintf(buff, BUFF_SZ, "\tUnexpectedly 0 data length\n"); | ||
| 703 | hid_debug_event(hdev, buff); | ||
| 704 | } else if (raw_data[1] + 1 <= size) { | ||
| 705 | snprintf(buff, BUFF_SZ, "\tData length: %d\n\tIR Data: ", | ||
| 706 | raw_data[1]); | ||
| 707 | hid_debug_event(hdev, buff); | ||
| 708 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+2, raw_data[1]); | ||
| 709 | hid_debug_event(hdev, buff); | ||
| 710 | } else { | ||
| 711 | snprintf(buff, BUFF_SZ, "\tOverflowing data length: %d\n", | ||
| 712 | raw_data[1]-1); | ||
| 713 | hid_debug_event(hdev, buff); | ||
| 714 | } | ||
| 715 | break; | ||
| 716 | case REPORT_EE_DATA: | ||
| 717 | /* Data buffer in response to REPORT_EE_READ or REPORT_EE_WRITE */ | ||
| 718 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 719 | "REPORT_EE_DATA", report->id, size-1); | ||
| 720 | hid_debug_event(hdev, buff); | ||
| 721 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
| 722 | raw_data[2], raw_data[1]); | ||
| 723 | hid_debug_event(hdev, buff); | ||
| 724 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
| 725 | hid_debug_event(hdev, buff); | ||
| 726 | if (raw_data[3] == 0) { | ||
| 727 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
| 728 | hid_debug_event(hdev, buff); | ||
| 729 | } else if (raw_data[3] + 4 <= size) { | ||
| 730 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
| 731 | hid_debug_event(hdev, buff); | ||
| 732 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
| 733 | hid_debug_event(hdev, buff); | ||
| 734 | } else { | ||
| 735 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
| 736 | hid_debug_event(hdev, buff); | ||
| 737 | } | ||
| 738 | break; | ||
| 739 | case REPORT_MEMORY: | ||
| 740 | /* Data buffer in response to REPORT_READ_MEMORY or REPORT_WRTIE_MEMORY */ | ||
| 741 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 742 | "REPORT_MEMORY", report->id, size-1); | ||
| 743 | hid_debug_event(hdev, buff); | ||
| 744 | switch (data->addr_sz) { | ||
| 745 | case 2: | ||
| 746 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
| 747 | raw_data[2], raw_data[1]); | ||
| 748 | hid_debug_event(hdev, buff); | ||
| 749 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
| 750 | hid_debug_event(hdev, buff); | ||
| 751 | if (raw_data[3] == 0) { | ||
| 752 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
| 753 | } else if (raw_data[3] + 4 <= size) { | ||
| 754 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
| 755 | hid_debug_event(hdev, buff); | ||
| 756 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
| 757 | } else { | ||
| 758 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
| 759 | } | ||
| 760 | break; | ||
| 761 | case 3: | ||
| 762 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n", | ||
| 763 | raw_data[3], raw_data[2], raw_data[1]); | ||
| 764 | hid_debug_event(hdev, buff); | ||
| 765 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]); | ||
| 766 | hid_debug_event(hdev, buff); | ||
| 767 | if (raw_data[4] == 0) { | ||
| 768 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
| 769 | } else if (raw_data[4] + 5 <= size) { | ||
| 770 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
| 771 | hid_debug_event(hdev, buff); | ||
| 772 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]); | ||
| 773 | } else { | ||
| 774 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
| 775 | } | ||
| 776 | break; | ||
| 777 | default: | ||
| 778 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
| 779 | } | ||
| 780 | hid_debug_event(hdev, buff); | ||
| 781 | break; | ||
| 782 | case REPORT_VERSION: | ||
| 783 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 784 | "REPORT_VERSION", report->id, size-1); | ||
| 785 | hid_debug_event(hdev, buff); | ||
| 786 | snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n", | ||
| 787 | raw_data[2], raw_data[1]); | ||
| 788 | hid_debug_event(hdev, buff); | ||
| 789 | break; | ||
| 790 | case REPORT_BL_ERASE_MEMORY: | ||
| 791 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 792 | "REPORT_BL_ERASE_MEMORY", report->id, size-1); | ||
| 793 | hid_debug_event(hdev, buff); | ||
| 794 | /* TODO */ | ||
| 795 | break; | ||
| 796 | case REPORT_BL_READ_MEMORY: | ||
| 797 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 798 | "REPORT_BL_READ_MEMORY", report->id, size-1); | ||
| 799 | hid_debug_event(hdev, buff); | ||
| 800 | /* TODO */ | ||
| 801 | break; | ||
| 802 | case REPORT_BL_WRITE_MEMORY: | ||
| 803 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 804 | "REPORT_BL_WRITE_MEMORY", report->id, size-1); | ||
| 805 | hid_debug_event(hdev, buff); | ||
| 806 | /* TODO */ | ||
| 807 | break; | ||
| 808 | case REPORT_DEVID: | ||
| 809 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 810 | "REPORT_DEVID", report->id, size-1); | ||
| 811 | hid_debug_event(hdev, buff); | ||
| 812 | snprintf(buff, BUFF_SZ, "\tSerial: 0x%02x%02x%02x%02x\n", | ||
| 813 | raw_data[1], raw_data[2], raw_data[3], raw_data[4]); | ||
| 814 | hid_debug_event(hdev, buff); | ||
| 815 | snprintf(buff, BUFF_SZ, "\tType: 0x%02x\n", | ||
| 816 | raw_data[5]); | ||
| 817 | hid_debug_event(hdev, buff); | ||
| 818 | break; | ||
| 819 | case REPORT_SPLASH_SIZE: | ||
| 820 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 821 | "REPORT_SPLASH_SIZE", report->id, size-1); | ||
| 822 | hid_debug_event(hdev, buff); | ||
| 823 | snprintf(buff, BUFF_SZ, "\tTotal splash space: %d\n", | ||
| 824 | (raw_data[2] << 8) | raw_data[1]); | ||
| 825 | hid_debug_event(hdev, buff); | ||
| 826 | snprintf(buff, BUFF_SZ, "\tUsed splash space: %d\n", | ||
| 827 | (raw_data[4] << 8) | raw_data[3]); | ||
| 828 | hid_debug_event(hdev, buff); | ||
| 829 | break; | ||
| 830 | case REPORT_HOOK_VERSION: | ||
| 831 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 832 | "REPORT_HOOK_VERSION", report->id, size-1); | ||
| 833 | hid_debug_event(hdev, buff); | ||
| 834 | snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n", | ||
| 835 | raw_data[1], raw_data[2]); | ||
| 836 | hid_debug_event(hdev, buff); | ||
| 837 | break; | ||
| 838 | default: | ||
| 839 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
| 840 | "<unknown>", report->id, size-1); | ||
| 841 | hid_debug_event(hdev, buff); | ||
| 842 | break; | ||
| 843 | } | ||
| 844 | wake_up_interruptible(&hdev->debug_wait); | ||
| 845 | kfree(buff); | ||
| 846 | } | ||
| 847 | |||
| 848 | void picolcd_init_devfs(struct picolcd_data *data, | ||
| 849 | struct hid_report *eeprom_r, struct hid_report *eeprom_w, | ||
| 850 | struct hid_report *flash_r, struct hid_report *flash_w, | ||
| 851 | struct hid_report *reset) | ||
| 852 | { | ||
| 853 | struct hid_device *hdev = data->hdev; | ||
| 854 | |||
| 855 | mutex_init(&data->mutex_flash); | ||
| 856 | |||
| 857 | /* reset */ | ||
| 858 | if (reset) | ||
| 859 | data->debug_reset = debugfs_create_file("reset", 0600, | ||
| 860 | hdev->debug_dir, data, &picolcd_debug_reset_fops); | ||
| 861 | |||
| 862 | /* eeprom */ | ||
| 863 | if (eeprom_r || eeprom_w) | ||
| 864 | data->debug_eeprom = debugfs_create_file("eeprom", | ||
| 865 | (eeprom_w ? S_IWUSR : 0) | (eeprom_r ? S_IRUSR : 0), | ||
| 866 | hdev->debug_dir, data, &picolcd_debug_eeprom_fops); | ||
| 867 | |||
| 868 | /* flash */ | ||
| 869 | if (flash_r && flash_r->maxfield == 1 && flash_r->field[0]->report_size == 8) | ||
| 870 | data->addr_sz = flash_r->field[0]->report_count - 1; | ||
| 871 | else | ||
| 872 | data->addr_sz = -1; | ||
| 873 | if (data->addr_sz == 2 || data->addr_sz == 3) { | ||
| 874 | data->debug_flash = debugfs_create_file("flash", | ||
| 875 | (flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0), | ||
| 876 | hdev->debug_dir, data, &picolcd_debug_flash_fops); | ||
| 877 | } else if (flash_r || flash_w) | ||
| 878 | hid_warn(hdev, "Unexpected FLASH access reports, please submit rdesc for review\n"); | ||
| 879 | } | ||
| 880 | |||
| 881 | void picolcd_exit_devfs(struct picolcd_data *data) | ||
| 882 | { | ||
| 883 | struct dentry *dent; | ||
| 884 | |||
| 885 | dent = data->debug_reset; | ||
| 886 | data->debug_reset = NULL; | ||
| 887 | if (dent) | ||
| 888 | debugfs_remove(dent); | ||
| 889 | dent = data->debug_eeprom; | ||
| 890 | data->debug_eeprom = NULL; | ||
| 891 | if (dent) | ||
| 892 | debugfs_remove(dent); | ||
| 893 | dent = data->debug_flash; | ||
| 894 | data->debug_flash = NULL; | ||
| 895 | if (dent) | ||
| 896 | debugfs_remove(dent); | ||
| 897 | mutex_destroy(&data->mutex_flash); | ||
| 898 | } | ||
| 899 | |||
diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c new file mode 100644 index 000000000000..0008a512211d --- /dev/null +++ b/drivers/hid/hid-picolcd_fb.c | |||
| @@ -0,0 +1,615 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> * | ||
| 3 | * * | ||
| 4 | * Based on Logitech G13 driver (v0.4) * | ||
| 5 | * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * | ||
| 6 | * * | ||
| 7 | * This program is free software: you can redistribute it and/or modify * | ||
| 8 | * it under the terms of the GNU General Public License as published by * | ||
| 9 | * the Free Software Foundation, version 2 of the License. * | ||
| 10 | * * | ||
| 11 | * This driver is distributed in the hope that it will be useful, but * | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * | ||
| 14 | * General Public License for more details. * | ||
| 15 | * * | ||
| 16 | * You should have received a copy of the GNU General Public License * | ||
| 17 | * along with this software. If not see <http://www.gnu.org/licenses/>. * | ||
| 18 | ***************************************************************************/ | ||
| 19 | |||
| 20 | #include <linux/hid.h> | ||
| 21 | #include <linux/vmalloc.h> | ||
| 22 | #include "usbhid/usbhid.h" | ||
| 23 | #include <linux/usb.h> | ||
| 24 | |||
| 25 | #include <linux/fb.h> | ||
| 26 | #include <linux/module.h> | ||
| 27 | |||
| 28 | #include "hid-picolcd.h" | ||
| 29 | |||
| 30 | /* Framebuffer | ||
| 31 | * | ||
| 32 | * The PicoLCD use a Topway LCD module of 256x64 pixel | ||
| 33 | * This display area is tiled over 4 controllers with 8 tiles | ||
| 34 | * each. Each tile has 8x64 pixel, each data byte representing | ||
| 35 | * a 1-bit wide vertical line of the tile. | ||
| 36 | * | ||
| 37 | * The display can be updated at a tile granularity. | ||
| 38 | * | ||
| 39 | * Chip 1 Chip 2 Chip 3 Chip 4 | ||
| 40 | * +----------------+----------------+----------------+----------------+ | ||
| 41 | * | Tile 1 | Tile 1 | Tile 1 | Tile 1 | | ||
| 42 | * +----------------+----------------+----------------+----------------+ | ||
| 43 | * | Tile 2 | Tile 2 | Tile 2 | Tile 2 | | ||
| 44 | * +----------------+----------------+----------------+----------------+ | ||
| 45 | * ... | ||
| 46 | * +----------------+----------------+----------------+----------------+ | ||
| 47 | * | Tile 8 | Tile 8 | Tile 8 | Tile 8 | | ||
| 48 | * +----------------+----------------+----------------+----------------+ | ||
| 49 | */ | ||
| 50 | #define PICOLCDFB_NAME "picolcdfb" | ||
| 51 | #define PICOLCDFB_WIDTH (256) | ||
| 52 | #define PICOLCDFB_HEIGHT (64) | ||
| 53 | #define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8) | ||
| 54 | |||
| 55 | #define PICOLCDFB_UPDATE_RATE_LIMIT 10 | ||
| 56 | #define PICOLCDFB_UPDATE_RATE_DEFAULT 2 | ||
| 57 | |||
| 58 | /* Framebuffer visual structures */ | ||
| 59 | static const struct fb_fix_screeninfo picolcdfb_fix = { | ||
| 60 | .id = PICOLCDFB_NAME, | ||
| 61 | .type = FB_TYPE_PACKED_PIXELS, | ||
| 62 | .visual = FB_VISUAL_MONO01, | ||
| 63 | .xpanstep = 0, | ||
| 64 | .ypanstep = 0, | ||
| 65 | .ywrapstep = 0, | ||
| 66 | .line_length = PICOLCDFB_WIDTH / 8, | ||
| 67 | .accel = FB_ACCEL_NONE, | ||
| 68 | }; | ||
| 69 | |||
| 70 | static const struct fb_var_screeninfo picolcdfb_var = { | ||
| 71 | .xres = PICOLCDFB_WIDTH, | ||
| 72 | .yres = PICOLCDFB_HEIGHT, | ||
| 73 | .xres_virtual = PICOLCDFB_WIDTH, | ||
| 74 | .yres_virtual = PICOLCDFB_HEIGHT, | ||
| 75 | .width = 103, | ||
| 76 | .height = 26, | ||
| 77 | .bits_per_pixel = 1, | ||
| 78 | .grayscale = 1, | ||
| 79 | .red = { | ||
| 80 | .offset = 0, | ||
| 81 | .length = 1, | ||
| 82 | .msb_right = 0, | ||
| 83 | }, | ||
| 84 | .green = { | ||
| 85 | .offset = 0, | ||
| 86 | .length = 1, | ||
| 87 | .msb_right = 0, | ||
| 88 | }, | ||
| 89 | .blue = { | ||
| 90 | .offset = 0, | ||
| 91 | .length = 1, | ||
| 92 | .msb_right = 0, | ||
| 93 | }, | ||
| 94 | .transp = { | ||
| 95 | .offset = 0, | ||
| 96 | .length = 0, | ||
| 97 | .msb_right = 0, | ||
| 98 | }, | ||
| 99 | }; | ||
| 100 | |||
| 101 | /* Send a given tile to PicoLCD */ | ||
| 102 | static int picolcd_fb_send_tile(struct picolcd_data *data, u8 *vbitmap, | ||
| 103 | int chip, int tile) | ||
| 104 | { | ||
| 105 | struct hid_report *report1, *report2; | ||
| 106 | unsigned long flags; | ||
| 107 | u8 *tdata; | ||
| 108 | int i; | ||
| 109 | |||
| 110 | report1 = picolcd_out_report(REPORT_LCD_CMD_DATA, data->hdev); | ||
| 111 | if (!report1 || report1->maxfield != 1) | ||
| 112 | return -ENODEV; | ||
| 113 | report2 = picolcd_out_report(REPORT_LCD_DATA, data->hdev); | ||
| 114 | if (!report2 || report2->maxfield != 1) | ||
| 115 | return -ENODEV; | ||
| 116 | |||
| 117 | spin_lock_irqsave(&data->lock, flags); | ||
| 118 | if ((data->status & PICOLCD_FAILED)) { | ||
| 119 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 120 | return -ENODEV; | ||
| 121 | } | ||
| 122 | hid_set_field(report1->field[0], 0, chip << 2); | ||
| 123 | hid_set_field(report1->field[0], 1, 0x02); | ||
| 124 | hid_set_field(report1->field[0], 2, 0x00); | ||
| 125 | hid_set_field(report1->field[0], 3, 0x00); | ||
| 126 | hid_set_field(report1->field[0], 4, 0xb8 | tile); | ||
| 127 | hid_set_field(report1->field[0], 5, 0x00); | ||
| 128 | hid_set_field(report1->field[0], 6, 0x00); | ||
| 129 | hid_set_field(report1->field[0], 7, 0x40); | ||
| 130 | hid_set_field(report1->field[0], 8, 0x00); | ||
| 131 | hid_set_field(report1->field[0], 9, 0x00); | ||
| 132 | hid_set_field(report1->field[0], 10, 32); | ||
| 133 | |||
| 134 | hid_set_field(report2->field[0], 0, (chip << 2) | 0x01); | ||
| 135 | hid_set_field(report2->field[0], 1, 0x00); | ||
| 136 | hid_set_field(report2->field[0], 2, 0x00); | ||
| 137 | hid_set_field(report2->field[0], 3, 32); | ||
| 138 | |||
| 139 | tdata = vbitmap + (tile * 4 + chip) * 64; | ||
| 140 | for (i = 0; i < 64; i++) | ||
| 141 | if (i < 32) | ||
| 142 | hid_set_field(report1->field[0], 11 + i, tdata[i]); | ||
| 143 | else | ||
| 144 | hid_set_field(report2->field[0], 4 + i - 32, tdata[i]); | ||
| 145 | |||
| 146 | usbhid_submit_report(data->hdev, report1, USB_DIR_OUT); | ||
| 147 | usbhid_submit_report(data->hdev, report2, USB_DIR_OUT); | ||
| 148 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 149 | return 0; | ||
| 150 | } | ||
| 151 | |||
| 152 | /* Translate a single tile*/ | ||
| 153 | static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp, | ||
| 154 | int chip, int tile) | ||
| 155 | { | ||
| 156 | int i, b, changed = 0; | ||
| 157 | u8 tdata[64]; | ||
| 158 | u8 *vdata = vbitmap + (tile * 4 + chip) * 64; | ||
| 159 | |||
| 160 | if (bpp == 1) { | ||
| 161 | for (b = 7; b >= 0; b--) { | ||
| 162 | const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32; | ||
| 163 | for (i = 0; i < 64; i++) { | ||
| 164 | tdata[i] <<= 1; | ||
| 165 | tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | } else if (bpp == 8) { | ||
| 169 | for (b = 7; b >= 0; b--) { | ||
| 170 | const u8 *bdata = bitmap + (tile * 256 + chip * 8 + b * 32) * 8; | ||
| 171 | for (i = 0; i < 64; i++) { | ||
| 172 | tdata[i] <<= 1; | ||
| 173 | tdata[i] |= (bdata[i] & 0x80) ? 0x01 : 0x00; | ||
| 174 | } | ||
| 175 | } | ||
| 176 | } else { | ||
| 177 | /* Oops, we should never get here! */ | ||
| 178 | WARN_ON(1); | ||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | for (i = 0; i < 64; i++) | ||
| 183 | if (tdata[i] != vdata[i]) { | ||
| 184 | changed = 1; | ||
| 185 | vdata[i] = tdata[i]; | ||
| 186 | } | ||
| 187 | return changed; | ||
| 188 | } | ||
| 189 | |||
| 190 | void picolcd_fb_refresh(struct picolcd_data *data) | ||
| 191 | { | ||
| 192 | if (data->fb_info) | ||
| 193 | schedule_delayed_work(&data->fb_info->deferred_work, 0); | ||
| 194 | } | ||
| 195 | |||
| 196 | /* Reconfigure LCD display */ | ||
| 197 | int picolcd_fb_reset(struct picolcd_data *data, int clear) | ||
| 198 | { | ||
| 199 | struct hid_report *report = picolcd_out_report(REPORT_LCD_CMD, data->hdev); | ||
| 200 | struct picolcd_fb_data *fbdata = data->fb_info->par; | ||
| 201 | int i, j; | ||
| 202 | unsigned long flags; | ||
| 203 | static const u8 mapcmd[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 }; | ||
| 204 | |||
| 205 | if (!report || report->maxfield != 1) | ||
| 206 | return -ENODEV; | ||
| 207 | |||
| 208 | spin_lock_irqsave(&data->lock, flags); | ||
| 209 | for (i = 0; i < 4; i++) { | ||
| 210 | for (j = 0; j < report->field[0]->maxusage; j++) | ||
| 211 | if (j == 0) | ||
| 212 | hid_set_field(report->field[0], j, i << 2); | ||
| 213 | else if (j < sizeof(mapcmd)) | ||
| 214 | hid_set_field(report->field[0], j, mapcmd[j]); | ||
| 215 | else | ||
| 216 | hid_set_field(report->field[0], j, 0); | ||
| 217 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
| 218 | } | ||
| 219 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 220 | |||
| 221 | if (clear) { | ||
| 222 | memset(fbdata->vbitmap, 0, PICOLCDFB_SIZE); | ||
| 223 | memset(fbdata->bitmap, 0, PICOLCDFB_SIZE*fbdata->bpp); | ||
| 224 | } | ||
| 225 | fbdata->force = 1; | ||
| 226 | |||
| 227 | /* schedule first output of framebuffer */ | ||
| 228 | if (fbdata->ready) | ||
| 229 | schedule_delayed_work(&data->fb_info->deferred_work, 0); | ||
| 230 | else | ||
| 231 | fbdata->ready = 1; | ||
| 232 | |||
| 233 | return 0; | ||
| 234 | } | ||
| 235 | |||
| 236 | /* Update fb_vbitmap from the screen_base and send changed tiles to device */ | ||
| 237 | static void picolcd_fb_update(struct fb_info *info) | ||
| 238 | { | ||
| 239 | int chip, tile, n; | ||
| 240 | unsigned long flags; | ||
| 241 | struct picolcd_fb_data *fbdata = info->par; | ||
| 242 | struct picolcd_data *data; | ||
| 243 | |||
| 244 | mutex_lock(&info->lock); | ||
| 245 | |||
| 246 | spin_lock_irqsave(&fbdata->lock, flags); | ||
| 247 | if (!fbdata->ready && fbdata->picolcd) | ||
| 248 | picolcd_fb_reset(fbdata->picolcd, 0); | ||
| 249 | spin_unlock_irqrestore(&fbdata->lock, flags); | ||
| 250 | |||
| 251 | /* | ||
| 252 | * Translate the framebuffer into the format needed by the PicoLCD. | ||
| 253 | * See display layout above. | ||
| 254 | * Do this one tile after the other and push those tiles that changed. | ||
| 255 | * | ||
| 256 | * Wait for our IO to complete as otherwise we might flood the queue! | ||
| 257 | */ | ||
| 258 | n = 0; | ||
| 259 | for (chip = 0; chip < 4; chip++) | ||
| 260 | for (tile = 0; tile < 8; tile++) { | ||
| 261 | if (!fbdata->force && !picolcd_fb_update_tile( | ||
| 262 | fbdata->vbitmap, fbdata->bitmap, | ||
| 263 | fbdata->bpp, chip, tile)) | ||
| 264 | continue; | ||
| 265 | n += 2; | ||
| 266 | if (n >= HID_OUTPUT_FIFO_SIZE / 2) { | ||
| 267 | spin_lock_irqsave(&fbdata->lock, flags); | ||
| 268 | data = fbdata->picolcd; | ||
| 269 | spin_unlock_irqrestore(&fbdata->lock, flags); | ||
| 270 | mutex_unlock(&info->lock); | ||
| 271 | if (!data) | ||
| 272 | return; | ||
| 273 | usbhid_wait_io(data->hdev); | ||
| 274 | mutex_lock(&info->lock); | ||
| 275 | n = 0; | ||
| 276 | } | ||
| 277 | spin_lock_irqsave(&fbdata->lock, flags); | ||
| 278 | data = fbdata->picolcd; | ||
| 279 | spin_unlock_irqrestore(&fbdata->lock, flags); | ||
| 280 | if (!data || picolcd_fb_send_tile(data, | ||
| 281 | fbdata->vbitmap, chip, tile)) | ||
| 282 | goto out; | ||
| 283 | } | ||
| 284 | fbdata->force = false; | ||
| 285 | if (n) { | ||
| 286 | spin_lock_irqsave(&fbdata->lock, flags); | ||
| 287 | data = fbdata->picolcd; | ||
| 288 | spin_unlock_irqrestore(&fbdata->lock, flags); | ||
| 289 | mutex_unlock(&info->lock); | ||
| 290 | if (data) | ||
| 291 | usbhid_wait_io(data->hdev); | ||
| 292 | return; | ||
| 293 | } | ||
| 294 | out: | ||
| 295 | mutex_unlock(&info->lock); | ||
| 296 | } | ||
| 297 | |||
| 298 | /* Stub to call the system default and update the image on the picoLCD */ | ||
| 299 | static void picolcd_fb_fillrect(struct fb_info *info, | ||
| 300 | const struct fb_fillrect *rect) | ||
| 301 | { | ||
| 302 | if (!info->par) | ||
| 303 | return; | ||
| 304 | sys_fillrect(info, rect); | ||
| 305 | |||
| 306 | schedule_delayed_work(&info->deferred_work, 0); | ||
| 307 | } | ||
| 308 | |||
| 309 | /* Stub to call the system default and update the image on the picoLCD */ | ||
| 310 | static void picolcd_fb_copyarea(struct fb_info *info, | ||
| 311 | const struct fb_copyarea *area) | ||
| 312 | { | ||
| 313 | if (!info->par) | ||
| 314 | return; | ||
| 315 | sys_copyarea(info, area); | ||
| 316 | |||
| 317 | schedule_delayed_work(&info->deferred_work, 0); | ||
| 318 | } | ||
| 319 | |||
| 320 | /* Stub to call the system default and update the image on the picoLCD */ | ||
| 321 | static void picolcd_fb_imageblit(struct fb_info *info, const struct fb_image *image) | ||
| 322 | { | ||
| 323 | if (!info->par) | ||
| 324 | return; | ||
| 325 | sys_imageblit(info, image); | ||
| 326 | |||
| 327 | schedule_delayed_work(&info->deferred_work, 0); | ||
| 328 | } | ||
| 329 | |||
| 330 | /* | ||
| 331 | * this is the slow path from userspace. they can seek and write to | ||
| 332 | * the fb. it's inefficient to do anything less than a full screen draw | ||
| 333 | */ | ||
| 334 | static ssize_t picolcd_fb_write(struct fb_info *info, const char __user *buf, | ||
| 335 | size_t count, loff_t *ppos) | ||
| 336 | { | ||
| 337 | ssize_t ret; | ||
| 338 | if (!info->par) | ||
| 339 | return -ENODEV; | ||
| 340 | ret = fb_sys_write(info, buf, count, ppos); | ||
| 341 | if (ret >= 0) | ||
| 342 | schedule_delayed_work(&info->deferred_work, 0); | ||
| 343 | return ret; | ||
| 344 | } | ||
| 345 | |||
| 346 | static int picolcd_fb_blank(int blank, struct fb_info *info) | ||
| 347 | { | ||
| 348 | /* We let fb notification do this for us via lcd/backlight device */ | ||
| 349 | return 0; | ||
| 350 | } | ||
| 351 | |||
| 352 | static void picolcd_fb_destroy(struct fb_info *info) | ||
| 353 | { | ||
| 354 | struct picolcd_fb_data *fbdata = info->par; | ||
| 355 | |||
| 356 | /* make sure no work is deferred */ | ||
| 357 | fb_deferred_io_cleanup(info); | ||
| 358 | |||
| 359 | /* No thridparty should ever unregister our framebuffer! */ | ||
| 360 | WARN_ON(fbdata->picolcd != NULL); | ||
| 361 | |||
| 362 | vfree((u8 *)info->fix.smem_start); | ||
| 363 | framebuffer_release(info); | ||
| 364 | } | ||
| 365 | |||
| 366 | static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||
| 367 | { | ||
| 368 | __u32 bpp = var->bits_per_pixel; | ||
| 369 | __u32 activate = var->activate; | ||
| 370 | |||
| 371 | /* only allow 1/8 bit depth (8-bit is grayscale) */ | ||
| 372 | *var = picolcdfb_var; | ||
| 373 | var->activate = activate; | ||
| 374 | if (bpp >= 8) { | ||
| 375 | var->bits_per_pixel = 8; | ||
| 376 | var->red.length = 8; | ||
| 377 | var->green.length = 8; | ||
| 378 | var->blue.length = 8; | ||
| 379 | } else { | ||
| 380 | var->bits_per_pixel = 1; | ||
| 381 | var->red.length = 1; | ||
| 382 | var->green.length = 1; | ||
| 383 | var->blue.length = 1; | ||
| 384 | } | ||
| 385 | return 0; | ||
| 386 | } | ||
| 387 | |||
| 388 | static int picolcd_set_par(struct fb_info *info) | ||
| 389 | { | ||
| 390 | struct picolcd_fb_data *fbdata = info->par; | ||
| 391 | u8 *tmp_fb, *o_fb; | ||
| 392 | if (info->var.bits_per_pixel == fbdata->bpp) | ||
| 393 | return 0; | ||
| 394 | /* switch between 1/8 bit depths */ | ||
| 395 | if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8) | ||
| 396 | return -EINVAL; | ||
| 397 | |||
| 398 | o_fb = fbdata->bitmap; | ||
| 399 | tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL); | ||
| 400 | if (!tmp_fb) | ||
| 401 | return -ENOMEM; | ||
| 402 | |||
| 403 | /* translate FB content to new bits-per-pixel */ | ||
| 404 | if (info->var.bits_per_pixel == 1) { | ||
| 405 | int i, b; | ||
| 406 | for (i = 0; i < PICOLCDFB_SIZE; i++) { | ||
| 407 | u8 p = 0; | ||
| 408 | for (b = 0; b < 8; b++) { | ||
| 409 | p <<= 1; | ||
| 410 | p |= o_fb[i*8+b] ? 0x01 : 0x00; | ||
| 411 | } | ||
| 412 | tmp_fb[i] = p; | ||
| 413 | } | ||
| 414 | memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE); | ||
| 415 | info->fix.visual = FB_VISUAL_MONO01; | ||
| 416 | info->fix.line_length = PICOLCDFB_WIDTH / 8; | ||
| 417 | } else { | ||
| 418 | int i; | ||
| 419 | memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE); | ||
| 420 | for (i = 0; i < PICOLCDFB_SIZE * 8; i++) | ||
| 421 | o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00; | ||
| 422 | info->fix.visual = FB_VISUAL_DIRECTCOLOR; | ||
| 423 | info->fix.line_length = PICOLCDFB_WIDTH; | ||
| 424 | } | ||
| 425 | |||
| 426 | kfree(tmp_fb); | ||
| 427 | fbdata->bpp = info->var.bits_per_pixel; | ||
| 428 | return 0; | ||
| 429 | } | ||
| 430 | |||
| 431 | /* Note this can't be const because of struct fb_info definition */ | ||
| 432 | static struct fb_ops picolcdfb_ops = { | ||
| 433 | .owner = THIS_MODULE, | ||
| 434 | .fb_destroy = picolcd_fb_destroy, | ||
| 435 | .fb_read = fb_sys_read, | ||
| 436 | .fb_write = picolcd_fb_write, | ||
| 437 | .fb_blank = picolcd_fb_blank, | ||
| 438 | .fb_fillrect = picolcd_fb_fillrect, | ||
| 439 | .fb_copyarea = picolcd_fb_copyarea, | ||
| 440 | .fb_imageblit = picolcd_fb_imageblit, | ||
| 441 | .fb_check_var = picolcd_fb_check_var, | ||
| 442 | .fb_set_par = picolcd_set_par, | ||
| 443 | }; | ||
| 444 | |||
| 445 | |||
| 446 | /* Callback from deferred IO workqueue */ | ||
| 447 | static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist) | ||
| 448 | { | ||
| 449 | picolcd_fb_update(info); | ||
| 450 | } | ||
| 451 | |||
| 452 | static const struct fb_deferred_io picolcd_fb_defio = { | ||
| 453 | .delay = HZ / PICOLCDFB_UPDATE_RATE_DEFAULT, | ||
| 454 | .deferred_io = picolcd_fb_deferred_io, | ||
| 455 | }; | ||
| 456 | |||
| 457 | |||
| 458 | /* | ||
| 459 | * The "fb_update_rate" sysfs attribute | ||
| 460 | */ | ||
| 461 | static ssize_t picolcd_fb_update_rate_show(struct device *dev, | ||
| 462 | struct device_attribute *attr, char *buf) | ||
| 463 | { | ||
| 464 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
| 465 | struct picolcd_fb_data *fbdata = data->fb_info->par; | ||
| 466 | unsigned i, fb_update_rate = fbdata->update_rate; | ||
| 467 | size_t ret = 0; | ||
| 468 | |||
| 469 | for (i = 1; i <= PICOLCDFB_UPDATE_RATE_LIMIT; i++) | ||
| 470 | if (ret >= PAGE_SIZE) | ||
| 471 | break; | ||
| 472 | else if (i == fb_update_rate) | ||
| 473 | ret += snprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i); | ||
| 474 | else | ||
| 475 | ret += snprintf(buf+ret, PAGE_SIZE-ret, "%u ", i); | ||
| 476 | if (ret > 0) | ||
| 477 | buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n'; | ||
| 478 | return ret; | ||
| 479 | } | ||
| 480 | |||
| 481 | static ssize_t picolcd_fb_update_rate_store(struct device *dev, | ||
| 482 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 483 | { | ||
| 484 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
| 485 | struct picolcd_fb_data *fbdata = data->fb_info->par; | ||
| 486 | int i; | ||
| 487 | unsigned u; | ||
| 488 | |||
| 489 | if (count < 1 || count > 10) | ||
| 490 | return -EINVAL; | ||
| 491 | |||
| 492 | i = sscanf(buf, "%u", &u); | ||
| 493 | if (i != 1) | ||
| 494 | return -EINVAL; | ||
| 495 | |||
| 496 | if (u > PICOLCDFB_UPDATE_RATE_LIMIT) | ||
| 497 | return -ERANGE; | ||
| 498 | else if (u == 0) | ||
| 499 | u = PICOLCDFB_UPDATE_RATE_DEFAULT; | ||
| 500 | |||
| 501 | fbdata->update_rate = u; | ||
| 502 | data->fb_info->fbdefio->delay = HZ / fbdata->update_rate; | ||
| 503 | return count; | ||
| 504 | } | ||
| 505 | |||
| 506 | static DEVICE_ATTR(fb_update_rate, 0666, picolcd_fb_update_rate_show, | ||
| 507 | picolcd_fb_update_rate_store); | ||
| 508 | |||
| 509 | /* initialize Framebuffer device */ | ||
| 510 | int picolcd_init_framebuffer(struct picolcd_data *data) | ||
| 511 | { | ||
| 512 | struct device *dev = &data->hdev->dev; | ||
| 513 | struct fb_info *info = NULL; | ||
| 514 | struct picolcd_fb_data *fbdata = NULL; | ||
| 515 | int i, error = -ENOMEM; | ||
| 516 | u32 *palette; | ||
| 517 | |||
| 518 | /* The extra memory is: | ||
| 519 | * - 256*u32 for pseudo_palette | ||
| 520 | * - struct fb_deferred_io | ||
| 521 | */ | ||
| 522 | info = framebuffer_alloc(256 * sizeof(u32) + | ||
| 523 | sizeof(struct fb_deferred_io) + | ||
| 524 | sizeof(struct picolcd_fb_data) + | ||
| 525 | PICOLCDFB_SIZE, dev); | ||
| 526 | if (info == NULL) { | ||
| 527 | dev_err(dev, "failed to allocate a framebuffer\n"); | ||
| 528 | goto err_nomem; | ||
| 529 | } | ||
| 530 | |||
| 531 | info->fbdefio = info->par; | ||
| 532 | *info->fbdefio = picolcd_fb_defio; | ||
| 533 | info->par += sizeof(struct fb_deferred_io); | ||
| 534 | palette = info->par; | ||
| 535 | info->par += 256 * sizeof(u32); | ||
| 536 | for (i = 0; i < 256; i++) | ||
| 537 | palette[i] = i > 0 && i < 16 ? 0xff : 0; | ||
| 538 | info->pseudo_palette = palette; | ||
| 539 | info->fbops = &picolcdfb_ops; | ||
| 540 | info->var = picolcdfb_var; | ||
| 541 | info->fix = picolcdfb_fix; | ||
| 542 | info->fix.smem_len = PICOLCDFB_SIZE*8; | ||
| 543 | info->flags = FBINFO_FLAG_DEFAULT; | ||
| 544 | |||
| 545 | fbdata = info->par; | ||
| 546 | spin_lock_init(&fbdata->lock); | ||
| 547 | fbdata->picolcd = data; | ||
| 548 | fbdata->update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT; | ||
| 549 | fbdata->bpp = picolcdfb_var.bits_per_pixel; | ||
| 550 | fbdata->force = 1; | ||
| 551 | fbdata->vbitmap = info->par + sizeof(struct picolcd_fb_data); | ||
| 552 | fbdata->bitmap = vmalloc(PICOLCDFB_SIZE*8); | ||
| 553 | if (fbdata->bitmap == NULL) { | ||
| 554 | dev_err(dev, "can't get a free page for framebuffer\n"); | ||
| 555 | goto err_nomem; | ||
| 556 | } | ||
| 557 | info->screen_base = (char __force __iomem *)fbdata->bitmap; | ||
| 558 | info->fix.smem_start = (unsigned long)fbdata->bitmap; | ||
| 559 | memset(fbdata->vbitmap, 0xff, PICOLCDFB_SIZE); | ||
| 560 | data->fb_info = info; | ||
| 561 | |||
| 562 | error = picolcd_fb_reset(data, 1); | ||
| 563 | if (error) { | ||
| 564 | dev_err(dev, "failed to configure display\n"); | ||
| 565 | goto err_cleanup; | ||
| 566 | } | ||
| 567 | |||
| 568 | error = device_create_file(dev, &dev_attr_fb_update_rate); | ||
| 569 | if (error) { | ||
| 570 | dev_err(dev, "failed to create sysfs attributes\n"); | ||
| 571 | goto err_cleanup; | ||
| 572 | } | ||
| 573 | |||
| 574 | fb_deferred_io_init(info); | ||
| 575 | error = register_framebuffer(info); | ||
| 576 | if (error) { | ||
| 577 | dev_err(dev, "failed to register framebuffer\n"); | ||
| 578 | goto err_sysfs; | ||
| 579 | } | ||
| 580 | return 0; | ||
| 581 | |||
| 582 | err_sysfs: | ||
| 583 | device_remove_file(dev, &dev_attr_fb_update_rate); | ||
| 584 | fb_deferred_io_cleanup(info); | ||
| 585 | err_cleanup: | ||
| 586 | data->fb_info = NULL; | ||
| 587 | |||
| 588 | err_nomem: | ||
| 589 | if (fbdata) | ||
| 590 | vfree(fbdata->bitmap); | ||
| 591 | framebuffer_release(info); | ||
| 592 | return error; | ||
| 593 | } | ||
| 594 | |||
| 595 | void picolcd_exit_framebuffer(struct picolcd_data *data) | ||
| 596 | { | ||
| 597 | struct fb_info *info = data->fb_info; | ||
| 598 | struct picolcd_fb_data *fbdata = info->par; | ||
| 599 | unsigned long flags; | ||
| 600 | |||
| 601 | device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate); | ||
| 602 | |||
| 603 | /* disconnect framebuffer from HID dev */ | ||
| 604 | spin_lock_irqsave(&fbdata->lock, flags); | ||
| 605 | fbdata->picolcd = NULL; | ||
| 606 | spin_unlock_irqrestore(&fbdata->lock, flags); | ||
| 607 | |||
| 608 | /* make sure there is no running update - thus that fbdata->picolcd | ||
| 609 | * once obtained under lock is guaranteed not to get free() under | ||
| 610 | * the feet of the deferred work */ | ||
| 611 | flush_delayed_work_sync(&info->deferred_work); | ||
| 612 | |||
| 613 | data->fb_info = NULL; | ||
| 614 | unregister_framebuffer(info); | ||
| 615 | } | ||
diff --git a/drivers/hid/hid-picolcd_lcd.c b/drivers/hid/hid-picolcd_lcd.c new file mode 100644 index 000000000000..2d0ddc5ac65f --- /dev/null +++ b/drivers/hid/hid-picolcd_lcd.c | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> * | ||
| 3 | * * | ||
| 4 | * Based on Logitech G13 driver (v0.4) * | ||
| 5 | * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * | ||
| 6 | * * | ||
| 7 | * This program is free software: you can redistribute it and/or modify * | ||
| 8 | * it under the terms of the GNU General Public License as published by * | ||
| 9 | * the Free Software Foundation, version 2 of the License. * | ||
| 10 | * * | ||
| 11 | * This driver is distributed in the hope that it will be useful, but * | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * | ||
| 14 | * General Public License for more details. * | ||
| 15 | * * | ||
| 16 | * You should have received a copy of the GNU General Public License * | ||
| 17 | * along with this software. If not see <http://www.gnu.org/licenses/>. * | ||
| 18 | ***************************************************************************/ | ||
| 19 | |||
| 20 | #include <linux/hid.h> | ||
| 21 | #include "usbhid/usbhid.h" | ||
| 22 | #include <linux/usb.h> | ||
| 23 | |||
| 24 | #include <linux/fb.h> | ||
| 25 | #include <linux/lcd.h> | ||
| 26 | |||
| 27 | #include "hid-picolcd.h" | ||
| 28 | |||
| 29 | /* | ||
| 30 | * lcd class device | ||
| 31 | */ | ||
| 32 | static int picolcd_get_contrast(struct lcd_device *ldev) | ||
| 33 | { | ||
| 34 | struct picolcd_data *data = lcd_get_data(ldev); | ||
| 35 | return data->lcd_contrast; | ||
| 36 | } | ||
| 37 | |||
| 38 | static int picolcd_set_contrast(struct lcd_device *ldev, int contrast) | ||
| 39 | { | ||
| 40 | struct picolcd_data *data = lcd_get_data(ldev); | ||
| 41 | struct hid_report *report = picolcd_out_report(REPORT_CONTRAST, data->hdev); | ||
| 42 | unsigned long flags; | ||
| 43 | |||
| 44 | if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) | ||
| 45 | return -ENODEV; | ||
| 46 | |||
| 47 | data->lcd_contrast = contrast & 0x0ff; | ||
| 48 | spin_lock_irqsave(&data->lock, flags); | ||
| 49 | hid_set_field(report->field[0], 0, data->lcd_contrast); | ||
| 50 | if (!(data->status & PICOLCD_FAILED)) | ||
| 51 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
| 52 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | |||
| 56 | static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb) | ||
| 57 | { | ||
| 58 | return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev)); | ||
| 59 | } | ||
| 60 | |||
| 61 | static struct lcd_ops picolcd_lcdops = { | ||
| 62 | .get_contrast = picolcd_get_contrast, | ||
| 63 | .set_contrast = picolcd_set_contrast, | ||
| 64 | .check_fb = picolcd_check_lcd_fb, | ||
| 65 | }; | ||
| 66 | |||
| 67 | int picolcd_init_lcd(struct picolcd_data *data, struct hid_report *report) | ||
| 68 | { | ||
| 69 | struct device *dev = &data->hdev->dev; | ||
| 70 | struct lcd_device *ldev; | ||
| 71 | |||
| 72 | if (!report) | ||
| 73 | return -ENODEV; | ||
| 74 | if (report->maxfield != 1 || report->field[0]->report_count != 1 || | ||
| 75 | report->field[0]->report_size != 8) { | ||
| 76 | dev_err(dev, "unsupported CONTRAST report"); | ||
| 77 | return -EINVAL; | ||
| 78 | } | ||
| 79 | |||
| 80 | ldev = lcd_device_register(dev_name(dev), dev, data, &picolcd_lcdops); | ||
| 81 | if (IS_ERR(ldev)) { | ||
| 82 | dev_err(dev, "failed to register LCD\n"); | ||
| 83 | return PTR_ERR(ldev); | ||
| 84 | } | ||
| 85 | ldev->props.max_contrast = 0x0ff; | ||
| 86 | data->lcd_contrast = 0xe5; | ||
| 87 | data->lcd = ldev; | ||
| 88 | picolcd_set_contrast(ldev, 0xe5); | ||
| 89 | return 0; | ||
| 90 | } | ||
| 91 | |||
| 92 | void picolcd_exit_lcd(struct picolcd_data *data) | ||
| 93 | { | ||
| 94 | struct lcd_device *ldev = data->lcd; | ||
| 95 | |||
| 96 | data->lcd = NULL; | ||
| 97 | if (ldev) | ||
| 98 | lcd_device_unregister(ldev); | ||
| 99 | } | ||
| 100 | |||
| 101 | int picolcd_resume_lcd(struct picolcd_data *data) | ||
| 102 | { | ||
| 103 | if (!data->lcd) | ||
| 104 | return 0; | ||
| 105 | return picolcd_set_contrast(data->lcd, data->lcd_contrast); | ||
| 106 | } | ||
| 107 | |||
diff --git a/drivers/hid/hid-picolcd_leds.c b/drivers/hid/hid-picolcd_leds.c new file mode 100644 index 000000000000..28cb6a4f9634 --- /dev/null +++ b/drivers/hid/hid-picolcd_leds.c | |||
| @@ -0,0 +1,175 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> * | ||
| 3 | * * | ||
| 4 | * Based on Logitech G13 driver (v0.4) * | ||
| 5 | * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * | ||
| 6 | * * | ||
| 7 | * This program is free software: you can redistribute it and/or modify * | ||
| 8 | * it under the terms of the GNU General Public License as published by * | ||
| 9 | * the Free Software Foundation, version 2 of the License. * | ||
| 10 | * * | ||
| 11 | * This driver is distributed in the hope that it will be useful, but * | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * | ||
| 14 | * General Public License for more details. * | ||
| 15 | * * | ||
| 16 | * You should have received a copy of the GNU General Public License * | ||
| 17 | * along with this software. If not see <http://www.gnu.org/licenses/>. * | ||
| 18 | ***************************************************************************/ | ||
| 19 | |||
| 20 | #include <linux/hid.h> | ||
| 21 | #include <linux/hid-debug.h> | ||
| 22 | #include <linux/input.h> | ||
| 23 | #include "hid-ids.h" | ||
| 24 | #include "usbhid/usbhid.h" | ||
| 25 | #include <linux/usb.h> | ||
| 26 | |||
| 27 | #include <linux/fb.h> | ||
| 28 | #include <linux/vmalloc.h> | ||
| 29 | #include <linux/backlight.h> | ||
| 30 | #include <linux/lcd.h> | ||
| 31 | |||
| 32 | #include <linux/leds.h> | ||
| 33 | |||
| 34 | #include <linux/seq_file.h> | ||
| 35 | #include <linux/debugfs.h> | ||
| 36 | |||
| 37 | #include <linux/completion.h> | ||
| 38 | #include <linux/uaccess.h> | ||
| 39 | #include <linux/module.h> | ||
| 40 | |||
| 41 | #include "hid-picolcd.h" | ||
| 42 | |||
| 43 | |||
| 44 | void picolcd_leds_set(struct picolcd_data *data) | ||
| 45 | { | ||
| 46 | struct hid_report *report; | ||
| 47 | unsigned long flags; | ||
| 48 | |||
| 49 | if (!data->led[0]) | ||
| 50 | return; | ||
| 51 | report = picolcd_out_report(REPORT_LED_STATE, data->hdev); | ||
| 52 | if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) | ||
| 53 | return; | ||
| 54 | |||
| 55 | spin_lock_irqsave(&data->lock, flags); | ||
| 56 | hid_set_field(report->field[0], 0, data->led_state); | ||
| 57 | if (!(data->status & PICOLCD_FAILED)) | ||
| 58 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
| 59 | spin_unlock_irqrestore(&data->lock, flags); | ||
| 60 | } | ||
| 61 | |||
| 62 | static void picolcd_led_set_brightness(struct led_classdev *led_cdev, | ||
| 63 | enum led_brightness value) | ||
| 64 | { | ||
| 65 | struct device *dev; | ||
| 66 | struct hid_device *hdev; | ||
| 67 | struct picolcd_data *data; | ||
| 68 | int i, state = 0; | ||
| 69 | |||
| 70 | dev = led_cdev->dev->parent; | ||
| 71 | hdev = container_of(dev, struct hid_device, dev); | ||
| 72 | data = hid_get_drvdata(hdev); | ||
| 73 | if (!data) | ||
| 74 | return; | ||
| 75 | for (i = 0; i < 8; i++) { | ||
| 76 | if (led_cdev != data->led[i]) | ||
| 77 | continue; | ||
| 78 | state = (data->led_state >> i) & 1; | ||
| 79 | if (value == LED_OFF && state) { | ||
| 80 | data->led_state &= ~(1 << i); | ||
| 81 | picolcd_leds_set(data); | ||
| 82 | } else if (value != LED_OFF && !state) { | ||
| 83 | data->led_state |= 1 << i; | ||
| 84 | picolcd_leds_set(data); | ||
| 85 | } | ||
| 86 | break; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev) | ||
| 91 | { | ||
| 92 | struct device *dev; | ||
| 93 | struct hid_device *hdev; | ||
| 94 | struct picolcd_data *data; | ||
| 95 | int i, value = 0; | ||
| 96 | |||
| 97 | dev = led_cdev->dev->parent; | ||
| 98 | hdev = container_of(dev, struct hid_device, dev); | ||
| 99 | data = hid_get_drvdata(hdev); | ||
| 100 | for (i = 0; i < 8; i++) | ||
| 101 | if (led_cdev == data->led[i]) { | ||
| 102 | value = (data->led_state >> i) & 1; | ||
| 103 | break; | ||
| 104 | } | ||
| 105 | return value ? LED_FULL : LED_OFF; | ||
| 106 | } | ||
| 107 | |||
| 108 | int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report) | ||
| 109 | { | ||
| 110 | struct device *dev = &data->hdev->dev; | ||
| 111 | struct led_classdev *led; | ||
| 112 | size_t name_sz = strlen(dev_name(dev)) + 8; | ||
| 113 | char *name; | ||
| 114 | int i, ret = 0; | ||
| 115 | |||
| 116 | if (!report) | ||
| 117 | return -ENODEV; | ||
| 118 | if (report->maxfield != 1 || report->field[0]->report_count != 1 || | ||
| 119 | report->field[0]->report_size != 8) { | ||
| 120 | dev_err(dev, "unsupported LED_STATE report"); | ||
| 121 | return -EINVAL; | ||
| 122 | } | ||
| 123 | |||
| 124 | for (i = 0; i < 8; i++) { | ||
| 125 | led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); | ||
| 126 | if (!led) { | ||
| 127 | dev_err(dev, "can't allocate memory for LED %d\n", i); | ||
| 128 | ret = -ENOMEM; | ||
| 129 | goto err; | ||
| 130 | } | ||
| 131 | name = (void *)(&led[1]); | ||
| 132 | snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i); | ||
| 133 | led->name = name; | ||
| 134 | led->brightness = 0; | ||
| 135 | led->max_brightness = 1; | ||
| 136 | led->brightness_get = picolcd_led_get_brightness; | ||
| 137 | led->brightness_set = picolcd_led_set_brightness; | ||
| 138 | |||
| 139 | data->led[i] = led; | ||
| 140 | ret = led_classdev_register(dev, data->led[i]); | ||
| 141 | if (ret) { | ||
| 142 | data->led[i] = NULL; | ||
| 143 | kfree(led); | ||
| 144 | dev_err(dev, "can't register LED %d\n", i); | ||
| 145 | goto err; | ||
| 146 | } | ||
| 147 | } | ||
| 148 | return 0; | ||
| 149 | err: | ||
| 150 | for (i = 0; i < 8; i++) | ||
| 151 | if (data->led[i]) { | ||
| 152 | led = data->led[i]; | ||
| 153 | data->led[i] = NULL; | ||
| 154 | led_classdev_unregister(led); | ||
| 155 | kfree(led); | ||
| 156 | } | ||
| 157 | return ret; | ||
| 158 | } | ||
| 159 | |||
| 160 | void picolcd_exit_leds(struct picolcd_data *data) | ||
| 161 | { | ||
| 162 | struct led_classdev *led; | ||
| 163 | int i; | ||
| 164 | |||
| 165 | for (i = 0; i < 8; i++) { | ||
| 166 | led = data->led[i]; | ||
| 167 | data->led[i] = NULL; | ||
| 168 | if (!led) | ||
| 169 | continue; | ||
| 170 | led_classdev_unregister(led); | ||
| 171 | kfree(led); | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | |||
diff --git a/drivers/hid/hid-primax.c b/drivers/hid/hid-primax.c index 4d3c60d88318..c15adb0c98a1 100644 --- a/drivers/hid/hid-primax.c +++ b/drivers/hid/hid-primax.c | |||
| @@ -64,29 +64,6 @@ static int px_raw_event(struct hid_device *hid, struct hid_report *report, | |||
| 64 | return 0; | 64 | return 0; |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | static int px_probe(struct hid_device *hid, const struct hid_device_id *id) | ||
| 68 | { | ||
| 69 | int ret; | ||
| 70 | |||
| 71 | ret = hid_parse(hid); | ||
| 72 | if (ret) { | ||
| 73 | hid_err(hid, "parse failed\n"); | ||
| 74 | goto fail; | ||
| 75 | } | ||
| 76 | |||
| 77 | ret = hid_hw_start(hid, HID_CONNECT_DEFAULT); | ||
| 78 | if (ret) | ||
| 79 | hid_err(hid, "hw start failed\n"); | ||
| 80 | |||
| 81 | fail: | ||
| 82 | return ret; | ||
| 83 | } | ||
| 84 | |||
| 85 | static void px_remove(struct hid_device *hid) | ||
| 86 | { | ||
| 87 | hid_hw_stop(hid); | ||
| 88 | } | ||
| 89 | |||
| 90 | static const struct hid_device_id px_devices[] = { | 67 | static const struct hid_device_id px_devices[] = { |
| 91 | { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) }, | 68 | { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) }, |
| 92 | { } | 69 | { } |
| @@ -97,8 +74,6 @@ static struct hid_driver px_driver = { | |||
| 97 | .name = "primax", | 74 | .name = "primax", |
| 98 | .id_table = px_devices, | 75 | .id_table = px_devices, |
| 99 | .raw_event = px_raw_event, | 76 | .raw_event = px_raw_event, |
| 100 | .probe = px_probe, | ||
| 101 | .remove = px_remove, | ||
| 102 | }; | 77 | }; |
| 103 | 78 | ||
| 104 | static int __init px_init(void) | 79 | static int __init px_init(void) |
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c index b71b77ab0dc7..ec8ca3336315 100644 --- a/drivers/hid/hid-prodikeys.c +++ b/drivers/hid/hid-prodikeys.c | |||
| @@ -105,7 +105,7 @@ static ssize_t show_channel(struct device *dev, | |||
| 105 | struct device_attribute *attr, char *buf) | 105 | struct device_attribute *attr, char *buf) |
| 106 | { | 106 | { |
| 107 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | 107 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 108 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | 108 | struct pk_device *pk = hid_get_drvdata(hdev); |
| 109 | 109 | ||
| 110 | dbg_hid("pcmidi sysfs read channel=%u\n", pk->pm->midi_channel); | 110 | dbg_hid("pcmidi sysfs read channel=%u\n", pk->pm->midi_channel); |
| 111 | 111 | ||
| @@ -118,7 +118,7 @@ static ssize_t store_channel(struct device *dev, | |||
| 118 | struct device_attribute *attr, const char *buf, size_t count) | 118 | struct device_attribute *attr, const char *buf, size_t count) |
| 119 | { | 119 | { |
| 120 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | 120 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 121 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | 121 | struct pk_device *pk = hid_get_drvdata(hdev); |
| 122 | 122 | ||
| 123 | unsigned channel = 0; | 123 | unsigned channel = 0; |
| 124 | 124 | ||
| @@ -142,7 +142,7 @@ static ssize_t show_sustain(struct device *dev, | |||
| 142 | struct device_attribute *attr, char *buf) | 142 | struct device_attribute *attr, char *buf) |
| 143 | { | 143 | { |
| 144 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | 144 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 145 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | 145 | struct pk_device *pk = hid_get_drvdata(hdev); |
| 146 | 146 | ||
| 147 | dbg_hid("pcmidi sysfs read sustain=%u\n", pk->pm->midi_sustain); | 147 | dbg_hid("pcmidi sysfs read sustain=%u\n", pk->pm->midi_sustain); |
| 148 | 148 | ||
| @@ -155,7 +155,7 @@ static ssize_t store_sustain(struct device *dev, | |||
| 155 | struct device_attribute *attr, const char *buf, size_t count) | 155 | struct device_attribute *attr, const char *buf, size_t count) |
| 156 | { | 156 | { |
| 157 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | 157 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 158 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | 158 | struct pk_device *pk = hid_get_drvdata(hdev); |
| 159 | 159 | ||
| 160 | unsigned sustain = 0; | 160 | unsigned sustain = 0; |
| 161 | 161 | ||
| @@ -181,7 +181,7 @@ static ssize_t show_octave(struct device *dev, | |||
| 181 | struct device_attribute *attr, char *buf) | 181 | struct device_attribute *attr, char *buf) |
| 182 | { | 182 | { |
| 183 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | 183 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 184 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | 184 | struct pk_device *pk = hid_get_drvdata(hdev); |
| 185 | 185 | ||
| 186 | dbg_hid("pcmidi sysfs read octave=%d\n", pk->pm->midi_octave); | 186 | dbg_hid("pcmidi sysfs read octave=%d\n", pk->pm->midi_octave); |
| 187 | 187 | ||
| @@ -194,7 +194,7 @@ static ssize_t store_octave(struct device *dev, | |||
| 194 | struct device_attribute *attr, const char *buf, size_t count) | 194 | struct device_attribute *attr, const char *buf, size_t count) |
| 195 | { | 195 | { |
| 196 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | 196 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
| 197 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | 197 | struct pk_device *pk = hid_get_drvdata(hdev); |
| 198 | 198 | ||
| 199 | int octave = 0; | 199 | int octave = 0; |
| 200 | 200 | ||
| @@ -759,7 +759,7 @@ static int pk_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 759 | struct hid_field *field, struct hid_usage *usage, | 759 | struct hid_field *field, struct hid_usage *usage, |
| 760 | unsigned long **bit, int *max) | 760 | unsigned long **bit, int *max) |
| 761 | { | 761 | { |
| 762 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | 762 | struct pk_device *pk = hid_get_drvdata(hdev); |
| 763 | struct pcmidi_snd *pm; | 763 | struct pcmidi_snd *pm; |
| 764 | 764 | ||
| 765 | pm = pk->pm; | 765 | pm = pk->pm; |
| @@ -777,7 +777,7 @@ static int pk_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 777 | static int pk_raw_event(struct hid_device *hdev, struct hid_report *report, | 777 | static int pk_raw_event(struct hid_device *hdev, struct hid_report *report, |
| 778 | u8 *data, int size) | 778 | u8 *data, int size) |
| 779 | { | 779 | { |
| 780 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | 780 | struct pk_device *pk = hid_get_drvdata(hdev); |
| 781 | int ret = 0; | 781 | int ret = 0; |
| 782 | 782 | ||
| 783 | if (1 == pk->pm->ifnum) { | 783 | if (1 == pk->pm->ifnum) { |
| @@ -858,7 +858,7 @@ err_free_pk: | |||
| 858 | 858 | ||
| 859 | static void pk_remove(struct hid_device *hdev) | 859 | static void pk_remove(struct hid_device *hdev) |
| 860 | { | 860 | { |
| 861 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | 861 | struct pk_device *pk = hid_get_drvdata(hdev); |
| 862 | struct pcmidi_snd *pm; | 862 | struct pcmidi_snd *pm; |
| 863 | 863 | ||
| 864 | pm = pk->pm; | 864 | pm = pk->pm; |
diff --git a/drivers/hid/hid-ps3remote.c b/drivers/hid/hid-ps3remote.c new file mode 100644 index 000000000000..03811e539d71 --- /dev/null +++ b/drivers/hid/hid-ps3remote.c | |||
| @@ -0,0 +1,215 @@ | |||
| 1 | /* | ||
| 2 | * HID driver for Sony PS3 BD Remote Control | ||
| 3 | * | ||
| 4 | * Copyright (c) 2012 David Dillow <dave@thedillows.org> | ||
| 5 | * Based on a blend of the bluez fakehid user-space code by Marcel Holtmann | ||
| 6 | * and other kernel HID drivers. | ||
| 7 | */ | ||
| 8 | |||
| 9 | /* | ||
| 10 | * This program is free software; you can redistribute it and/or modify it | ||
| 11 | * under the terms of the GNU General Public License as published by the Free | ||
| 12 | * Software Foundation; either version 2 of the License, or (at your option) | ||
| 13 | * any later version. | ||
| 14 | */ | ||
| 15 | |||
| 16 | /* NOTE: in order for the Sony PS3 BD Remote Control to be found by | ||
| 17 | * a Bluetooth host, the key combination Start+Enter has to be kept pressed | ||
| 18 | * for about 7 seconds with the Bluetooth Host Controller in discovering mode. | ||
| 19 | * | ||
| 20 | * There will be no PIN request from the device. | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/device.h> | ||
| 24 | #include <linux/hid.h> | ||
| 25 | #include <linux/module.h> | ||
| 26 | |||
| 27 | #include "hid-ids.h" | ||
| 28 | |||
| 29 | static __u8 ps3remote_rdesc[] = { | ||
| 30 | 0x05, 0x01, /* GUsagePage Generic Desktop */ | ||
| 31 | 0x09, 0x05, /* LUsage 0x05 [Game Pad] */ | ||
| 32 | 0xA1, 0x01, /* MCollection Application (mouse, keyboard) */ | ||
| 33 | |||
| 34 | /* Use collection 1 for joypad buttons */ | ||
| 35 | 0xA1, 0x02, /* MCollection Logical (interrelated data) */ | ||
| 36 | |||
| 37 | /* Ignore the 1st byte, maybe it is used for a controller | ||
| 38 | * number but it's not needed for correct operation */ | ||
| 39 | 0x75, 0x08, /* GReportSize 0x08 [8] */ | ||
| 40 | 0x95, 0x01, /* GReportCount 0x01 [1] */ | ||
| 41 | 0x81, 0x01, /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */ | ||
| 42 | |||
| 43 | /* Bytes from 2nd to 4th are a bitmap for joypad buttons, for these | ||
| 44 | * buttons multiple keypresses are allowed */ | ||
| 45 | 0x05, 0x09, /* GUsagePage Button */ | ||
| 46 | 0x19, 0x01, /* LUsageMinimum 0x01 [Button 1 (primary/trigger)] */ | ||
| 47 | 0x29, 0x18, /* LUsageMaximum 0x18 [Button 24] */ | ||
| 48 | 0x14, /* GLogicalMinimum [0] */ | ||
| 49 | 0x25, 0x01, /* GLogicalMaximum 0x01 [1] */ | ||
| 50 | 0x75, 0x01, /* GReportSize 0x01 [1] */ | ||
| 51 | 0x95, 0x18, /* GReportCount 0x18 [24] */ | ||
| 52 | 0x81, 0x02, /* MInput 0x02 (Data[0] Var[1] Abs[2]) */ | ||
| 53 | |||
| 54 | 0xC0, /* MEndCollection */ | ||
| 55 | |||
| 56 | /* Use collection 2 for remote control buttons */ | ||
| 57 | 0xA1, 0x02, /* MCollection Logical (interrelated data) */ | ||
| 58 | |||
| 59 | /* 5th byte is used for remote control buttons */ | ||
| 60 | 0x05, 0x09, /* GUsagePage Button */ | ||
| 61 | 0x18, /* LUsageMinimum [No button pressed] */ | ||
| 62 | 0x29, 0xFE, /* LUsageMaximum 0xFE [Button 254] */ | ||
| 63 | 0x14, /* GLogicalMinimum [0] */ | ||
| 64 | 0x26, 0xFE, 0x00, /* GLogicalMaximum 0x00FE [254] */ | ||
| 65 | 0x75, 0x08, /* GReportSize 0x08 [8] */ | ||
| 66 | 0x95, 0x01, /* GReportCount 0x01 [1] */ | ||
| 67 | 0x80, /* MInput */ | ||
| 68 | |||
| 69 | /* Ignore bytes from 6th to 11th, 6th to 10th are always constant at | ||
| 70 | * 0xff and 11th is for press indication */ | ||
| 71 | 0x75, 0x08, /* GReportSize 0x08 [8] */ | ||
| 72 | 0x95, 0x06, /* GReportCount 0x06 [6] */ | ||
| 73 | 0x81, 0x01, /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */ | ||
| 74 | |||
| 75 | /* 12th byte is for battery strength */ | ||
| 76 | 0x05, 0x06, /* GUsagePage Generic Device Controls */ | ||
| 77 | 0x09, 0x20, /* LUsage 0x20 [Battery Strength] */ | ||
| 78 | 0x14, /* GLogicalMinimum [0] */ | ||
| 79 | 0x25, 0x05, /* GLogicalMaximum 0x05 [5] */ | ||
| 80 | 0x75, 0x08, /* GReportSize 0x08 [8] */ | ||
| 81 | 0x95, 0x01, /* GReportCount 0x01 [1] */ | ||
| 82 | 0x81, 0x02, /* MInput 0x02 (Data[0] Var[1] Abs[2]) */ | ||
| 83 | |||
| 84 | 0xC0, /* MEndCollection */ | ||
| 85 | |||
| 86 | 0xC0 /* MEndCollection [Game Pad] */ | ||
| 87 | }; | ||
| 88 | |||
| 89 | static const unsigned int ps3remote_keymap_joypad_buttons[] = { | ||
| 90 | [0x01] = KEY_SELECT, | ||
| 91 | [0x02] = BTN_THUMBL, /* L3 */ | ||
| 92 | [0x03] = BTN_THUMBR, /* R3 */ | ||
| 93 | [0x04] = BTN_START, | ||
| 94 | [0x05] = KEY_UP, | ||
| 95 | [0x06] = KEY_RIGHT, | ||
| 96 | [0x07] = KEY_DOWN, | ||
| 97 | [0x08] = KEY_LEFT, | ||
| 98 | [0x09] = BTN_TL2, /* L2 */ | ||
| 99 | [0x0a] = BTN_TR2, /* R2 */ | ||
| 100 | [0x0b] = BTN_TL, /* L1 */ | ||
| 101 | [0x0c] = BTN_TR, /* R1 */ | ||
| 102 | [0x0d] = KEY_OPTION, /* options/triangle */ | ||
| 103 | [0x0e] = KEY_BACK, /* back/circle */ | ||
| 104 | [0x0f] = BTN_0, /* cross */ | ||
| 105 | [0x10] = KEY_SCREEN, /* view/square */ | ||
| 106 | [0x11] = KEY_HOMEPAGE, /* PS button */ | ||
| 107 | [0x14] = KEY_ENTER, | ||
| 108 | }; | ||
| 109 | static const unsigned int ps3remote_keymap_remote_buttons[] = { | ||
| 110 | [0x00] = KEY_1, | ||
| 111 | [0x01] = KEY_2, | ||
| 112 | [0x02] = KEY_3, | ||
| 113 | [0x03] = KEY_4, | ||
| 114 | [0x04] = KEY_5, | ||
| 115 | [0x05] = KEY_6, | ||
| 116 | [0x06] = KEY_7, | ||
| 117 | [0x07] = KEY_8, | ||
| 118 | [0x08] = KEY_9, | ||
| 119 | [0x09] = KEY_0, | ||
| 120 | [0x0e] = KEY_ESC, /* return */ | ||
| 121 | [0x0f] = KEY_CLEAR, | ||
| 122 | [0x16] = KEY_EJECTCD, | ||
| 123 | [0x1a] = KEY_MENU, /* top menu */ | ||
| 124 | [0x28] = KEY_TIME, | ||
| 125 | [0x30] = KEY_PREVIOUS, | ||
| 126 | [0x31] = KEY_NEXT, | ||
| 127 | [0x32] = KEY_PLAY, | ||
| 128 | [0x33] = KEY_REWIND, /* scan back */ | ||
| 129 | [0x34] = KEY_FORWARD, /* scan forward */ | ||
| 130 | [0x38] = KEY_STOP, | ||
| 131 | [0x39] = KEY_PAUSE, | ||
| 132 | [0x40] = KEY_CONTEXT_MENU, /* pop up/menu */ | ||
| 133 | [0x60] = KEY_FRAMEBACK, /* slow/step back */ | ||
| 134 | [0x61] = KEY_FRAMEFORWARD, /* slow/step forward */ | ||
| 135 | [0x63] = KEY_SUBTITLE, | ||
| 136 | [0x64] = KEY_AUDIO, | ||
| 137 | [0x65] = KEY_ANGLE, | ||
| 138 | [0x70] = KEY_INFO, /* display */ | ||
| 139 | [0x80] = KEY_BLUE, | ||
| 140 | [0x81] = KEY_RED, | ||
| 141 | [0x82] = KEY_GREEN, | ||
| 142 | [0x83] = KEY_YELLOW, | ||
| 143 | }; | ||
| 144 | |||
| 145 | static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc, | ||
| 146 | unsigned int *rsize) | ||
| 147 | { | ||
| 148 | *rsize = sizeof(ps3remote_rdesc); | ||
| 149 | return ps3remote_rdesc; | ||
| 150 | } | ||
| 151 | |||
| 152 | static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi, | ||
| 153 | struct hid_field *field, struct hid_usage *usage, | ||
| 154 | unsigned long **bit, int *max) | ||
| 155 | { | ||
| 156 | unsigned int key = usage->hid & HID_USAGE; | ||
| 157 | |||
| 158 | if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON) | ||
| 159 | return -1; | ||
| 160 | |||
| 161 | switch (usage->collection_index) { | ||
| 162 | case 1: | ||
| 163 | if (key >= ARRAY_SIZE(ps3remote_keymap_joypad_buttons)) | ||
| 164 | return -1; | ||
| 165 | |||
| 166 | key = ps3remote_keymap_joypad_buttons[key]; | ||
| 167 | if (!key) | ||
| 168 | return -1; | ||
| 169 | break; | ||
| 170 | case 2: | ||
| 171 | if (key >= ARRAY_SIZE(ps3remote_keymap_remote_buttons)) | ||
| 172 | return -1; | ||
| 173 | |||
| 174 | key = ps3remote_keymap_remote_buttons[key]; | ||
| 175 | if (!key) | ||
| 176 | return -1; | ||
| 177 | break; | ||
| 178 | default: | ||
| 179 | return -1; | ||
| 180 | } | ||
| 181 | |||
| 182 | hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key); | ||
| 183 | return 1; | ||
| 184 | } | ||
| 185 | |||
| 186 | static const struct hid_device_id ps3remote_devices[] = { | ||
| 187 | /* PS3 BD Remote Control */ | ||
| 188 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) }, | ||
| 189 | /* Logitech Harmony Adapter for PS3 */ | ||
| 190 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) }, | ||
| 191 | { } | ||
| 192 | }; | ||
| 193 | MODULE_DEVICE_TABLE(hid, ps3remote_devices); | ||
| 194 | |||
| 195 | static struct hid_driver ps3remote_driver = { | ||
| 196 | .name = "ps3_remote", | ||
| 197 | .id_table = ps3remote_devices, | ||
| 198 | .report_fixup = ps3remote_fixup, | ||
| 199 | .input_mapping = ps3remote_mapping, | ||
| 200 | }; | ||
| 201 | |||
| 202 | static int __init ps3remote_init(void) | ||
| 203 | { | ||
| 204 | return hid_register_driver(&ps3remote_driver); | ||
| 205 | } | ||
| 206 | |||
| 207 | static void __exit ps3remote_exit(void) | ||
| 208 | { | ||
| 209 | hid_unregister_driver(&ps3remote_driver); | ||
| 210 | } | ||
| 211 | |||
| 212 | module_init(ps3remote_init); | ||
| 213 | module_exit(ps3remote_exit); | ||
| 214 | MODULE_LICENSE("GPL"); | ||
| 215 | MODULE_AUTHOR("David Dillow <dave@thedillows.org>, Antonio Ospite <ospite@studenti.unina.it>"); | ||
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c index 3c1fd8af5e0c..a5821d317229 100644 --- a/drivers/hid/hid-samsung.c +++ b/drivers/hid/hid-samsung.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | * Copyright (c) 2008 Jiri Slaby | 8 | * Copyright (c) 2008 Jiri Slaby |
| 10 | * Copyright (c) 2010 Don Prince <dhprince.devel@yahoo.co.uk> | 9 | * Copyright (c) 2010 Don Prince <dhprince.devel@yahoo.co.uk> |
| 11 | * | 10 | * |
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 5cd25bd907f8..7f33ebf299c2 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | * Copyright (c) 1999 Andreas Gal | 4 | * Copyright (c) 1999 Andreas Gal |
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2007 Paul Walmsley | ||
| 8 | * Copyright (c) 2008 Jiri Slaby | 7 | * Copyright (c) 2008 Jiri Slaby |
| 9 | * Copyright (c) 2006-2008 Jiri Kosina | 8 | * Copyright (c) 2006-2008 Jiri Kosina |
| 10 | */ | 9 | */ |
diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c index d484a0043dd4..45b4b066a262 100644 --- a/drivers/hid/hid-sunplus.c +++ b/drivers/hid/hid-sunplus.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | * Copyright (c) 2008 Jiri Slaby | 8 | * Copyright (c) 2008 Jiri Slaby |
| 10 | */ | 9 | */ |
| 11 | 10 | ||
diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c index 3aba02be1f26..2e56a1fd2375 100644 --- a/drivers/hid/hid-uclogic.c +++ b/drivers/hid/hid-uclogic.c | |||
| @@ -466,6 +466,86 @@ static __u8 twhl850_rdesc_fixed2[] = { | |||
| 466 | 0xC0 /* End Collection */ | 466 | 0xC0 /* End Collection */ |
| 467 | }; | 467 | }; |
| 468 | 468 | ||
| 469 | /* | ||
| 470 | * See TWHA60 description, device and HID report descriptors at | ||
| 471 | * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_TWHA60 | ||
| 472 | */ | ||
| 473 | |||
| 474 | /* Size of the original descriptors of TWHA60 tablet */ | ||
| 475 | #define TWHA60_RDESC_ORIG_SIZE0 254 | ||
| 476 | #define TWHA60_RDESC_ORIG_SIZE1 139 | ||
| 477 | |||
| 478 | /* Fixed TWHA60 report descriptor, interface 0 (stylus) */ | ||
| 479 | static __u8 twha60_rdesc_fixed0[] = { | ||
| 480 | 0x05, 0x0D, /* Usage Page (Digitizer), */ | ||
| 481 | 0x09, 0x02, /* Usage (Pen), */ | ||
| 482 | 0xA1, 0x01, /* Collection (Application), */ | ||
| 483 | 0x85, 0x09, /* Report ID (9), */ | ||
| 484 | 0x09, 0x20, /* Usage (Stylus), */ | ||
| 485 | 0xA0, /* Collection (Physical), */ | ||
| 486 | 0x75, 0x01, /* Report Size (1), */ | ||
| 487 | 0x09, 0x42, /* Usage (Tip Switch), */ | ||
| 488 | 0x09, 0x44, /* Usage (Barrel Switch), */ | ||
| 489 | 0x09, 0x46, /* Usage (Tablet Pick), */ | ||
| 490 | 0x14, /* Logical Minimum (0), */ | ||
| 491 | 0x25, 0x01, /* Logical Maximum (1), */ | ||
| 492 | 0x95, 0x03, /* Report Count (3), */ | ||
| 493 | 0x81, 0x02, /* Input (Variable), */ | ||
| 494 | 0x95, 0x04, /* Report Count (4), */ | ||
| 495 | 0x81, 0x01, /* Input (Constant), */ | ||
| 496 | 0x09, 0x32, /* Usage (In Range), */ | ||
| 497 | 0x95, 0x01, /* Report Count (1), */ | ||
| 498 | 0x81, 0x02, /* Input (Variable), */ | ||
| 499 | 0x75, 0x10, /* Report Size (16), */ | ||
| 500 | 0x95, 0x01, /* Report Count (1), */ | ||
| 501 | 0x14, /* Logical Minimum (0), */ | ||
| 502 | 0xA4, /* Push, */ | ||
| 503 | 0x05, 0x01, /* Usage Page (Desktop), */ | ||
| 504 | 0x55, 0xFD, /* Unit Exponent (-3), */ | ||
| 505 | 0x65, 0x13, /* Unit (Inch), */ | ||
| 506 | 0x34, /* Physical Minimum (0), */ | ||
| 507 | 0x09, 0x30, /* Usage (X), */ | ||
| 508 | 0x46, 0x10, 0x27, /* Physical Maximum (10000), */ | ||
| 509 | 0x27, 0x3F, 0x9C, | ||
| 510 | 0x00, 0x00, /* Logical Maximum (39999), */ | ||
| 511 | 0x81, 0x02, /* Input (Variable), */ | ||
| 512 | 0x09, 0x31, /* Usage (Y), */ | ||
| 513 | 0x46, 0x6A, 0x18, /* Physical Maximum (6250), */ | ||
| 514 | 0x26, 0xA7, 0x61, /* Logical Maximum (24999), */ | ||
| 515 | 0x81, 0x02, /* Input (Variable), */ | ||
| 516 | 0xB4, /* Pop, */ | ||
| 517 | 0x09, 0x30, /* Usage (Tip Pressure), */ | ||
| 518 | 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ | ||
| 519 | 0x81, 0x02, /* Input (Variable), */ | ||
| 520 | 0xC0, /* End Collection, */ | ||
| 521 | 0xC0 /* End Collection */ | ||
| 522 | }; | ||
| 523 | |||
| 524 | /* Fixed TWHA60 report descriptor, interface 1 (frame buttons) */ | ||
| 525 | static __u8 twha60_rdesc_fixed1[] = { | ||
| 526 | 0x05, 0x01, /* Usage Page (Desktop), */ | ||
| 527 | 0x09, 0x06, /* Usage (Keyboard), */ | ||
| 528 | 0xA1, 0x01, /* Collection (Application), */ | ||
| 529 | 0x85, 0x05, /* Report ID (5), */ | ||
| 530 | 0x05, 0x07, /* Usage Page (Keyboard), */ | ||
| 531 | 0x14, /* Logical Minimum (0), */ | ||
| 532 | 0x25, 0x01, /* Logical Maximum (1), */ | ||
| 533 | 0x75, 0x01, /* Report Size (1), */ | ||
| 534 | 0x95, 0x08, /* Report Count (8), */ | ||
| 535 | 0x81, 0x01, /* Input (Constant), */ | ||
| 536 | 0x95, 0x0C, /* Report Count (12), */ | ||
| 537 | 0x19, 0x3A, /* Usage Minimum (KB F1), */ | ||
| 538 | 0x29, 0x45, /* Usage Maximum (KB F12), */ | ||
| 539 | 0x81, 0x02, /* Input (Variable), */ | ||
| 540 | 0x95, 0x0C, /* Report Count (12), */ | ||
| 541 | 0x19, 0x68, /* Usage Minimum (KB F13), */ | ||
| 542 | 0x29, 0x73, /* Usage Maximum (KB F24), */ | ||
| 543 | 0x81, 0x02, /* Input (Variable), */ | ||
| 544 | 0x95, 0x08, /* Report Count (8), */ | ||
| 545 | 0x81, 0x01, /* Input (Constant), */ | ||
| 546 | 0xC0 /* End Collection */ | ||
| 547 | }; | ||
| 548 | |||
| 469 | static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc, | 549 | static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc, |
| 470 | unsigned int *rsize) | 550 | unsigned int *rsize) |
| 471 | { | 551 | { |
| @@ -525,6 +605,22 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc, | |||
| 525 | break; | 605 | break; |
| 526 | } | 606 | } |
| 527 | break; | 607 | break; |
| 608 | case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60: | ||
| 609 | switch (iface_num) { | ||
| 610 | case 0: | ||
| 611 | if (*rsize == TWHA60_RDESC_ORIG_SIZE0) { | ||
| 612 | rdesc = twha60_rdesc_fixed0; | ||
| 613 | *rsize = sizeof(twha60_rdesc_fixed0); | ||
| 614 | } | ||
| 615 | break; | ||
| 616 | case 1: | ||
| 617 | if (*rsize == TWHA60_RDESC_ORIG_SIZE1) { | ||
| 618 | rdesc = twha60_rdesc_fixed1; | ||
| 619 | *rsize = sizeof(twha60_rdesc_fixed1); | ||
| 620 | } | ||
| 621 | break; | ||
| 622 | } | ||
| 623 | break; | ||
| 528 | } | 624 | } |
| 529 | 625 | ||
| 530 | return rdesc; | 626 | return rdesc; |
| @@ -543,6 +639,8 @@ static const struct hid_device_id uclogic_devices[] = { | |||
| 543 | USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, | 639 | USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, |
| 544 | { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, | 640 | { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, |
| 545 | USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) }, | 641 | USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) }, |
| 642 | { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, | ||
| 643 | USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) }, | ||
| 546 | { } | 644 | { } |
| 547 | }; | 645 | }; |
| 548 | MODULE_DEVICE_TABLE(hid, uclogic_devices); | 646 | MODULE_DEVICE_TABLE(hid, uclogic_devices); |
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index fe23a1eb586b..2f60da9ed066 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com> | 8 | * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com> |
| 10 | * Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru> | 9 | * Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru> |
| 11 | * Copyright (c) 2009 Bastien Nocera <hadess@hadess.net> | 10 | * Copyright (c) 2009 Bastien Nocera <hadess@hadess.net> |
| @@ -33,6 +32,8 @@ | |||
| 33 | #define PAD_DEVICE_ID 0x0F | 32 | #define PAD_DEVICE_ID 0x0F |
| 34 | 33 | ||
| 35 | #define WAC_CMD_LED_CONTROL 0x20 | 34 | #define WAC_CMD_LED_CONTROL 0x20 |
| 35 | #define WAC_CMD_ICON_START_STOP 0x21 | ||
| 36 | #define WAC_CMD_ICON_TRANSFER 0x26 | ||
| 36 | 37 | ||
| 37 | struct wacom_data { | 38 | struct wacom_data { |
| 38 | __u16 tool; | 39 | __u16 tool; |
| @@ -69,6 +70,91 @@ static enum power_supply_property wacom_ac_props[] = { | |||
| 69 | POWER_SUPPLY_PROP_SCOPE, | 70 | POWER_SUPPLY_PROP_SCOPE, |
| 70 | }; | 71 | }; |
| 71 | 72 | ||
| 73 | static void wacom_scramble(__u8 *image) | ||
| 74 | { | ||
| 75 | __u16 mask; | ||
| 76 | __u16 s1; | ||
| 77 | __u16 s2; | ||
| 78 | __u16 r1 ; | ||
| 79 | __u16 r2 ; | ||
| 80 | __u16 r; | ||
| 81 | __u8 buf[256]; | ||
| 82 | int i, w, x, y, z; | ||
| 83 | |||
| 84 | for (x = 0; x < 32; x++) { | ||
| 85 | for (y = 0; y < 8; y++) | ||
| 86 | buf[(8 * x) + (7 - y)] = image[(8 * x) + y]; | ||
| 87 | } | ||
| 88 | |||
| 89 | /* Change 76543210 into GECA6420 as required by Intuos4 WL | ||
| 90 | * HGFEDCBA HFDB7531 | ||
| 91 | */ | ||
| 92 | for (x = 0; x < 4; x++) { | ||
| 93 | for (y = 0; y < 4; y++) { | ||
| 94 | for (z = 0; z < 8; z++) { | ||
| 95 | mask = 0x0001; | ||
| 96 | r1 = 0; | ||
| 97 | r2 = 0; | ||
| 98 | i = (x << 6) + (y << 4) + z; | ||
| 99 | s1 = buf[i]; | ||
| 100 | s2 = buf[i+8]; | ||
| 101 | for (w = 0; w < 8; w++) { | ||
| 102 | r1 |= (s1 & mask); | ||
| 103 | r2 |= (s2 & mask); | ||
| 104 | s1 <<= 1; | ||
| 105 | s2 <<= 1; | ||
| 106 | mask <<= 2; | ||
| 107 | } | ||
| 108 | r = r1 | (r2 << 1); | ||
| 109 | i = (x << 6) + (y << 4) + (z << 1); | ||
| 110 | image[i] = 0xFF & r; | ||
| 111 | image[i+1] = (0xFF00 & r) >> 8; | ||
| 112 | } | ||
| 113 | } | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | static void wacom_set_image(struct hid_device *hdev, const char *image, | ||
| 118 | __u8 icon_no) | ||
| 119 | { | ||
| 120 | __u8 rep_data[68]; | ||
| 121 | __u8 p[256]; | ||
| 122 | int ret, i, j; | ||
| 123 | |||
| 124 | for (i = 0; i < 256; i++) | ||
| 125 | p[i] = image[i]; | ||
| 126 | |||
| 127 | rep_data[0] = WAC_CMD_ICON_START_STOP; | ||
| 128 | rep_data[1] = 0; | ||
| 129 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | ||
| 130 | HID_FEATURE_REPORT); | ||
| 131 | if (ret < 0) | ||
| 132 | goto err; | ||
| 133 | |||
| 134 | rep_data[0] = WAC_CMD_ICON_TRANSFER; | ||
| 135 | rep_data[1] = icon_no & 0x07; | ||
| 136 | |||
| 137 | wacom_scramble(p); | ||
| 138 | |||
| 139 | for (i = 0; i < 4; i++) { | ||
| 140 | for (j = 0; j < 64; j++) | ||
| 141 | rep_data[j + 3] = p[(i << 6) + j]; | ||
| 142 | |||
| 143 | rep_data[2] = i; | ||
| 144 | ret = hdev->hid_output_raw_report(hdev, rep_data, 67, | ||
| 145 | HID_FEATURE_REPORT); | ||
| 146 | } | ||
| 147 | |||
| 148 | rep_data[0] = WAC_CMD_ICON_START_STOP; | ||
| 149 | rep_data[1] = 0; | ||
| 150 | |||
| 151 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | ||
| 152 | HID_FEATURE_REPORT); | ||
| 153 | |||
| 154 | err: | ||
| 155 | return; | ||
| 156 | } | ||
| 157 | |||
| 72 | static void wacom_leds_set_brightness(struct led_classdev *led_dev, | 158 | static void wacom_leds_set_brightness(struct led_classdev *led_dev, |
| 73 | enum led_brightness value) | 159 | enum led_brightness value) |
| 74 | { | 160 | { |
| @@ -91,7 +177,10 @@ static void wacom_leds_set_brightness(struct led_classdev *led_dev, | |||
| 91 | if (buf) { | 177 | if (buf) { |
| 92 | buf[0] = WAC_CMD_LED_CONTROL; | 178 | buf[0] = WAC_CMD_LED_CONTROL; |
| 93 | buf[1] = led; | 179 | buf[1] = led; |
| 94 | buf[2] = value; | 180 | buf[2] = value >> 2; |
| 181 | buf[3] = value; | ||
| 182 | /* use fixed brightness for OLEDs */ | ||
| 183 | buf[4] = 0x08; | ||
| 95 | hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT); | 184 | hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT); |
| 96 | kfree(buf); | 185 | kfree(buf); |
| 97 | } | 186 | } |
| @@ -317,6 +406,34 @@ static ssize_t wacom_store_speed(struct device *dev, | |||
| 317 | static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP, | 406 | static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP, |
| 318 | wacom_show_speed, wacom_store_speed); | 407 | wacom_show_speed, wacom_store_speed); |
| 319 | 408 | ||
| 409 | #define WACOM_STORE(OLED_ID) \ | ||
| 410 | static ssize_t wacom_oled##OLED_ID##_store(struct device *dev, \ | ||
| 411 | struct device_attribute *attr, \ | ||
| 412 | const char *buf, size_t count) \ | ||
| 413 | { \ | ||
| 414 | struct hid_device *hdev = container_of(dev, struct hid_device, \ | ||
| 415 | dev); \ | ||
| 416 | \ | ||
| 417 | if (count != 256) \ | ||
| 418 | return -EINVAL; \ | ||
| 419 | \ | ||
| 420 | wacom_set_image(hdev, buf, OLED_ID); \ | ||
| 421 | \ | ||
| 422 | return count; \ | ||
| 423 | } \ | ||
| 424 | \ | ||
| 425 | static DEVICE_ATTR(oled##OLED_ID##_img, S_IWUSR | S_IWGRP, NULL, \ | ||
| 426 | wacom_oled##OLED_ID##_store) | ||
| 427 | |||
| 428 | WACOM_STORE(0); | ||
| 429 | WACOM_STORE(1); | ||
| 430 | WACOM_STORE(2); | ||
| 431 | WACOM_STORE(3); | ||
| 432 | WACOM_STORE(4); | ||
| 433 | WACOM_STORE(5); | ||
| 434 | WACOM_STORE(6); | ||
| 435 | WACOM_STORE(7); | ||
| 436 | |||
| 320 | static int wacom_gr_parse_report(struct hid_device *hdev, | 437 | static int wacom_gr_parse_report(struct hid_device *hdev, |
| 321 | struct wacom_data *wdata, | 438 | struct wacom_data *wdata, |
| 322 | struct input_dev *input, unsigned char *data) | 439 | struct input_dev *input, unsigned char *data) |
| @@ -717,17 +834,33 @@ static int wacom_probe(struct hid_device *hdev, | |||
| 717 | hid_warn(hdev, | 834 | hid_warn(hdev, |
| 718 | "can't create sysfs speed attribute err: %d\n", ret); | 835 | "can't create sysfs speed attribute err: %d\n", ret); |
| 719 | 836 | ||
| 837 | #define OLED_INIT(OLED_ID) \ | ||
| 838 | do { \ | ||
| 839 | ret = device_create_file(&hdev->dev, \ | ||
| 840 | &dev_attr_oled##OLED_ID##_img); \ | ||
| 841 | if (ret) \ | ||
| 842 | hid_warn(hdev, \ | ||
| 843 | "can't create sysfs oled attribute, err: %d\n", ret);\ | ||
| 844 | } while (0) | ||
| 845 | |||
| 846 | OLED_INIT(0); | ||
| 847 | OLED_INIT(1); | ||
| 848 | OLED_INIT(2); | ||
| 849 | OLED_INIT(3); | ||
| 850 | OLED_INIT(4); | ||
| 851 | OLED_INIT(5); | ||
| 852 | OLED_INIT(6); | ||
| 853 | OLED_INIT(7); | ||
| 854 | |||
| 720 | wdata->features = 0; | 855 | wdata->features = 0; |
| 721 | wacom_set_features(hdev, 1); | 856 | wacom_set_features(hdev, 1); |
| 722 | 857 | ||
| 723 | if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) { | 858 | if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) { |
| 724 | sprintf(hdev->name, "%s", "Wacom Intuos4 WL"); | 859 | sprintf(hdev->name, "%s", "Wacom Intuos4 WL"); |
| 725 | ret = wacom_initialize_leds(hdev); | 860 | ret = wacom_initialize_leds(hdev); |
| 726 | if (ret) { | 861 | if (ret) |
| 727 | hid_warn(hdev, | 862 | hid_warn(hdev, |
| 728 | "can't create led attribute, err: %d\n", ret); | 863 | "can't create led attribute, err: %d\n", ret); |
| 729 | goto destroy_leds; | ||
| 730 | } | ||
| 731 | } | 864 | } |
| 732 | 865 | ||
| 733 | wdata->battery.properties = wacom_battery_props; | 866 | wdata->battery.properties = wacom_battery_props; |
| @@ -740,8 +873,8 @@ static int wacom_probe(struct hid_device *hdev, | |||
| 740 | 873 | ||
| 741 | ret = power_supply_register(&hdev->dev, &wdata->battery); | 874 | ret = power_supply_register(&hdev->dev, &wdata->battery); |
| 742 | if (ret) { | 875 | if (ret) { |
| 743 | hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n", | 876 | hid_err(hdev, "can't create sysfs battery attribute, err: %d\n", |
| 744 | ret); | 877 | ret); |
| 745 | goto err_battery; | 878 | goto err_battery; |
| 746 | } | 879 | } |
| 747 | 880 | ||
| @@ -756,8 +889,8 @@ static int wacom_probe(struct hid_device *hdev, | |||
| 756 | 889 | ||
| 757 | ret = power_supply_register(&hdev->dev, &wdata->ac); | 890 | ret = power_supply_register(&hdev->dev, &wdata->ac); |
| 758 | if (ret) { | 891 | if (ret) { |
| 759 | hid_warn(hdev, | 892 | hid_err(hdev, |
| 760 | "can't create ac battery attribute, err: %d\n", ret); | 893 | "can't create ac battery attribute, err: %d\n", ret); |
| 761 | goto err_ac; | 894 | goto err_ac; |
| 762 | } | 895 | } |
| 763 | 896 | ||
| @@ -767,10 +900,17 @@ static int wacom_probe(struct hid_device *hdev, | |||
| 767 | err_ac: | 900 | err_ac: |
| 768 | power_supply_unregister(&wdata->battery); | 901 | power_supply_unregister(&wdata->battery); |
| 769 | err_battery: | 902 | err_battery: |
| 903 | wacom_destroy_leds(hdev); | ||
| 904 | device_remove_file(&hdev->dev, &dev_attr_oled0_img); | ||
| 905 | device_remove_file(&hdev->dev, &dev_attr_oled1_img); | ||
| 906 | device_remove_file(&hdev->dev, &dev_attr_oled2_img); | ||
| 907 | device_remove_file(&hdev->dev, &dev_attr_oled3_img); | ||
| 908 | device_remove_file(&hdev->dev, &dev_attr_oled4_img); | ||
| 909 | device_remove_file(&hdev->dev, &dev_attr_oled5_img); | ||
| 910 | device_remove_file(&hdev->dev, &dev_attr_oled6_img); | ||
| 911 | device_remove_file(&hdev->dev, &dev_attr_oled7_img); | ||
| 770 | device_remove_file(&hdev->dev, &dev_attr_speed); | 912 | device_remove_file(&hdev->dev, &dev_attr_speed); |
| 771 | hid_hw_stop(hdev); | 913 | hid_hw_stop(hdev); |
| 772 | destroy_leds: | ||
| 773 | wacom_destroy_leds(hdev); | ||
| 774 | err_free: | 914 | err_free: |
| 775 | kfree(wdata); | 915 | kfree(wdata); |
| 776 | return ret; | 916 | return ret; |
| @@ -781,6 +921,14 @@ static void wacom_remove(struct hid_device *hdev) | |||
| 781 | struct wacom_data *wdata = hid_get_drvdata(hdev); | 921 | struct wacom_data *wdata = hid_get_drvdata(hdev); |
| 782 | 922 | ||
| 783 | wacom_destroy_leds(hdev); | 923 | wacom_destroy_leds(hdev); |
| 924 | device_remove_file(&hdev->dev, &dev_attr_oled0_img); | ||
| 925 | device_remove_file(&hdev->dev, &dev_attr_oled1_img); | ||
| 926 | device_remove_file(&hdev->dev, &dev_attr_oled2_img); | ||
| 927 | device_remove_file(&hdev->dev, &dev_attr_oled3_img); | ||
| 928 | device_remove_file(&hdev->dev, &dev_attr_oled4_img); | ||
| 929 | device_remove_file(&hdev->dev, &dev_attr_oled5_img); | ||
| 930 | device_remove_file(&hdev->dev, &dev_attr_oled6_img); | ||
| 931 | device_remove_file(&hdev->dev, &dev_attr_oled7_img); | ||
| 784 | device_remove_file(&hdev->dev, &dev_attr_speed); | 932 | device_remove_file(&hdev->dev, &dev_attr_speed); |
| 785 | hid_hw_stop(hdev); | 933 | hid_hw_stop(hdev); |
| 786 | 934 | ||
diff --git a/drivers/hid/hid-waltop.c b/drivers/hid/hid-waltop.c index 745e4e9a8cf2..bb536ab5941e 100644 --- a/drivers/hid/hid-waltop.c +++ b/drivers/hid/hid-waltop.c | |||
| @@ -638,28 +638,6 @@ static __u8 sirius_battery_free_tablet_rdesc_fixed[] = { | |||
| 638 | 0xC0 /* End Collection */ | 638 | 0xC0 /* End Collection */ |
| 639 | }; | 639 | }; |
| 640 | 640 | ||
| 641 | static int waltop_probe(struct hid_device *hdev, | ||
| 642 | const struct hid_device_id *id) | ||
| 643 | { | ||
| 644 | int ret; | ||
| 645 | |||
| 646 | ret = hid_parse(hdev); | ||
| 647 | if (ret) { | ||
| 648 | hid_err(hdev, "parse failed\n"); | ||
| 649 | goto err; | ||
| 650 | } | ||
| 651 | |||
| 652 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | ||
| 653 | if (ret) { | ||
| 654 | hid_err(hdev, "hw start failed\n"); | ||
| 655 | goto err; | ||
| 656 | } | ||
| 657 | |||
| 658 | return 0; | ||
| 659 | err: | ||
| 660 | return ret; | ||
| 661 | } | ||
| 662 | |||
| 663 | static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc, | 641 | static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc, |
| 664 | unsigned int *rsize) | 642 | unsigned int *rsize) |
| 665 | { | 643 | { |
| @@ -776,11 +754,6 @@ static int waltop_raw_event(struct hid_device *hdev, struct hid_report *report, | |||
| 776 | return 0; | 754 | return 0; |
| 777 | } | 755 | } |
| 778 | 756 | ||
| 779 | static void waltop_remove(struct hid_device *hdev) | ||
| 780 | { | ||
| 781 | hid_hw_stop(hdev); | ||
| 782 | } | ||
| 783 | |||
| 784 | static const struct hid_device_id waltop_devices[] = { | 757 | static const struct hid_device_id waltop_devices[] = { |
| 785 | { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, | 758 | { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, |
| 786 | USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) }, | 759 | USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) }, |
| @@ -803,10 +776,8 @@ MODULE_DEVICE_TABLE(hid, waltop_devices); | |||
| 803 | static struct hid_driver waltop_driver = { | 776 | static struct hid_driver waltop_driver = { |
| 804 | .name = "waltop", | 777 | .name = "waltop", |
| 805 | .id_table = waltop_devices, | 778 | .id_table = waltop_devices, |
| 806 | .probe = waltop_probe, | ||
| 807 | .report_fixup = waltop_report_fixup, | 779 | .report_fixup = waltop_report_fixup, |
| 808 | .raw_event = waltop_raw_event, | 780 | .raw_event = waltop_raw_event, |
| 809 | .remove = waltop_remove, | ||
| 810 | }; | 781 | }; |
| 811 | 782 | ||
| 812 | static int __init waltop_init(void) | 783 | static int __init waltop_init(void) |
diff --git a/drivers/hid/hid-wiimote-ext.c b/drivers/hid/hid-wiimote-ext.c index 0a1805c9b0e5..bc85bf29062e 100644 --- a/drivers/hid/hid-wiimote-ext.c +++ b/drivers/hid/hid-wiimote-ext.c | |||
| @@ -28,12 +28,14 @@ struct wiimote_ext { | |||
| 28 | bool mp_plugged; | 28 | bool mp_plugged; |
| 29 | bool motionp; | 29 | bool motionp; |
| 30 | __u8 ext_type; | 30 | __u8 ext_type; |
| 31 | __u16 calib[4][3]; | ||
| 31 | }; | 32 | }; |
| 32 | 33 | ||
| 33 | enum wiiext_type { | 34 | enum wiiext_type { |
| 34 | WIIEXT_NONE, /* placeholder */ | 35 | WIIEXT_NONE, /* placeholder */ |
| 35 | WIIEXT_CLASSIC, /* Nintendo classic controller */ | 36 | WIIEXT_CLASSIC, /* Nintendo classic controller */ |
| 36 | WIIEXT_NUNCHUCK, /* Nintendo nunchuck controller */ | 37 | WIIEXT_NUNCHUCK, /* Nintendo nunchuck controller */ |
| 38 | WIIEXT_BALANCE_BOARD, /* Nintendo balance board controller */ | ||
| 37 | }; | 39 | }; |
| 38 | 40 | ||
| 39 | enum wiiext_keys { | 41 | enum wiiext_keys { |
| @@ -126,6 +128,7 @@ error: | |||
| 126 | static __u8 ext_read(struct wiimote_ext *ext) | 128 | static __u8 ext_read(struct wiimote_ext *ext) |
| 127 | { | 129 | { |
| 128 | ssize_t ret; | 130 | ssize_t ret; |
| 131 | __u8 buf[24], i, j, offs = 0; | ||
| 129 | __u8 rmem[2], wmem; | 132 | __u8 rmem[2], wmem; |
| 130 | __u8 type = WIIEXT_NONE; | 133 | __u8 type = WIIEXT_NONE; |
| 131 | 134 | ||
| @@ -151,6 +154,28 @@ static __u8 ext_read(struct wiimote_ext *ext) | |||
| 151 | type = WIIEXT_NUNCHUCK; | 154 | type = WIIEXT_NUNCHUCK; |
| 152 | else if (rmem[0] == 0x01 && rmem[1] == 0x01) | 155 | else if (rmem[0] == 0x01 && rmem[1] == 0x01) |
| 153 | type = WIIEXT_CLASSIC; | 156 | type = WIIEXT_CLASSIC; |
| 157 | else if (rmem[0] == 0x04 && rmem[1] == 0x02) | ||
| 158 | type = WIIEXT_BALANCE_BOARD; | ||
| 159 | } | ||
| 160 | |||
| 161 | /* get balance board calibration data */ | ||
| 162 | if (type == WIIEXT_BALANCE_BOARD) { | ||
| 163 | ret = wiimote_cmd_read(ext->wdata, 0xa40024, buf, 12); | ||
| 164 | ret += wiimote_cmd_read(ext->wdata, 0xa40024 + 12, | ||
| 165 | buf + 12, 12); | ||
| 166 | |||
| 167 | if (ret != 24) { | ||
| 168 | type = WIIEXT_NONE; | ||
| 169 | } else { | ||
| 170 | for (i = 0; i < 3; i++) { | ||
| 171 | for (j = 0; j < 4; j++) { | ||
| 172 | ext->calib[j][i] = buf[offs]; | ||
| 173 | ext->calib[j][i] <<= 8; | ||
| 174 | ext->calib[j][i] |= buf[offs + 1]; | ||
| 175 | offs += 2; | ||
| 176 | } | ||
| 177 | } | ||
| 178 | } | ||
| 154 | } | 179 | } |
| 155 | 180 | ||
| 156 | wiimote_cmd_release(ext->wdata); | 181 | wiimote_cmd_release(ext->wdata); |
| @@ -509,6 +534,71 @@ static void handler_classic(struct wiimote_ext *ext, const __u8 *payload) | |||
| 509 | input_sync(ext->input); | 534 | input_sync(ext->input); |
| 510 | } | 535 | } |
| 511 | 536 | ||
| 537 | static void handler_balance_board(struct wiimote_ext *ext, const __u8 *payload) | ||
| 538 | { | ||
| 539 | __s32 val[4], tmp; | ||
| 540 | unsigned int i; | ||
| 541 | |||
| 542 | /* Byte | 8 7 6 5 4 3 2 1 | | ||
| 543 | * -----+--------------------------+ | ||
| 544 | * 1 | Top Right <15:8> | | ||
| 545 | * 2 | Top Right <7:0> | | ||
| 546 | * -----+--------------------------+ | ||
| 547 | * 3 | Bottom Right <15:8> | | ||
| 548 | * 4 | Bottom Right <7:0> | | ||
| 549 | * -----+--------------------------+ | ||
| 550 | * 5 | Top Left <15:8> | | ||
| 551 | * 6 | Top Left <7:0> | | ||
| 552 | * -----+--------------------------+ | ||
| 553 | * 7 | Bottom Left <15:8> | | ||
| 554 | * 8 | Bottom Left <7:0> | | ||
| 555 | * -----+--------------------------+ | ||
| 556 | * | ||
| 557 | * These values represent the weight-measurements of the Wii-balance | ||
| 558 | * board with 16bit precision. | ||
| 559 | * | ||
| 560 | * The balance-board is never reported interleaved with motionp. | ||
| 561 | */ | ||
| 562 | |||
| 563 | val[0] = payload[0]; | ||
| 564 | val[0] <<= 8; | ||
| 565 | val[0] |= payload[1]; | ||
| 566 | |||
| 567 | val[1] = payload[2]; | ||
| 568 | val[1] <<= 8; | ||
| 569 | val[1] |= payload[3]; | ||
| 570 | |||
| 571 | val[2] = payload[4]; | ||
| 572 | val[2] <<= 8; | ||
| 573 | val[2] |= payload[5]; | ||
| 574 | |||
| 575 | val[3] = payload[6]; | ||
| 576 | val[3] <<= 8; | ||
| 577 | val[3] |= payload[7]; | ||
| 578 | |||
| 579 | /* apply calibration data */ | ||
| 580 | for (i = 0; i < 4; i++) { | ||
| 581 | if (val[i] < ext->calib[i][1]) { | ||
| 582 | tmp = val[i] - ext->calib[i][0]; | ||
| 583 | tmp *= 1700; | ||
| 584 | tmp /= ext->calib[i][1] - ext->calib[i][0]; | ||
| 585 | } else { | ||
| 586 | tmp = val[i] - ext->calib[i][1]; | ||
| 587 | tmp *= 1700; | ||
| 588 | tmp /= ext->calib[i][2] - ext->calib[i][1]; | ||
| 589 | tmp += 1700; | ||
| 590 | } | ||
| 591 | val[i] = tmp; | ||
| 592 | } | ||
| 593 | |||
| 594 | input_report_abs(ext->input, ABS_HAT0X, val[0]); | ||
| 595 | input_report_abs(ext->input, ABS_HAT0Y, val[1]); | ||
| 596 | input_report_abs(ext->input, ABS_HAT1X, val[2]); | ||
| 597 | input_report_abs(ext->input, ABS_HAT1Y, val[3]); | ||
| 598 | |||
| 599 | input_sync(ext->input); | ||
| 600 | } | ||
| 601 | |||
| 512 | /* call this with state.lock spinlock held */ | 602 | /* call this with state.lock spinlock held */ |
| 513 | void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload) | 603 | void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload) |
| 514 | { | 604 | { |
| @@ -523,6 +613,8 @@ void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload) | |||
| 523 | handler_nunchuck(ext, payload); | 613 | handler_nunchuck(ext, payload); |
| 524 | } else if (ext->ext_type == WIIEXT_CLASSIC) { | 614 | } else if (ext->ext_type == WIIEXT_CLASSIC) { |
| 525 | handler_classic(ext, payload); | 615 | handler_classic(ext, payload); |
| 616 | } else if (ext->ext_type == WIIEXT_BALANCE_BOARD) { | ||
| 617 | handler_balance_board(ext, payload); | ||
| 526 | } | 618 | } |
| 527 | } | 619 | } |
| 528 | 620 | ||
| @@ -551,6 +643,11 @@ static ssize_t wiiext_show(struct device *dev, struct device_attribute *attr, | |||
| 551 | return sprintf(buf, "motionp+classic\n"); | 643 | return sprintf(buf, "motionp+classic\n"); |
| 552 | else | 644 | else |
| 553 | return sprintf(buf, "classic\n"); | 645 | return sprintf(buf, "classic\n"); |
| 646 | } else if (type == WIIEXT_BALANCE_BOARD) { | ||
| 647 | if (motionp) | ||
| 648 | return sprintf(buf, "motionp+balanceboard\n"); | ||
| 649 | else | ||
| 650 | return sprintf(buf, "balanceboard\n"); | ||
| 554 | } else { | 651 | } else { |
| 555 | if (motionp) | 652 | if (motionp) |
| 556 | return sprintf(buf, "motionp\n"); | 653 | return sprintf(buf, "motionp\n"); |
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 3b6f7bf5a77e..17d15bb610d1 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c | |||
| @@ -42,6 +42,7 @@ static struct cdev hidraw_cdev; | |||
| 42 | static struct class *hidraw_class; | 42 | static struct class *hidraw_class; |
| 43 | static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES]; | 43 | static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES]; |
| 44 | static DEFINE_MUTEX(minors_lock); | 44 | static DEFINE_MUTEX(minors_lock); |
| 45 | static void drop_ref(struct hidraw *hid, int exists_bit); | ||
| 45 | 46 | ||
| 46 | static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | 47 | static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) |
| 47 | { | 48 | { |
| @@ -113,7 +114,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, | |||
| 113 | __u8 *buf; | 114 | __u8 *buf; |
| 114 | int ret = 0; | 115 | int ret = 0; |
| 115 | 116 | ||
| 116 | if (!hidraw_table[minor]) { | 117 | if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { |
| 117 | ret = -ENODEV; | 118 | ret = -ENODEV; |
| 118 | goto out; | 119 | goto out; |
| 119 | } | 120 | } |
| @@ -261,7 +262,7 @@ static int hidraw_open(struct inode *inode, struct file *file) | |||
| 261 | } | 262 | } |
| 262 | 263 | ||
| 263 | mutex_lock(&minors_lock); | 264 | mutex_lock(&minors_lock); |
| 264 | if (!hidraw_table[minor]) { | 265 | if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { |
| 265 | err = -ENODEV; | 266 | err = -ENODEV; |
| 266 | goto out_unlock; | 267 | goto out_unlock; |
| 267 | } | 268 | } |
| @@ -298,36 +299,12 @@ out: | |||
| 298 | static int hidraw_release(struct inode * inode, struct file * file) | 299 | static int hidraw_release(struct inode * inode, struct file * file) |
| 299 | { | 300 | { |
| 300 | unsigned int minor = iminor(inode); | 301 | unsigned int minor = iminor(inode); |
| 301 | struct hidraw *dev; | ||
| 302 | struct hidraw_list *list = file->private_data; | 302 | struct hidraw_list *list = file->private_data; |
| 303 | int ret; | ||
| 304 | int i; | ||
| 305 | |||
| 306 | mutex_lock(&minors_lock); | ||
| 307 | if (!hidraw_table[minor]) { | ||
| 308 | ret = -ENODEV; | ||
| 309 | goto unlock; | ||
| 310 | } | ||
| 311 | 303 | ||
| 304 | drop_ref(hidraw_table[minor], 0); | ||
| 312 | list_del(&list->node); | 305 | list_del(&list->node); |
| 313 | dev = hidraw_table[minor]; | ||
| 314 | if (!--dev->open) { | ||
| 315 | if (list->hidraw->exist) { | ||
| 316 | hid_hw_power(dev->hid, PM_HINT_NORMAL); | ||
| 317 | hid_hw_close(dev->hid); | ||
| 318 | } else { | ||
| 319 | kfree(list->hidraw); | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i) | ||
| 324 | kfree(list->buffer[i].value); | ||
| 325 | kfree(list); | 306 | kfree(list); |
| 326 | ret = 0; | 307 | return 0; |
| 327 | unlock: | ||
| 328 | mutex_unlock(&minors_lock); | ||
| 329 | |||
| 330 | return ret; | ||
| 331 | } | 308 | } |
| 332 | 309 | ||
| 333 | static long hidraw_ioctl(struct file *file, unsigned int cmd, | 310 | static long hidraw_ioctl(struct file *file, unsigned int cmd, |
| @@ -529,21 +506,7 @@ EXPORT_SYMBOL_GPL(hidraw_connect); | |||
| 529 | void hidraw_disconnect(struct hid_device *hid) | 506 | void hidraw_disconnect(struct hid_device *hid) |
| 530 | { | 507 | { |
| 531 | struct hidraw *hidraw = hid->hidraw; | 508 | struct hidraw *hidraw = hid->hidraw; |
| 532 | 509 | drop_ref(hidraw, 1); | |
| 533 | mutex_lock(&minors_lock); | ||
| 534 | hidraw->exist = 0; | ||
| 535 | |||
| 536 | device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); | ||
| 537 | |||
| 538 | hidraw_table[hidraw->minor] = NULL; | ||
| 539 | |||
| 540 | if (hidraw->open) { | ||
| 541 | hid_hw_close(hid); | ||
| 542 | wake_up_interruptible(&hidraw->wait); | ||
| 543 | } else { | ||
| 544 | kfree(hidraw); | ||
| 545 | } | ||
| 546 | mutex_unlock(&minors_lock); | ||
| 547 | } | 510 | } |
| 548 | EXPORT_SYMBOL_GPL(hidraw_disconnect); | 511 | EXPORT_SYMBOL_GPL(hidraw_disconnect); |
| 549 | 512 | ||
| @@ -559,21 +522,28 @@ int __init hidraw_init(void) | |||
| 559 | 522 | ||
| 560 | if (result < 0) { | 523 | if (result < 0) { |
| 561 | pr_warn("can't get major number\n"); | 524 | pr_warn("can't get major number\n"); |
| 562 | result = 0; | ||
| 563 | goto out; | 525 | goto out; |
| 564 | } | 526 | } |
| 565 | 527 | ||
| 566 | hidraw_class = class_create(THIS_MODULE, "hidraw"); | 528 | hidraw_class = class_create(THIS_MODULE, "hidraw"); |
| 567 | if (IS_ERR(hidraw_class)) { | 529 | if (IS_ERR(hidraw_class)) { |
| 568 | result = PTR_ERR(hidraw_class); | 530 | result = PTR_ERR(hidraw_class); |
| 569 | unregister_chrdev(hidraw_major, "hidraw"); | 531 | goto error_cdev; |
| 570 | goto out; | ||
| 571 | } | 532 | } |
| 572 | 533 | ||
| 573 | cdev_init(&hidraw_cdev, &hidraw_ops); | 534 | cdev_init(&hidraw_cdev, &hidraw_ops); |
| 574 | cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES); | 535 | result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES); |
| 536 | if (result < 0) | ||
| 537 | goto error_class; | ||
| 538 | |||
| 575 | out: | 539 | out: |
| 576 | return result; | 540 | return result; |
| 541 | |||
| 542 | error_class: | ||
| 543 | class_destroy(hidraw_class); | ||
| 544 | error_cdev: | ||
| 545 | unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES); | ||
| 546 | goto out; | ||
| 577 | } | 547 | } |
| 578 | 548 | ||
| 579 | void hidraw_exit(void) | 549 | void hidraw_exit(void) |
| @@ -585,3 +555,23 @@ void hidraw_exit(void) | |||
| 585 | unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES); | 555 | unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES); |
| 586 | 556 | ||
| 587 | } | 557 | } |
| 558 | |||
| 559 | static void drop_ref(struct hidraw *hidraw, int exists_bit) | ||
| 560 | { | ||
| 561 | mutex_lock(&minors_lock); | ||
| 562 | if (exists_bit) { | ||
| 563 | hid_hw_close(hidraw->hid); | ||
| 564 | hidraw->exist = 0; | ||
| 565 | if (hidraw->open) | ||
| 566 | wake_up_interruptible(&hidraw->wait); | ||
| 567 | } else { | ||
| 568 | --hidraw->open; | ||
| 569 | } | ||
| 570 | |||
| 571 | if (!hidraw->open && !hidraw->exist) { | ||
| 572 | device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); | ||
| 573 | hidraw_table[hidraw->minor] = NULL; | ||
| 574 | kfree(hidraw); | ||
| 575 | } | ||
| 576 | mutex_unlock(&minors_lock); | ||
| 577 | } | ||
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index dedd8e4e5c6d..8e0c4bf94ebc 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c | |||
| @@ -1415,20 +1415,20 @@ static int hid_post_reset(struct usb_interface *intf) | |||
| 1415 | * configuration descriptors passed, we already know that | 1415 | * configuration descriptors passed, we already know that |
| 1416 | * the size of the HID report descriptor has not changed. | 1416 | * the size of the HID report descriptor has not changed. |
| 1417 | */ | 1417 | */ |
| 1418 | rdesc = kmalloc(hid->rsize, GFP_KERNEL); | 1418 | rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL); |
| 1419 | if (!rdesc) { | 1419 | if (!rdesc) { |
| 1420 | dbg_hid("couldn't allocate rdesc memory (post_reset)\n"); | 1420 | dbg_hid("couldn't allocate rdesc memory (post_reset)\n"); |
| 1421 | return 1; | 1421 | return 1; |
| 1422 | } | 1422 | } |
| 1423 | status = hid_get_class_descriptor(dev, | 1423 | status = hid_get_class_descriptor(dev, |
| 1424 | interface->desc.bInterfaceNumber, | 1424 | interface->desc.bInterfaceNumber, |
| 1425 | HID_DT_REPORT, rdesc, hid->rsize); | 1425 | HID_DT_REPORT, rdesc, hid->dev_rsize); |
| 1426 | if (status < 0) { | 1426 | if (status < 0) { |
| 1427 | dbg_hid("reading report descriptor failed (post_reset)\n"); | 1427 | dbg_hid("reading report descriptor failed (post_reset)\n"); |
| 1428 | kfree(rdesc); | 1428 | kfree(rdesc); |
| 1429 | return 1; | 1429 | return 1; |
| 1430 | } | 1430 | } |
| 1431 | status = memcmp(rdesc, hid->rdesc, hid->rsize); | 1431 | status = memcmp(rdesc, hid->dev_rdesc, hid->dev_rsize); |
| 1432 | kfree(rdesc); | 1432 | kfree(rdesc); |
| 1433 | if (status != 0) { | 1433 | if (status != 0) { |
| 1434 | dbg_hid("report descriptor changed\n"); | 1434 | dbg_hid("report descriptor changed\n"); |
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 991e85c7325c..11c7932dc7e6 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c | |||
| @@ -70,12 +70,13 @@ static const struct hid_blacklist { | |||
| 70 | { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, | 70 | { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, |
| 71 | { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, | 71 | { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, |
| 72 | { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, | 72 | { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, |
| 73 | { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, | ||
| 73 | { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, | 74 | { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, |
| 74 | { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, | 75 | { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, |
| 75 | { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS }, | 76 | { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS }, |
| 76 | { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS }, | 77 | { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS }, |
| 77 | { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, | 78 | { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, |
| 78 | { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NOGET }, | 79 | { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001, HID_QUIRK_NOGET }, |
| 79 | { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET }, | 80 | { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET }, |
| 80 | { USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET }, | 81 | { USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET }, |
| 81 | { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, | 82 | { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, |
diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c index cfec802cf9ca..f915eb1c29f7 100644 --- a/drivers/hwmon/ad7314.c +++ b/drivers/hwmon/ad7314.c | |||
| @@ -87,10 +87,18 @@ static ssize_t ad7314_show_temperature(struct device *dev, | |||
| 87 | } | 87 | } |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | static ssize_t ad7314_show_name(struct device *dev, | ||
| 91 | struct device_attribute *devattr, char *buf) | ||
| 92 | { | ||
| 93 | return sprintf(buf, "%s\n", to_spi_device(dev)->modalias); | ||
| 94 | } | ||
| 95 | |||
| 96 | static DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL); | ||
| 90 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, | 97 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, |
| 91 | ad7314_show_temperature, NULL, 0); | 98 | ad7314_show_temperature, NULL, 0); |
| 92 | 99 | ||
| 93 | static struct attribute *ad7314_attributes[] = { | 100 | static struct attribute *ad7314_attributes[] = { |
| 101 | &dev_attr_name.attr, | ||
| 94 | &sensor_dev_attr_temp1_input.dev_attr.attr, | 102 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
| 95 | NULL, | 103 | NULL, |
| 96 | }; | 104 | }; |
diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c index e65c6e45d36b..7bf4ce3d405e 100644 --- a/drivers/hwmon/ads7871.c +++ b/drivers/hwmon/ads7871.c | |||
| @@ -139,6 +139,12 @@ static ssize_t show_voltage(struct device *dev, | |||
| 139 | } | 139 | } |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | static ssize_t ads7871_show_name(struct device *dev, | ||
| 143 | struct device_attribute *devattr, char *buf) | ||
| 144 | { | ||
| 145 | return sprintf(buf, "%s\n", to_spi_device(dev)->modalias); | ||
| 146 | } | ||
| 147 | |||
| 142 | static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_voltage, NULL, 0); | 148 | static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_voltage, NULL, 0); |
| 143 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 1); | 149 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 1); |
| 144 | static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 2); | 150 | static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 2); |
| @@ -148,6 +154,8 @@ static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_voltage, NULL, 5); | |||
| 148 | static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 6); | 154 | static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 6); |
| 149 | static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 7); | 155 | static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 7); |
| 150 | 156 | ||
| 157 | static DEVICE_ATTR(name, S_IRUGO, ads7871_show_name, NULL); | ||
| 158 | |||
| 151 | static struct attribute *ads7871_attributes[] = { | 159 | static struct attribute *ads7871_attributes[] = { |
| 152 | &sensor_dev_attr_in0_input.dev_attr.attr, | 160 | &sensor_dev_attr_in0_input.dev_attr.attr, |
| 153 | &sensor_dev_attr_in1_input.dev_attr.attr, | 161 | &sensor_dev_attr_in1_input.dev_attr.attr, |
| @@ -157,6 +165,7 @@ static struct attribute *ads7871_attributes[] = { | |||
| 157 | &sensor_dev_attr_in5_input.dev_attr.attr, | 165 | &sensor_dev_attr_in5_input.dev_attr.attr, |
| 158 | &sensor_dev_attr_in6_input.dev_attr.attr, | 166 | &sensor_dev_attr_in6_input.dev_attr.attr, |
| 159 | &sensor_dev_attr_in7_input.dev_attr.attr, | 167 | &sensor_dev_attr_in7_input.dev_attr.attr, |
| 168 | &dev_attr_name.attr, | ||
| 160 | NULL | 169 | NULL |
| 161 | }; | 170 | }; |
| 162 | 171 | ||
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 282708860517..8f3f6f2c45fd 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c | |||
| @@ -53,10 +53,10 @@ | |||
| 53 | 53 | ||
| 54 | #define APPLESMC_MAX_DATA_LENGTH 32 | 54 | #define APPLESMC_MAX_DATA_LENGTH 32 |
| 55 | 55 | ||
| 56 | /* wait up to 32 ms for a status change. */ | 56 | /* wait up to 128 ms for a status change. */ |
| 57 | #define APPLESMC_MIN_WAIT 0x0010 | 57 | #define APPLESMC_MIN_WAIT 0x0010 |
| 58 | #define APPLESMC_RETRY_WAIT 0x0100 | 58 | #define APPLESMC_RETRY_WAIT 0x0100 |
| 59 | #define APPLESMC_MAX_WAIT 0x8000 | 59 | #define APPLESMC_MAX_WAIT 0x20000 |
| 60 | 60 | ||
| 61 | #define APPLESMC_READ_CMD 0x10 | 61 | #define APPLESMC_READ_CMD 0x10 |
| 62 | #define APPLESMC_WRITE_CMD 0x11 | 62 | #define APPLESMC_WRITE_CMD 0x11 |
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 0fa356fe82cc..984a3f13923b 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c | |||
| @@ -815,17 +815,20 @@ static int __init coretemp_init(void) | |||
| 815 | if (err) | 815 | if (err) |
| 816 | goto exit; | 816 | goto exit; |
| 817 | 817 | ||
| 818 | get_online_cpus(); | ||
| 818 | for_each_online_cpu(i) | 819 | for_each_online_cpu(i) |
| 819 | get_core_online(i); | 820 | get_core_online(i); |
| 820 | 821 | ||
| 821 | #ifndef CONFIG_HOTPLUG_CPU | 822 | #ifndef CONFIG_HOTPLUG_CPU |
| 822 | if (list_empty(&pdev_list)) { | 823 | if (list_empty(&pdev_list)) { |
| 824 | put_online_cpus(); | ||
| 823 | err = -ENODEV; | 825 | err = -ENODEV; |
| 824 | goto exit_driver_unreg; | 826 | goto exit_driver_unreg; |
| 825 | } | 827 | } |
| 826 | #endif | 828 | #endif |
| 827 | 829 | ||
| 828 | register_hotcpu_notifier(&coretemp_cpu_notifier); | 830 | register_hotcpu_notifier(&coretemp_cpu_notifier); |
| 831 | put_online_cpus(); | ||
| 829 | return 0; | 832 | return 0; |
| 830 | 833 | ||
| 831 | #ifndef CONFIG_HOTPLUG_CPU | 834 | #ifndef CONFIG_HOTPLUG_CPU |
| @@ -840,6 +843,7 @@ static void __exit coretemp_exit(void) | |||
| 840 | { | 843 | { |
| 841 | struct pdev_entry *p, *n; | 844 | struct pdev_entry *p, *n; |
| 842 | 845 | ||
| 846 | get_online_cpus(); | ||
| 843 | unregister_hotcpu_notifier(&coretemp_cpu_notifier); | 847 | unregister_hotcpu_notifier(&coretemp_cpu_notifier); |
| 844 | mutex_lock(&pdev_list_mutex); | 848 | mutex_lock(&pdev_list_mutex); |
| 845 | list_for_each_entry_safe(p, n, &pdev_list, list) { | 849 | list_for_each_entry_safe(p, n, &pdev_list, list) { |
| @@ -848,6 +852,7 @@ static void __exit coretemp_exit(void) | |||
| 848 | kfree(p); | 852 | kfree(p); |
| 849 | } | 853 | } |
| 850 | mutex_unlock(&pdev_list_mutex); | 854 | mutex_unlock(&pdev_list_mutex); |
| 855 | put_online_cpus(); | ||
| 851 | platform_driver_unregister(&coretemp_driver); | 856 | platform_driver_unregister(&coretemp_driver); |
| 852 | } | 857 | } |
| 853 | 858 | ||
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index 2764b78a784b..af69073b3fe8 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c | |||
| @@ -129,12 +129,12 @@ static bool __devinit fam15h_power_is_internal_node0(struct pci_dev *f4) | |||
| 129 | * counter saturations resulting in bogus power readings. | 129 | * counter saturations resulting in bogus power readings. |
| 130 | * We correct this value ourselves to cope with older BIOSes. | 130 | * We correct this value ourselves to cope with older BIOSes. |
| 131 | */ | 131 | */ |
| 132 | static DEFINE_PCI_DEVICE_TABLE(affected_device) = { | 132 | static const struct pci_device_id affected_device[] = { |
| 133 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) }, | 133 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) }, |
| 134 | { 0 } | 134 | { 0 } |
| 135 | }; | 135 | }; |
| 136 | 136 | ||
| 137 | static void __devinit tweak_runavg_range(struct pci_dev *pdev) | 137 | static void tweak_runavg_range(struct pci_dev *pdev) |
| 138 | { | 138 | { |
| 139 | u32 val; | 139 | u32 val; |
| 140 | 140 | ||
| @@ -158,6 +158,16 @@ static void __devinit tweak_runavg_range(struct pci_dev *pdev) | |||
| 158 | REG_TDP_RUNNING_AVERAGE, val); | 158 | REG_TDP_RUNNING_AVERAGE, val); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | #ifdef CONFIG_PM | ||
| 162 | static int fam15h_power_resume(struct pci_dev *pdev) | ||
| 163 | { | ||
| 164 | tweak_runavg_range(pdev); | ||
| 165 | return 0; | ||
| 166 | } | ||
| 167 | #else | ||
| 168 | #define fam15h_power_resume NULL | ||
| 169 | #endif | ||
| 170 | |||
| 161 | static void __devinit fam15h_power_init_data(struct pci_dev *f4, | 171 | static void __devinit fam15h_power_init_data(struct pci_dev *f4, |
| 162 | struct fam15h_power_data *data) | 172 | struct fam15h_power_data *data) |
| 163 | { | 173 | { |
| @@ -256,6 +266,7 @@ static struct pci_driver fam15h_power_driver = { | |||
| 256 | .id_table = fam15h_power_id_table, | 266 | .id_table = fam15h_power_id_table, |
| 257 | .probe = fam15h_power_probe, | 267 | .probe = fam15h_power_probe, |
| 258 | .remove = __devexit_p(fam15h_power_remove), | 268 | .remove = __devexit_p(fam15h_power_remove), |
| 269 | .resume = fam15h_power_resume, | ||
| 259 | }; | 270 | }; |
| 260 | 271 | ||
| 261 | module_pci_driver(fam15h_power_driver); | 272 | module_pci_driver(fam15h_power_driver); |
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 7f3f4a385729..602148299f68 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c | |||
| @@ -69,22 +69,6 @@ struct ina2xx_data { | |||
| 69 | u16 regs[INA2XX_MAX_REGISTERS]; | 69 | u16 regs[INA2XX_MAX_REGISTERS]; |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | int ina2xx_read_word(struct i2c_client *client, int reg) | ||
| 73 | { | ||
| 74 | int val = i2c_smbus_read_word_data(client, reg); | ||
| 75 | if (unlikely(val < 0)) { | ||
| 76 | dev_dbg(&client->dev, | ||
| 77 | "Failed to read register: %d\n", reg); | ||
| 78 | return val; | ||
| 79 | } | ||
| 80 | return be16_to_cpu(val); | ||
| 81 | } | ||
| 82 | |||
| 83 | void ina2xx_write_word(struct i2c_client *client, int reg, int data) | ||
| 84 | { | ||
| 85 | i2c_smbus_write_word_data(client, reg, cpu_to_be16(data)); | ||
| 86 | } | ||
| 87 | |||
| 88 | static struct ina2xx_data *ina2xx_update_device(struct device *dev) | 72 | static struct ina2xx_data *ina2xx_update_device(struct device *dev) |
| 89 | { | 73 | { |
| 90 | struct i2c_client *client = to_i2c_client(dev); | 74 | struct i2c_client *client = to_i2c_client(dev); |
| @@ -102,7 +86,7 @@ static struct ina2xx_data *ina2xx_update_device(struct device *dev) | |||
| 102 | 86 | ||
| 103 | /* Read all registers */ | 87 | /* Read all registers */ |
| 104 | for (i = 0; i < data->registers; i++) { | 88 | for (i = 0; i < data->registers; i++) { |
| 105 | int rv = ina2xx_read_word(client, i); | 89 | int rv = i2c_smbus_read_word_swapped(client, i); |
| 106 | if (rv < 0) { | 90 | if (rv < 0) { |
| 107 | ret = ERR_PTR(rv); | 91 | ret = ERR_PTR(rv); |
| 108 | goto abort; | 92 | goto abort; |
| @@ -279,22 +263,26 @@ static int ina2xx_probe(struct i2c_client *client, | |||
| 279 | switch (data->kind) { | 263 | switch (data->kind) { |
| 280 | case ina219: | 264 | case ina219: |
| 281 | /* device configuration */ | 265 | /* device configuration */ |
| 282 | ina2xx_write_word(client, INA2XX_CONFIG, INA219_CONFIG_DEFAULT); | 266 | i2c_smbus_write_word_swapped(client, INA2XX_CONFIG, |
| 267 | INA219_CONFIG_DEFAULT); | ||
| 283 | 268 | ||
| 284 | /* set current LSB to 1mA, shunt is in uOhms */ | 269 | /* set current LSB to 1mA, shunt is in uOhms */ |
| 285 | /* (equation 13 in datasheet) */ | 270 | /* (equation 13 in datasheet) */ |
| 286 | ina2xx_write_word(client, INA2XX_CALIBRATION, 40960000 / shunt); | 271 | i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION, |
| 272 | 40960000 / shunt); | ||
| 287 | dev_info(&client->dev, | 273 | dev_info(&client->dev, |
| 288 | "power monitor INA219 (Rshunt = %li uOhm)\n", shunt); | 274 | "power monitor INA219 (Rshunt = %li uOhm)\n", shunt); |
| 289 | data->registers = INA219_REGISTERS; | 275 | data->registers = INA219_REGISTERS; |
| 290 | break; | 276 | break; |
| 291 | case ina226: | 277 | case ina226: |
| 292 | /* device configuration */ | 278 | /* device configuration */ |
| 293 | ina2xx_write_word(client, INA2XX_CONFIG, INA226_CONFIG_DEFAULT); | 279 | i2c_smbus_write_word_swapped(client, INA2XX_CONFIG, |
| 280 | INA226_CONFIG_DEFAULT); | ||
| 294 | 281 | ||
| 295 | /* set current LSB to 1mA, shunt is in uOhms */ | 282 | /* set current LSB to 1mA, shunt is in uOhms */ |
| 296 | /* (equation 1 in datasheet)*/ | 283 | /* (equation 1 in datasheet)*/ |
| 297 | ina2xx_write_word(client, INA2XX_CALIBRATION, 5120000 / shunt); | 284 | i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION, |
| 285 | 5120000 / shunt); | ||
| 298 | dev_info(&client->dev, | 286 | dev_info(&client->dev, |
| 299 | "power monitor INA226 (Rshunt = %li uOhm)\n", shunt); | 287 | "power monitor INA226 (Rshunt = %li uOhm)\n", shunt); |
| 300 | data->registers = INA226_REGISTERS; | 288 | data->registers = INA226_REGISTERS; |
diff --git a/drivers/hwmon/twl4030-madc-hwmon.c b/drivers/hwmon/twl4030-madc-hwmon.c index 0018c7dd0097..1a174f0a3cde 100644 --- a/drivers/hwmon/twl4030-madc-hwmon.c +++ b/drivers/hwmon/twl4030-madc-hwmon.c | |||
| @@ -44,12 +44,13 @@ static ssize_t madc_read(struct device *dev, | |||
| 44 | struct device_attribute *devattr, char *buf) | 44 | struct device_attribute *devattr, char *buf) |
| 45 | { | 45 | { |
| 46 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 46 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
| 47 | struct twl4030_madc_request req; | 47 | struct twl4030_madc_request req = { |
| 48 | .channels = 1 << attr->index, | ||
| 49 | .method = TWL4030_MADC_SW2, | ||
| 50 | .type = TWL4030_MADC_WAIT, | ||
| 51 | }; | ||
| 48 | long val; | 52 | long val; |
| 49 | 53 | ||
| 50 | req.channels = (1 << attr->index); | ||
| 51 | req.method = TWL4030_MADC_SW2; | ||
| 52 | req.func_cb = NULL; | ||
| 53 | val = twl4030_madc_conversion(&req); | 54 | val = twl4030_madc_conversion(&req); |
| 54 | if (val < 0) | 55 | if (val < 0) |
| 55 | return val; | 56 | return val; |
diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c index ee4ebc198a94..2e56c6ce9fb6 100644 --- a/drivers/hwmon/via-cputemp.c +++ b/drivers/hwmon/via-cputemp.c | |||
| @@ -328,6 +328,7 @@ static int __init via_cputemp_init(void) | |||
| 328 | if (err) | 328 | if (err) |
| 329 | goto exit; | 329 | goto exit; |
| 330 | 330 | ||
| 331 | get_online_cpus(); | ||
| 331 | for_each_online_cpu(i) { | 332 | for_each_online_cpu(i) { |
| 332 | struct cpuinfo_x86 *c = &cpu_data(i); | 333 | struct cpuinfo_x86 *c = &cpu_data(i); |
| 333 | 334 | ||
| @@ -347,12 +348,14 @@ static int __init via_cputemp_init(void) | |||
| 347 | 348 | ||
| 348 | #ifndef CONFIG_HOTPLUG_CPU | 349 | #ifndef CONFIG_HOTPLUG_CPU |
| 349 | if (list_empty(&pdev_list)) { | 350 | if (list_empty(&pdev_list)) { |
| 351 | put_online_cpus(); | ||
| 350 | err = -ENODEV; | 352 | err = -ENODEV; |
| 351 | goto exit_driver_unreg; | 353 | goto exit_driver_unreg; |
| 352 | } | 354 | } |
| 353 | #endif | 355 | #endif |
| 354 | 356 | ||
| 355 | register_hotcpu_notifier(&via_cputemp_cpu_notifier); | 357 | register_hotcpu_notifier(&via_cputemp_cpu_notifier); |
| 358 | put_online_cpus(); | ||
| 356 | return 0; | 359 | return 0; |
| 357 | 360 | ||
| 358 | #ifndef CONFIG_HOTPLUG_CPU | 361 | #ifndef CONFIG_HOTPLUG_CPU |
| @@ -367,6 +370,7 @@ static void __exit via_cputemp_exit(void) | |||
| 367 | { | 370 | { |
| 368 | struct pdev_entry *p, *n; | 371 | struct pdev_entry *p, *n; |
| 369 | 372 | ||
| 373 | get_online_cpus(); | ||
| 370 | unregister_hotcpu_notifier(&via_cputemp_cpu_notifier); | 374 | unregister_hotcpu_notifier(&via_cputemp_cpu_notifier); |
| 371 | mutex_lock(&pdev_list_mutex); | 375 | mutex_lock(&pdev_list_mutex); |
| 372 | list_for_each_entry_safe(p, n, &pdev_list, list) { | 376 | list_for_each_entry_safe(p, n, &pdev_list, list) { |
| @@ -375,6 +379,7 @@ static void __exit via_cputemp_exit(void) | |||
| 375 | kfree(p); | 379 | kfree(p); |
| 376 | } | 380 | } |
| 377 | mutex_unlock(&pdev_list_mutex); | 381 | mutex_unlock(&pdev_list_mutex); |
| 382 | put_online_cpus(); | ||
| 378 | platform_driver_unregister(&via_cputemp_driver); | 383 | platform_driver_unregister(&via_cputemp_driver); |
| 379 | } | 384 | } |
| 380 | 385 | ||
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c index 1201a15784c3..db713c0dfba4 100644 --- a/drivers/hwspinlock/hwspinlock_core.c +++ b/drivers/hwspinlock/hwspinlock_core.c | |||
| @@ -552,7 +552,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_request_specific); | |||
| 552 | */ | 552 | */ |
| 553 | int hwspin_lock_free(struct hwspinlock *hwlock) | 553 | int hwspin_lock_free(struct hwspinlock *hwlock) |
| 554 | { | 554 | { |
| 555 | struct device *dev = hwlock->bank->dev; | 555 | struct device *dev; |
| 556 | struct hwspinlock *tmp; | 556 | struct hwspinlock *tmp; |
| 557 | int ret; | 557 | int ret; |
| 558 | 558 | ||
| @@ -561,6 +561,7 @@ int hwspin_lock_free(struct hwspinlock *hwlock) | |||
| 561 | return -EINVAL; | 561 | return -EINVAL; |
| 562 | } | 562 | } |
| 563 | 563 | ||
| 564 | dev = hwlock->bank->dev; | ||
| 564 | mutex_lock(&hwspinlock_tree_lock); | 565 | mutex_lock(&hwspinlock_tree_lock); |
| 565 | 566 | ||
| 566 | /* make sure the hwspinlock is used */ | 567 | /* make sure the hwspinlock is used */ |
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 73133b1063f0..6f5f98d69af7 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c | |||
| @@ -476,17 +476,17 @@ static int pca_init(struct i2c_adapter *adap) | |||
| 476 | /* To avoid integer overflow, use clock/100 for calculations */ | 476 | /* To avoid integer overflow, use clock/100 for calculations */ |
| 477 | clock = pca_clock(pca_data) / 100; | 477 | clock = pca_clock(pca_data) / 100; |
| 478 | 478 | ||
| 479 | if (pca_data->i2c_clock > 10000) { | 479 | if (pca_data->i2c_clock > 1000000) { |
| 480 | mode = I2C_PCA_MODE_TURBO; | 480 | mode = I2C_PCA_MODE_TURBO; |
| 481 | min_tlow = 14; | 481 | min_tlow = 14; |
| 482 | min_thi = 5; | 482 | min_thi = 5; |
| 483 | raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */ | 483 | raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */ |
| 484 | } else if (pca_data->i2c_clock > 4000) { | 484 | } else if (pca_data->i2c_clock > 400000) { |
| 485 | mode = I2C_PCA_MODE_FASTP; | 485 | mode = I2C_PCA_MODE_FASTP; |
| 486 | min_tlow = 17; | 486 | min_tlow = 17; |
| 487 | min_thi = 9; | 487 | min_thi = 9; |
| 488 | raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */ | 488 | raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */ |
| 489 | } else if (pca_data->i2c_clock > 1000) { | 489 | } else if (pca_data->i2c_clock > 100000) { |
| 490 | mode = I2C_PCA_MODE_FAST; | 490 | mode = I2C_PCA_MODE_FAST; |
| 491 | min_tlow = 44; | 491 | min_tlow = 44; |
| 492 | min_thi = 20; | 492 | min_thi = 20; |
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index b4aaa1bd6728..970a1612e795 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
| @@ -104,6 +104,7 @@ config I2C_I801 | |||
| 104 | DH89xxCC (PCH) | 104 | DH89xxCC (PCH) |
| 105 | Panther Point (PCH) | 105 | Panther Point (PCH) |
| 106 | Lynx Point (PCH) | 106 | Lynx Point (PCH) |
| 107 | Lynx Point-LP (PCH) | ||
| 107 | 108 | ||
| 108 | This driver can also be built as a module. If so, the module | 109 | This driver can also be built as a module. If so, the module |
| 109 | will be called i2c-i801. | 110 | will be called i2c-i801. |
| @@ -354,9 +355,13 @@ config I2C_DAVINCI | |||
| 354 | devices such as DaVinci NIC. | 355 | devices such as DaVinci NIC. |
| 355 | For details please see http://www.ti.com/davinci | 356 | For details please see http://www.ti.com/davinci |
| 356 | 357 | ||
| 358 | config I2C_DESIGNWARE_CORE | ||
| 359 | tristate | ||
| 360 | |||
| 357 | config I2C_DESIGNWARE_PLATFORM | 361 | config I2C_DESIGNWARE_PLATFORM |
| 358 | tristate "Synopsys DesignWare Platform" | 362 | tristate "Synopsys DesignWare Platform" |
| 359 | depends on HAVE_CLK | 363 | depends on HAVE_CLK |
| 364 | select I2C_DESIGNWARE_CORE | ||
| 360 | help | 365 | help |
| 361 | If you say yes to this option, support will be included for the | 366 | If you say yes to this option, support will be included for the |
| 362 | Synopsys DesignWare I2C adapter. Only master mode is supported. | 367 | Synopsys DesignWare I2C adapter. Only master mode is supported. |
| @@ -367,6 +372,7 @@ config I2C_DESIGNWARE_PLATFORM | |||
| 367 | config I2C_DESIGNWARE_PCI | 372 | config I2C_DESIGNWARE_PCI |
| 368 | tristate "Synopsys DesignWare PCI" | 373 | tristate "Synopsys DesignWare PCI" |
| 369 | depends on PCI | 374 | depends on PCI |
| 375 | select I2C_DESIGNWARE_CORE | ||
| 370 | help | 376 | help |
| 371 | If you say yes to this option, support will be included for the | 377 | If you say yes to this option, support will be included for the |
| 372 | Synopsys DesignWare I2C adapter. Only master mode is supported. | 378 | Synopsys DesignWare I2C adapter. Only master mode is supported. |
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index ce3c2be7fb40..37c4182cc98b 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile | |||
| @@ -33,10 +33,11 @@ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o | |||
| 33 | obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o | 33 | obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o |
| 34 | obj-$(CONFIG_I2C_CPM) += i2c-cpm.o | 34 | obj-$(CONFIG_I2C_CPM) += i2c-cpm.o |
| 35 | obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o | 35 | obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o |
| 36 | obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o | ||
| 36 | obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o | 37 | obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o |
| 37 | i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o | 38 | i2c-designware-platform-objs := i2c-designware-platdrv.o |
| 38 | obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o | 39 | obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o |
| 39 | i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-core.o | 40 | i2c-designware-pci-objs := i2c-designware-pcidrv.o |
| 40 | obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o | 41 | obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o |
| 41 | obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o | 42 | obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o |
| 42 | obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o | 43 | obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o |
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 1e48bec80edf..7b8ebbefb581 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | * ---------------------------------------------------------------------------- | 25 | * ---------------------------------------------------------------------------- |
| 26 | * | 26 | * |
| 27 | */ | 27 | */ |
| 28 | #include <linux/export.h> | ||
| 28 | #include <linux/clk.h> | 29 | #include <linux/clk.h> |
| 29 | #include <linux/errno.h> | 30 | #include <linux/errno.h> |
| 30 | #include <linux/err.h> | 31 | #include <linux/err.h> |
| @@ -316,6 +317,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev) | |||
| 316 | dw_writel(dev, dev->master_cfg , DW_IC_CON); | 317 | dw_writel(dev, dev->master_cfg , DW_IC_CON); |
| 317 | return 0; | 318 | return 0; |
| 318 | } | 319 | } |
| 320 | EXPORT_SYMBOL_GPL(i2c_dw_init); | ||
| 319 | 321 | ||
| 320 | /* | 322 | /* |
| 321 | * Waiting for bus not busy | 323 | * Waiting for bus not busy |
| @@ -568,12 +570,14 @@ done: | |||
| 568 | 570 | ||
| 569 | return ret; | 571 | return ret; |
| 570 | } | 572 | } |
| 573 | EXPORT_SYMBOL_GPL(i2c_dw_xfer); | ||
| 571 | 574 | ||
| 572 | u32 i2c_dw_func(struct i2c_adapter *adap) | 575 | u32 i2c_dw_func(struct i2c_adapter *adap) |
| 573 | { | 576 | { |
| 574 | struct dw_i2c_dev *dev = i2c_get_adapdata(adap); | 577 | struct dw_i2c_dev *dev = i2c_get_adapdata(adap); |
| 575 | return dev->functionality; | 578 | return dev->functionality; |
| 576 | } | 579 | } |
| 580 | EXPORT_SYMBOL_GPL(i2c_dw_func); | ||
| 577 | 581 | ||
| 578 | static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) | 582 | static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) |
| 579 | { | 583 | { |
| @@ -678,17 +682,20 @@ tx_aborted: | |||
| 678 | 682 | ||
| 679 | return IRQ_HANDLED; | 683 | return IRQ_HANDLED; |
| 680 | } | 684 | } |
| 685 | EXPORT_SYMBOL_GPL(i2c_dw_isr); | ||
| 681 | 686 | ||
| 682 | void i2c_dw_enable(struct dw_i2c_dev *dev) | 687 | void i2c_dw_enable(struct dw_i2c_dev *dev) |
| 683 | { | 688 | { |
| 684 | /* Enable the adapter */ | 689 | /* Enable the adapter */ |
| 685 | dw_writel(dev, 1, DW_IC_ENABLE); | 690 | dw_writel(dev, 1, DW_IC_ENABLE); |
| 686 | } | 691 | } |
| 692 | EXPORT_SYMBOL_GPL(i2c_dw_enable); | ||
| 687 | 693 | ||
| 688 | u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev) | 694 | u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev) |
| 689 | { | 695 | { |
| 690 | return dw_readl(dev, DW_IC_ENABLE); | 696 | return dw_readl(dev, DW_IC_ENABLE); |
| 691 | } | 697 | } |
| 698 | EXPORT_SYMBOL_GPL(i2c_dw_is_enabled); | ||
| 692 | 699 | ||
| 693 | void i2c_dw_disable(struct dw_i2c_dev *dev) | 700 | void i2c_dw_disable(struct dw_i2c_dev *dev) |
| 694 | { | 701 | { |
| @@ -699,18 +706,22 @@ void i2c_dw_disable(struct dw_i2c_dev *dev) | |||
| 699 | dw_writel(dev, 0, DW_IC_INTR_MASK); | 706 | dw_writel(dev, 0, DW_IC_INTR_MASK); |
| 700 | dw_readl(dev, DW_IC_CLR_INTR); | 707 | dw_readl(dev, DW_IC_CLR_INTR); |
| 701 | } | 708 | } |
| 709 | EXPORT_SYMBOL_GPL(i2c_dw_disable); | ||
| 702 | 710 | ||
| 703 | void i2c_dw_clear_int(struct dw_i2c_dev *dev) | 711 | void i2c_dw_clear_int(struct dw_i2c_dev *dev) |
| 704 | { | 712 | { |
| 705 | dw_readl(dev, DW_IC_CLR_INTR); | 713 | dw_readl(dev, DW_IC_CLR_INTR); |
| 706 | } | 714 | } |
| 715 | EXPORT_SYMBOL_GPL(i2c_dw_clear_int); | ||
| 707 | 716 | ||
| 708 | void i2c_dw_disable_int(struct dw_i2c_dev *dev) | 717 | void i2c_dw_disable_int(struct dw_i2c_dev *dev) |
| 709 | { | 718 | { |
| 710 | dw_writel(dev, 0, DW_IC_INTR_MASK); | 719 | dw_writel(dev, 0, DW_IC_INTR_MASK); |
| 711 | } | 720 | } |
| 721 | EXPORT_SYMBOL_GPL(i2c_dw_disable_int); | ||
| 712 | 722 | ||
| 713 | u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev) | 723 | u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev) |
| 714 | { | 724 | { |
| 715 | return dw_readl(dev, DW_IC_COMP_PARAM_1); | 725 | return dw_readl(dev, DW_IC_COMP_PARAM_1); |
| 716 | } | 726 | } |
| 727 | EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param); | ||
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 898dcf9c7ade..33e9b0c09af2 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c | |||
| @@ -52,6 +52,7 @@ | |||
| 52 | DH89xxCC (PCH) 0x2330 32 hard yes yes yes | 52 | DH89xxCC (PCH) 0x2330 32 hard yes yes yes |
| 53 | Panther Point (PCH) 0x1e22 32 hard yes yes yes | 53 | Panther Point (PCH) 0x1e22 32 hard yes yes yes |
| 54 | Lynx Point (PCH) 0x8c22 32 hard yes yes yes | 54 | Lynx Point (PCH) 0x8c22 32 hard yes yes yes |
| 55 | Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes | ||
| 55 | 56 | ||
| 56 | Features supported by this driver: | 57 | Features supported by this driver: |
| 57 | Software PEC no | 58 | Software PEC no |
| @@ -155,6 +156,7 @@ | |||
| 155 | #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 | 156 | #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 |
| 156 | #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 | 157 | #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 |
| 157 | #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 | 158 | #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 |
| 159 | #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 | ||
| 158 | 160 | ||
| 159 | struct i801_priv { | 161 | struct i801_priv { |
| 160 | struct i2c_adapter adapter; | 162 | struct i2c_adapter adapter; |
| @@ -771,6 +773,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = { | |||
| 771 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) }, | 773 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) }, |
| 772 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) }, | 774 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) }, |
| 773 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) }, | 775 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) }, |
| 776 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) }, | ||
| 774 | { 0, } | 777 | { 0, } |
| 775 | }; | 778 | }; |
| 776 | 779 | ||
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 088c5c1ed17d..51f05b8520ed 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c | |||
| @@ -365,10 +365,6 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) | |||
| 365 | struct device_node *node = dev->of_node; | 365 | struct device_node *node = dev->of_node; |
| 366 | int ret; | 366 | int ret; |
| 367 | 367 | ||
| 368 | if (!node) | ||
| 369 | return -EINVAL; | ||
| 370 | |||
| 371 | i2c->speed = &mxs_i2c_95kHz_config; | ||
| 372 | ret = of_property_read_u32(node, "clock-frequency", &speed); | 368 | ret = of_property_read_u32(node, "clock-frequency", &speed); |
| 373 | if (ret) | 369 | if (ret) |
| 374 | dev_warn(dev, "No I2C speed selected, using 100kHz\n"); | 370 | dev_warn(dev, "No I2C speed selected, using 100kHz\n"); |
| @@ -419,10 +415,13 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) | |||
| 419 | return err; | 415 | return err; |
| 420 | 416 | ||
| 421 | i2c->dev = dev; | 417 | i2c->dev = dev; |
| 418 | i2c->speed = &mxs_i2c_95kHz_config; | ||
| 422 | 419 | ||
| 423 | err = mxs_i2c_get_ofdata(i2c); | 420 | if (dev->of_node) { |
| 424 | if (err) | 421 | err = mxs_i2c_get_ofdata(i2c); |
| 425 | return err; | 422 | if (err) |
| 423 | return err; | ||
| 424 | } | ||
| 426 | 425 | ||
| 427 | platform_set_drvdata(pdev, i2c); | 426 | platform_set_drvdata(pdev, i2c); |
| 428 | 427 | ||
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 5d54416770b0..8488bddfe465 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c | |||
| @@ -48,8 +48,9 @@ enum { | |||
| 48 | mcntrl_afie = 0x00000002, | 48 | mcntrl_afie = 0x00000002, |
| 49 | mcntrl_naie = 0x00000004, | 49 | mcntrl_naie = 0x00000004, |
| 50 | mcntrl_drmie = 0x00000008, | 50 | mcntrl_drmie = 0x00000008, |
| 51 | mcntrl_daie = 0x00000020, | 51 | mcntrl_drsie = 0x00000010, |
| 52 | mcntrl_rffie = 0x00000040, | 52 | mcntrl_rffie = 0x00000020, |
| 53 | mcntrl_daie = 0x00000040, | ||
| 53 | mcntrl_tffie = 0x00000080, | 54 | mcntrl_tffie = 0x00000080, |
| 54 | mcntrl_reset = 0x00000100, | 55 | mcntrl_reset = 0x00000100, |
| 55 | mcntrl_cdbmode = 0x00000400, | 56 | mcntrl_cdbmode = 0x00000400, |
| @@ -290,31 +291,37 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data) | |||
| 290 | * or we didn't 'ask' for it yet. | 291 | * or we didn't 'ask' for it yet. |
| 291 | */ | 292 | */ |
| 292 | if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) { | 293 | if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) { |
| 293 | dev_dbg(&alg_data->adapter.dev, | 294 | /* 'Asking' is done asynchronously, e.g. dummy TX of several |
| 294 | "%s(): Write dummy data to fill Rx-fifo...\n", | 295 | * bytes is done before the first actual RX arrives in FIFO. |
| 295 | __func__); | 296 | * Therefore, ordered bytes (via TX) are counted separately. |
| 297 | */ | ||
| 298 | if (alg_data->mif.order) { | ||
| 299 | dev_dbg(&alg_data->adapter.dev, | ||
| 300 | "%s(): Write dummy data to fill Rx-fifo...\n", | ||
| 301 | __func__); | ||
| 296 | 302 | ||
| 297 | if (alg_data->mif.len == 1) { | 303 | if (alg_data->mif.order == 1) { |
| 298 | /* Last byte, do not acknowledge next rcv. */ | 304 | /* Last byte, do not acknowledge next rcv. */ |
| 299 | val |= stop_bit; | 305 | val |= stop_bit; |
| 306 | |||
| 307 | /* | ||
| 308 | * Enable interrupt RFDAIE (data in Rx fifo), | ||
| 309 | * and disable DRMIE (need data for Tx) | ||
| 310 | */ | ||
| 311 | ctl = ioread32(I2C_REG_CTL(alg_data)); | ||
| 312 | ctl |= mcntrl_rffie | mcntrl_daie; | ||
| 313 | ctl &= ~mcntrl_drmie; | ||
| 314 | iowrite32(ctl, I2C_REG_CTL(alg_data)); | ||
| 315 | } | ||
| 300 | 316 | ||
| 301 | /* | 317 | /* |
| 302 | * Enable interrupt RFDAIE (data in Rx fifo), | 318 | * Now we'll 'ask' for data: |
| 303 | * and disable DRMIE (need data for Tx) | 319 | * For each byte we want to receive, we must |
| 320 | * write a (dummy) byte to the Tx-FIFO. | ||
| 304 | */ | 321 | */ |
| 305 | ctl = ioread32(I2C_REG_CTL(alg_data)); | 322 | iowrite32(val, I2C_REG_TX(alg_data)); |
| 306 | ctl |= mcntrl_rffie | mcntrl_daie; | 323 | alg_data->mif.order--; |
| 307 | ctl &= ~mcntrl_drmie; | ||
| 308 | iowrite32(ctl, I2C_REG_CTL(alg_data)); | ||
| 309 | } | 324 | } |
| 310 | |||
| 311 | /* | ||
| 312 | * Now we'll 'ask' for data: | ||
| 313 | * For each byte we want to receive, we must | ||
| 314 | * write a (dummy) byte to the Tx-FIFO. | ||
| 315 | */ | ||
| 316 | iowrite32(val, I2C_REG_TX(alg_data)); | ||
| 317 | |||
| 318 | return 0; | 325 | return 0; |
| 319 | } | 326 | } |
| 320 | 327 | ||
| @@ -514,6 +521,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | |||
| 514 | 521 | ||
| 515 | alg_data->mif.buf = pmsg->buf; | 522 | alg_data->mif.buf = pmsg->buf; |
| 516 | alg_data->mif.len = pmsg->len; | 523 | alg_data->mif.len = pmsg->len; |
| 524 | alg_data->mif.order = pmsg->len; | ||
| 517 | alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ? | 525 | alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ? |
| 518 | I2C_SMBUS_READ : I2C_SMBUS_WRITE; | 526 | I2C_SMBUS_READ : I2C_SMBUS_WRITE; |
| 519 | alg_data->mif.ret = 0; | 527 | alg_data->mif.ret = 0; |
| @@ -566,6 +574,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | |||
| 566 | /* Cleanup to be sure... */ | 574 | /* Cleanup to be sure... */ |
| 567 | alg_data->mif.buf = NULL; | 575 | alg_data->mif.buf = NULL; |
| 568 | alg_data->mif.len = 0; | 576 | alg_data->mif.len = 0; |
| 577 | alg_data->mif.order = 0; | ||
| 569 | 578 | ||
| 570 | dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n", | 579 | dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n", |
| 571 | __func__, ioread32(I2C_REG_STS(alg_data))); | 580 | __func__, ioread32(I2C_REG_STS(alg_data))); |
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 2efa56c5ff2c..2091ae8f539a 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
| @@ -637,6 +637,22 @@ static void i2c_adapter_dev_release(struct device *dev) | |||
| 637 | } | 637 | } |
| 638 | 638 | ||
| 639 | /* | 639 | /* |
| 640 | * This function is only needed for mutex_lock_nested, so it is never | ||
| 641 | * called unless locking correctness checking is enabled. Thus we | ||
| 642 | * make it inline to avoid a compiler warning. That's what gcc ends up | ||
| 643 | * doing anyway. | ||
| 644 | */ | ||
| 645 | static inline unsigned int i2c_adapter_depth(struct i2c_adapter *adapter) | ||
| 646 | { | ||
| 647 | unsigned int depth = 0; | ||
| 648 | |||
| 649 | while ((adapter = i2c_parent_is_i2c_adapter(adapter))) | ||
| 650 | depth++; | ||
| 651 | |||
| 652 | return depth; | ||
| 653 | } | ||
| 654 | |||
| 655 | /* | ||
| 640 | * Let users instantiate I2C devices through sysfs. This can be used when | 656 | * Let users instantiate I2C devices through sysfs. This can be used when |
| 641 | * platform initialization code doesn't contain the proper data for | 657 | * platform initialization code doesn't contain the proper data for |
| 642 | * whatever reason. Also useful for drivers that do device detection and | 658 | * whatever reason. Also useful for drivers that do device detection and |
| @@ -726,7 +742,8 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, | |||
| 726 | 742 | ||
| 727 | /* Make sure the device was added through sysfs */ | 743 | /* Make sure the device was added through sysfs */ |
| 728 | res = -ENOENT; | 744 | res = -ENOENT; |
| 729 | mutex_lock(&adap->userspace_clients_lock); | 745 | mutex_lock_nested(&adap->userspace_clients_lock, |
| 746 | i2c_adapter_depth(adap)); | ||
| 730 | list_for_each_entry_safe(client, next, &adap->userspace_clients, | 747 | list_for_each_entry_safe(client, next, &adap->userspace_clients, |
| 731 | detected) { | 748 | detected) { |
| 732 | if (client->addr == addr) { | 749 | if (client->addr == addr) { |
| @@ -1073,7 +1090,8 @@ int i2c_del_adapter(struct i2c_adapter *adap) | |||
| 1073 | return res; | 1090 | return res; |
| 1074 | 1091 | ||
| 1075 | /* Remove devices instantiated from sysfs */ | 1092 | /* Remove devices instantiated from sysfs */ |
| 1076 | mutex_lock(&adap->userspace_clients_lock); | 1093 | mutex_lock_nested(&adap->userspace_clients_lock, |
| 1094 | i2c_adapter_depth(adap)); | ||
| 1077 | list_for_each_entry_safe(client, next, &adap->userspace_clients, | 1095 | list_for_each_entry_safe(client, next, &adap->userspace_clients, |
| 1078 | detected) { | 1096 | detected) { |
| 1079 | dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name, | 1097 | dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name, |
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index f61780a02374..3bd5540238a7 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c | |||
| @@ -617,7 +617,7 @@ static int __devinit at91_adc_probe(struct platform_device *pdev) | |||
| 617 | st->adc_clk = clk_get(&pdev->dev, "adc_op_clk"); | 617 | st->adc_clk = clk_get(&pdev->dev, "adc_op_clk"); |
| 618 | if (IS_ERR(st->adc_clk)) { | 618 | if (IS_ERR(st->adc_clk)) { |
| 619 | dev_err(&pdev->dev, "Failed to get the ADC clock.\n"); | 619 | dev_err(&pdev->dev, "Failed to get the ADC clock.\n"); |
| 620 | ret = PTR_ERR(st->clk); | 620 | ret = PTR_ERR(st->adc_clk); |
| 621 | goto error_disable_clk; | 621 | goto error_disable_clk; |
| 622 | } | 622 | } |
| 623 | 623 | ||
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 51f42061dae9..6cfd4d8fd0bd 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c | |||
| @@ -1361,11 +1361,11 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb) | |||
| 1361 | struct tid_info *t = dev->rdev.lldi.tids; | 1361 | struct tid_info *t = dev->rdev.lldi.tids; |
| 1362 | 1362 | ||
| 1363 | ep = lookup_tid(t, tid); | 1363 | ep = lookup_tid(t, tid); |
| 1364 | PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); | ||
| 1365 | if (!ep) { | 1364 | if (!ep) { |
| 1366 | printk(KERN_WARNING MOD "Abort rpl to freed endpoint\n"); | 1365 | printk(KERN_WARNING MOD "Abort rpl to freed endpoint\n"); |
| 1367 | return 0; | 1366 | return 0; |
| 1368 | } | 1367 | } |
| 1368 | PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); | ||
| 1369 | mutex_lock(&ep->com.mutex); | 1369 | mutex_lock(&ep->com.mutex); |
| 1370 | switch (ep->com.state) { | 1370 | switch (ep->com.state) { |
| 1371 | case ABORTING: | 1371 | case ABORTING: |
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index 53589000fd07..8615d7cf7e01 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c | |||
| @@ -42,6 +42,7 @@ | |||
| 42 | */ | 42 | */ |
| 43 | 43 | ||
| 44 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
| 45 | #include <linux/smpboot.h> | ||
| 45 | 46 | ||
| 46 | #include "ehca_classes.h" | 47 | #include "ehca_classes.h" |
| 47 | #include "ehca_irq.h" | 48 | #include "ehca_irq.h" |
| @@ -652,7 +653,7 @@ void ehca_tasklet_eq(unsigned long data) | |||
| 652 | ehca_process_eq((struct ehca_shca*)data, 1); | 653 | ehca_process_eq((struct ehca_shca*)data, 1); |
| 653 | } | 654 | } |
| 654 | 655 | ||
| 655 | static inline int find_next_online_cpu(struct ehca_comp_pool *pool) | 656 | static int find_next_online_cpu(struct ehca_comp_pool *pool) |
| 656 | { | 657 | { |
| 657 | int cpu; | 658 | int cpu; |
| 658 | unsigned long flags; | 659 | unsigned long flags; |
| @@ -662,17 +663,20 @@ static inline int find_next_online_cpu(struct ehca_comp_pool *pool) | |||
| 662 | ehca_dmp(cpu_online_mask, cpumask_size(), ""); | 663 | ehca_dmp(cpu_online_mask, cpumask_size(), ""); |
| 663 | 664 | ||
| 664 | spin_lock_irqsave(&pool->last_cpu_lock, flags); | 665 | spin_lock_irqsave(&pool->last_cpu_lock, flags); |
| 665 | cpu = cpumask_next(pool->last_cpu, cpu_online_mask); | 666 | do { |
| 666 | if (cpu >= nr_cpu_ids) | 667 | cpu = cpumask_next(pool->last_cpu, cpu_online_mask); |
| 667 | cpu = cpumask_first(cpu_online_mask); | 668 | if (cpu >= nr_cpu_ids) |
| 668 | pool->last_cpu = cpu; | 669 | cpu = cpumask_first(cpu_online_mask); |
| 670 | pool->last_cpu = cpu; | ||
| 671 | } while (!per_cpu_ptr(pool->cpu_comp_tasks, cpu)->active); | ||
| 669 | spin_unlock_irqrestore(&pool->last_cpu_lock, flags); | 672 | spin_unlock_irqrestore(&pool->last_cpu_lock, flags); |
| 670 | 673 | ||
| 671 | return cpu; | 674 | return cpu; |
| 672 | } | 675 | } |
| 673 | 676 | ||
| 674 | static void __queue_comp_task(struct ehca_cq *__cq, | 677 | static void __queue_comp_task(struct ehca_cq *__cq, |
| 675 | struct ehca_cpu_comp_task *cct) | 678 | struct ehca_cpu_comp_task *cct, |
| 679 | struct task_struct *thread) | ||
| 676 | { | 680 | { |
| 677 | unsigned long flags; | 681 | unsigned long flags; |
| 678 | 682 | ||
| @@ -683,7 +687,7 @@ static void __queue_comp_task(struct ehca_cq *__cq, | |||
| 683 | __cq->nr_callbacks++; | 687 | __cq->nr_callbacks++; |
| 684 | list_add_tail(&__cq->entry, &cct->cq_list); | 688 | list_add_tail(&__cq->entry, &cct->cq_list); |
| 685 | cct->cq_jobs++; | 689 | cct->cq_jobs++; |
| 686 | wake_up(&cct->wait_queue); | 690 | wake_up_process(thread); |
| 687 | } else | 691 | } else |
| 688 | __cq->nr_callbacks++; | 692 | __cq->nr_callbacks++; |
| 689 | 693 | ||
| @@ -695,6 +699,7 @@ static void queue_comp_task(struct ehca_cq *__cq) | |||
| 695 | { | 699 | { |
| 696 | int cpu_id; | 700 | int cpu_id; |
| 697 | struct ehca_cpu_comp_task *cct; | 701 | struct ehca_cpu_comp_task *cct; |
| 702 | struct task_struct *thread; | ||
| 698 | int cq_jobs; | 703 | int cq_jobs; |
| 699 | unsigned long flags; | 704 | unsigned long flags; |
| 700 | 705 | ||
| @@ -702,7 +707,8 @@ static void queue_comp_task(struct ehca_cq *__cq) | |||
| 702 | BUG_ON(!cpu_online(cpu_id)); | 707 | BUG_ON(!cpu_online(cpu_id)); |
| 703 | 708 | ||
| 704 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id); | 709 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id); |
| 705 | BUG_ON(!cct); | 710 | thread = *per_cpu_ptr(pool->cpu_comp_threads, cpu_id); |
| 711 | BUG_ON(!cct || !thread); | ||
| 706 | 712 | ||
| 707 | spin_lock_irqsave(&cct->task_lock, flags); | 713 | spin_lock_irqsave(&cct->task_lock, flags); |
| 708 | cq_jobs = cct->cq_jobs; | 714 | cq_jobs = cct->cq_jobs; |
| @@ -710,28 +716,25 @@ static void queue_comp_task(struct ehca_cq *__cq) | |||
| 710 | if (cq_jobs > 0) { | 716 | if (cq_jobs > 0) { |
| 711 | cpu_id = find_next_online_cpu(pool); | 717 | cpu_id = find_next_online_cpu(pool); |
| 712 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id); | 718 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id); |
| 713 | BUG_ON(!cct); | 719 | thread = *per_cpu_ptr(pool->cpu_comp_threads, cpu_id); |
| 720 | BUG_ON(!cct || !thread); | ||
| 714 | } | 721 | } |
| 715 | 722 | __queue_comp_task(__cq, cct, thread); | |
| 716 | __queue_comp_task(__cq, cct); | ||
| 717 | } | 723 | } |
| 718 | 724 | ||
| 719 | static void run_comp_task(struct ehca_cpu_comp_task *cct) | 725 | static void run_comp_task(struct ehca_cpu_comp_task *cct) |
| 720 | { | 726 | { |
| 721 | struct ehca_cq *cq; | 727 | struct ehca_cq *cq; |
| 722 | unsigned long flags; | ||
| 723 | |||
| 724 | spin_lock_irqsave(&cct->task_lock, flags); | ||
| 725 | 728 | ||
| 726 | while (!list_empty(&cct->cq_list)) { | 729 | while (!list_empty(&cct->cq_list)) { |
| 727 | cq = list_entry(cct->cq_list.next, struct ehca_cq, entry); | 730 | cq = list_entry(cct->cq_list.next, struct ehca_cq, entry); |
| 728 | spin_unlock_irqrestore(&cct->task_lock, flags); | 731 | spin_unlock_irq(&cct->task_lock); |
| 729 | 732 | ||
| 730 | comp_event_callback(cq); | 733 | comp_event_callback(cq); |
| 731 | if (atomic_dec_and_test(&cq->nr_events)) | 734 | if (atomic_dec_and_test(&cq->nr_events)) |
| 732 | wake_up(&cq->wait_completion); | 735 | wake_up(&cq->wait_completion); |
| 733 | 736 | ||
| 734 | spin_lock_irqsave(&cct->task_lock, flags); | 737 | spin_lock_irq(&cct->task_lock); |
| 735 | spin_lock(&cq->task_lock); | 738 | spin_lock(&cq->task_lock); |
| 736 | cq->nr_callbacks--; | 739 | cq->nr_callbacks--; |
| 737 | if (!cq->nr_callbacks) { | 740 | if (!cq->nr_callbacks) { |
| @@ -740,159 +743,76 @@ static void run_comp_task(struct ehca_cpu_comp_task *cct) | |||
| 740 | } | 743 | } |
| 741 | spin_unlock(&cq->task_lock); | 744 | spin_unlock(&cq->task_lock); |
| 742 | } | 745 | } |
| 743 | |||
| 744 | spin_unlock_irqrestore(&cct->task_lock, flags); | ||
| 745 | } | 746 | } |
| 746 | 747 | ||
| 747 | static int comp_task(void *__cct) | 748 | static void comp_task_park(unsigned int cpu) |
| 748 | { | 749 | { |
| 749 | struct ehca_cpu_comp_task *cct = __cct; | 750 | struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); |
| 750 | int cql_empty; | 751 | struct ehca_cpu_comp_task *target; |
| 751 | DECLARE_WAITQUEUE(wait, current); | 752 | struct task_struct *thread; |
| 752 | 753 | struct ehca_cq *cq, *tmp; | |
| 753 | set_current_state(TASK_INTERRUPTIBLE); | 754 | LIST_HEAD(list); |
| 754 | while (!kthread_should_stop()) { | ||
| 755 | add_wait_queue(&cct->wait_queue, &wait); | ||
| 756 | |||
| 757 | spin_lock_irq(&cct->task_lock); | ||
| 758 | cql_empty = list_empty(&cct->cq_list); | ||
| 759 | spin_unlock_irq(&cct->task_lock); | ||
| 760 | if (cql_empty) | ||
| 761 | schedule(); | ||
| 762 | else | ||
| 763 | __set_current_state(TASK_RUNNING); | ||
| 764 | |||
| 765 | remove_wait_queue(&cct->wait_queue, &wait); | ||
| 766 | 755 | ||
| 767 | spin_lock_irq(&cct->task_lock); | 756 | spin_lock_irq(&cct->task_lock); |
| 768 | cql_empty = list_empty(&cct->cq_list); | 757 | cct->cq_jobs = 0; |
| 769 | spin_unlock_irq(&cct->task_lock); | 758 | cct->active = 0; |
| 770 | if (!cql_empty) | 759 | list_splice_init(&cct->cq_list, &list); |
| 771 | run_comp_task(__cct); | 760 | spin_unlock_irq(&cct->task_lock); |
| 772 | 761 | ||
| 773 | set_current_state(TASK_INTERRUPTIBLE); | 762 | cpu = find_next_online_cpu(pool); |
| 763 | target = per_cpu_ptr(pool->cpu_comp_tasks, cpu); | ||
| 764 | thread = *per_cpu_ptr(pool->cpu_comp_threads, cpu); | ||
| 765 | spin_lock_irq(&target->task_lock); | ||
| 766 | list_for_each_entry_safe(cq, tmp, &list, entry) { | ||
| 767 | list_del(&cq->entry); | ||
| 768 | __queue_comp_task(cq, target, thread); | ||
| 774 | } | 769 | } |
| 775 | __set_current_state(TASK_RUNNING); | 770 | spin_unlock_irq(&target->task_lock); |
| 776 | |||
| 777 | return 0; | ||
| 778 | } | ||
| 779 | |||
| 780 | static struct task_struct *create_comp_task(struct ehca_comp_pool *pool, | ||
| 781 | int cpu) | ||
| 782 | { | ||
| 783 | struct ehca_cpu_comp_task *cct; | ||
| 784 | |||
| 785 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); | ||
| 786 | spin_lock_init(&cct->task_lock); | ||
| 787 | INIT_LIST_HEAD(&cct->cq_list); | ||
| 788 | init_waitqueue_head(&cct->wait_queue); | ||
| 789 | cct->task = kthread_create_on_node(comp_task, cct, cpu_to_node(cpu), | ||
| 790 | "ehca_comp/%d", cpu); | ||
| 791 | |||
| 792 | return cct->task; | ||
| 793 | } | 771 | } |
| 794 | 772 | ||
| 795 | static void destroy_comp_task(struct ehca_comp_pool *pool, | 773 | static void comp_task_stop(unsigned int cpu, bool online) |
| 796 | int cpu) | ||
| 797 | { | 774 | { |
| 798 | struct ehca_cpu_comp_task *cct; | 775 | struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); |
| 799 | struct task_struct *task; | ||
| 800 | unsigned long flags_cct; | ||
| 801 | |||
| 802 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); | ||
| 803 | |||
| 804 | spin_lock_irqsave(&cct->task_lock, flags_cct); | ||
| 805 | 776 | ||
| 806 | task = cct->task; | 777 | spin_lock_irq(&cct->task_lock); |
| 807 | cct->task = NULL; | ||
| 808 | cct->cq_jobs = 0; | 778 | cct->cq_jobs = 0; |
| 809 | 779 | cct->active = 0; | |
| 810 | spin_unlock_irqrestore(&cct->task_lock, flags_cct); | 780 | WARN_ON(!list_empty(&cct->cq_list)); |
| 811 | 781 | spin_unlock_irq(&cct->task_lock); | |
| 812 | if (task) | ||
| 813 | kthread_stop(task); | ||
| 814 | } | 782 | } |
| 815 | 783 | ||
| 816 | static void __cpuinit take_over_work(struct ehca_comp_pool *pool, int cpu) | 784 | static int comp_task_should_run(unsigned int cpu) |
| 817 | { | 785 | { |
| 818 | struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); | 786 | struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); |
| 819 | LIST_HEAD(list); | ||
| 820 | struct ehca_cq *cq; | ||
| 821 | unsigned long flags_cct; | ||
| 822 | |||
| 823 | spin_lock_irqsave(&cct->task_lock, flags_cct); | ||
| 824 | |||
| 825 | list_splice_init(&cct->cq_list, &list); | ||
| 826 | |||
| 827 | while (!list_empty(&list)) { | ||
| 828 | cq = list_entry(cct->cq_list.next, struct ehca_cq, entry); | ||
| 829 | |||
| 830 | list_del(&cq->entry); | ||
| 831 | __queue_comp_task(cq, this_cpu_ptr(pool->cpu_comp_tasks)); | ||
| 832 | } | ||
| 833 | |||
| 834 | spin_unlock_irqrestore(&cct->task_lock, flags_cct); | ||
| 835 | 787 | ||
| 788 | return cct->cq_jobs; | ||
| 836 | } | 789 | } |
| 837 | 790 | ||
| 838 | static int __cpuinit comp_pool_callback(struct notifier_block *nfb, | 791 | static void comp_task(unsigned int cpu) |
| 839 | unsigned long action, | ||
| 840 | void *hcpu) | ||
| 841 | { | 792 | { |
| 842 | unsigned int cpu = (unsigned long)hcpu; | 793 | struct ehca_cpu_comp_task *cct = this_cpu_ptr(pool->cpu_comp_tasks); |
| 843 | struct ehca_cpu_comp_task *cct; | 794 | int cql_empty; |
| 844 | 795 | ||
| 845 | switch (action) { | 796 | spin_lock_irq(&cct->task_lock); |
| 846 | case CPU_UP_PREPARE: | 797 | cql_empty = list_empty(&cct->cq_list); |
| 847 | case CPU_UP_PREPARE_FROZEN: | 798 | if (!cql_empty) { |
| 848 | ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu); | 799 | __set_current_state(TASK_RUNNING); |
| 849 | if (!create_comp_task(pool, cpu)) { | 800 | run_comp_task(cct); |
| 850 | ehca_gen_err("Can't create comp_task for cpu: %x", cpu); | ||
| 851 | return notifier_from_errno(-ENOMEM); | ||
| 852 | } | ||
| 853 | break; | ||
| 854 | case CPU_UP_CANCELED: | ||
| 855 | case CPU_UP_CANCELED_FROZEN: | ||
| 856 | ehca_gen_dbg("CPU: %x (CPU_CANCELED)", cpu); | ||
| 857 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); | ||
| 858 | kthread_bind(cct->task, cpumask_any(cpu_online_mask)); | ||
| 859 | destroy_comp_task(pool, cpu); | ||
| 860 | break; | ||
| 861 | case CPU_ONLINE: | ||
| 862 | case CPU_ONLINE_FROZEN: | ||
| 863 | ehca_gen_dbg("CPU: %x (CPU_ONLINE)", cpu); | ||
| 864 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); | ||
| 865 | kthread_bind(cct->task, cpu); | ||
| 866 | wake_up_process(cct->task); | ||
| 867 | break; | ||
| 868 | case CPU_DOWN_PREPARE: | ||
| 869 | case CPU_DOWN_PREPARE_FROZEN: | ||
| 870 | ehca_gen_dbg("CPU: %x (CPU_DOWN_PREPARE)", cpu); | ||
| 871 | break; | ||
| 872 | case CPU_DOWN_FAILED: | ||
| 873 | case CPU_DOWN_FAILED_FROZEN: | ||
| 874 | ehca_gen_dbg("CPU: %x (CPU_DOWN_FAILED)", cpu); | ||
| 875 | break; | ||
| 876 | case CPU_DEAD: | ||
| 877 | case CPU_DEAD_FROZEN: | ||
| 878 | ehca_gen_dbg("CPU: %x (CPU_DEAD)", cpu); | ||
| 879 | destroy_comp_task(pool, cpu); | ||
| 880 | take_over_work(pool, cpu); | ||
| 881 | break; | ||
| 882 | } | 801 | } |
| 883 | 802 | spin_unlock_irq(&cct->task_lock); | |
| 884 | return NOTIFY_OK; | ||
| 885 | } | 803 | } |
| 886 | 804 | ||
| 887 | static struct notifier_block comp_pool_callback_nb __cpuinitdata = { | 805 | static struct smp_hotplug_thread comp_pool_threads = { |
| 888 | .notifier_call = comp_pool_callback, | 806 | .thread_should_run = comp_task_should_run, |
| 889 | .priority = 0, | 807 | .thread_fn = comp_task, |
| 808 | .thread_comm = "ehca_comp/%u", | ||
| 809 | .cleanup = comp_task_stop, | ||
| 810 | .park = comp_task_park, | ||
| 890 | }; | 811 | }; |
| 891 | 812 | ||
| 892 | int ehca_create_comp_pool(void) | 813 | int ehca_create_comp_pool(void) |
| 893 | { | 814 | { |
| 894 | int cpu; | 815 | int cpu, ret = -ENOMEM; |
| 895 | struct task_struct *task; | ||
| 896 | 816 | ||
| 897 | if (!ehca_scaling_code) | 817 | if (!ehca_scaling_code) |
| 898 | return 0; | 818 | return 0; |
| @@ -905,38 +825,46 @@ int ehca_create_comp_pool(void) | |||
| 905 | pool->last_cpu = cpumask_any(cpu_online_mask); | 825 | pool->last_cpu = cpumask_any(cpu_online_mask); |
| 906 | 826 | ||
| 907 | pool->cpu_comp_tasks = alloc_percpu(struct ehca_cpu_comp_task); | 827 | pool->cpu_comp_tasks = alloc_percpu(struct ehca_cpu_comp_task); |
| 908 | if (pool->cpu_comp_tasks == NULL) { | 828 | if (!pool->cpu_comp_tasks) |
| 909 | kfree(pool); | 829 | goto out_pool; |
| 910 | return -EINVAL; | ||
| 911 | } | ||
| 912 | 830 | ||
| 913 | for_each_online_cpu(cpu) { | 831 | pool->cpu_comp_threads = alloc_percpu(struct task_struct *); |
| 914 | task = create_comp_task(pool, cpu); | 832 | if (!pool->cpu_comp_threads) |
| 915 | if (task) { | 833 | goto out_tasks; |
| 916 | kthread_bind(task, cpu); | 834 | |
| 917 | wake_up_process(task); | 835 | for_each_present_cpu(cpu) { |
| 918 | } | 836 | struct ehca_cpu_comp_task *cct; |
| 837 | |||
| 838 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); | ||
| 839 | spin_lock_init(&cct->task_lock); | ||
| 840 | INIT_LIST_HEAD(&cct->cq_list); | ||
| 919 | } | 841 | } |
| 920 | 842 | ||
| 921 | register_hotcpu_notifier(&comp_pool_callback_nb); | 843 | comp_pool_threads.store = pool->cpu_comp_threads; |
| 844 | ret = smpboot_register_percpu_thread(&comp_pool_threads); | ||
| 845 | if (ret) | ||
| 846 | goto out_threads; | ||
| 922 | 847 | ||
| 923 | printk(KERN_INFO "eHCA scaling code enabled\n"); | 848 | pr_info("eHCA scaling code enabled\n"); |
| 849 | return ret; | ||
| 924 | 850 | ||
| 925 | return 0; | 851 | out_threads: |
| 852 | free_percpu(pool->cpu_comp_threads); | ||
| 853 | out_tasks: | ||
| 854 | free_percpu(pool->cpu_comp_tasks); | ||
| 855 | out_pool: | ||
| 856 | kfree(pool); | ||
| 857 | return ret; | ||
| 926 | } | 858 | } |
| 927 | 859 | ||
| 928 | void ehca_destroy_comp_pool(void) | 860 | void ehca_destroy_comp_pool(void) |
| 929 | { | 861 | { |
| 930 | int i; | ||
| 931 | |||
| 932 | if (!ehca_scaling_code) | 862 | if (!ehca_scaling_code) |
| 933 | return; | 863 | return; |
| 934 | 864 | ||
| 935 | unregister_hotcpu_notifier(&comp_pool_callback_nb); | 865 | smpboot_unregister_percpu_thread(&comp_pool_threads); |
| 936 | |||
| 937 | for_each_online_cpu(i) | ||
| 938 | destroy_comp_task(pool, i); | ||
| 939 | 866 | ||
| 867 | free_percpu(pool->cpu_comp_threads); | ||
| 940 | free_percpu(pool->cpu_comp_tasks); | 868 | free_percpu(pool->cpu_comp_tasks); |
| 941 | kfree(pool); | 869 | kfree(pool); |
| 942 | } | 870 | } |
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.h b/drivers/infiniband/hw/ehca/ehca_irq.h index 3346cb06cea6..5370199f08c7 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.h +++ b/drivers/infiniband/hw/ehca/ehca_irq.h | |||
| @@ -58,15 +58,15 @@ void ehca_tasklet_eq(unsigned long data); | |||
| 58 | void ehca_process_eq(struct ehca_shca *shca, int is_irq); | 58 | void ehca_process_eq(struct ehca_shca *shca, int is_irq); |
| 59 | 59 | ||
| 60 | struct ehca_cpu_comp_task { | 60 | struct ehca_cpu_comp_task { |
| 61 | wait_queue_head_t wait_queue; | ||
| 62 | struct list_head cq_list; | 61 | struct list_head cq_list; |
| 63 | struct task_struct *task; | ||
| 64 | spinlock_t task_lock; | 62 | spinlock_t task_lock; |
| 65 | int cq_jobs; | 63 | int cq_jobs; |
| 64 | int active; | ||
| 66 | }; | 65 | }; |
| 67 | 66 | ||
| 68 | struct ehca_comp_pool { | 67 | struct ehca_comp_pool { |
| 69 | struct ehca_cpu_comp_task *cpu_comp_tasks; | 68 | struct ehca_cpu_comp_task __percpu *cpu_comp_tasks; |
| 69 | struct task_struct * __percpu *cpu_comp_threads; | ||
| 70 | int last_cpu; | 70 | int last_cpu; |
| 71 | spinlock_t last_cpu_lock; | 71 | spinlock_t last_cpu_lock; |
| 72 | }; | 72 | }; |
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index cb5b7f7d4d38..b29a4246ef41 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | |||
| @@ -2219,7 +2219,6 @@ static bool ocrdma_poll_success_scqe(struct ocrdma_qp *qp, | |||
| 2219 | u32 wqe_idx; | 2219 | u32 wqe_idx; |
| 2220 | 2220 | ||
| 2221 | if (!qp->wqe_wr_id_tbl[tail].signaled) { | 2221 | if (!qp->wqe_wr_id_tbl[tail].signaled) { |
| 2222 | expand = true; /* CQE cannot be consumed yet */ | ||
| 2223 | *polled = false; /* WC cannot be consumed yet */ | 2222 | *polled = false; /* WC cannot be consumed yet */ |
| 2224 | } else { | 2223 | } else { |
| 2225 | ibwc->status = IB_WC_SUCCESS; | 2224 | ibwc->status = IB_WC_SUCCESS; |
| @@ -2227,10 +2226,11 @@ static bool ocrdma_poll_success_scqe(struct ocrdma_qp *qp, | |||
| 2227 | ibwc->qp = &qp->ibqp; | 2226 | ibwc->qp = &qp->ibqp; |
| 2228 | ocrdma_update_wc(qp, ibwc, tail); | 2227 | ocrdma_update_wc(qp, ibwc, tail); |
| 2229 | *polled = true; | 2228 | *polled = true; |
| 2230 | wqe_idx = le32_to_cpu(cqe->wq.wqeidx) & OCRDMA_CQE_WQEIDX_MASK; | ||
| 2231 | if (tail != wqe_idx) | ||
| 2232 | expand = true; /* Coalesced CQE can't be consumed yet */ | ||
| 2233 | } | 2229 | } |
| 2230 | wqe_idx = le32_to_cpu(cqe->wq.wqeidx) & OCRDMA_CQE_WQEIDX_MASK; | ||
| 2231 | if (tail != wqe_idx) | ||
| 2232 | expand = true; /* Coalesced CQE can't be consumed yet */ | ||
| 2233 | |||
| 2234 | ocrdma_hwq_inc_tail(&qp->sq); | 2234 | ocrdma_hwq_inc_tail(&qp->sq); |
| 2235 | return expand; | 2235 | return expand; |
| 2236 | } | 2236 | } |
diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c index 19f1e6c45fb6..ccb119143d20 100644 --- a/drivers/infiniband/hw/qib/qib_mad.c +++ b/drivers/infiniband/hw/qib/qib_mad.c | |||
| @@ -471,9 +471,10 @@ static int subn_get_portinfo(struct ib_smp *smp, struct ib_device *ibdev, | |||
| 471 | if (port_num != port) { | 471 | if (port_num != port) { |
| 472 | ibp = to_iport(ibdev, port_num); | 472 | ibp = to_iport(ibdev, port_num); |
| 473 | ret = check_mkey(ibp, smp, 0); | 473 | ret = check_mkey(ibp, smp, 0); |
| 474 | if (ret) | 474 | if (ret) { |
| 475 | ret = IB_MAD_RESULT_FAILURE; | 475 | ret = IB_MAD_RESULT_FAILURE; |
| 476 | goto bail; | 476 | goto bail; |
| 477 | } | ||
| 477 | } | 478 | } |
| 478 | } | 479 | } |
| 479 | 480 | ||
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index ca43901ed861..0af216d21f87 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h | |||
| @@ -262,7 +262,10 @@ struct ipoib_ethtool_st { | |||
| 262 | u16 max_coalesced_frames; | 262 | u16 max_coalesced_frames; |
| 263 | }; | 263 | }; |
| 264 | 264 | ||
| 265 | struct ipoib_neigh_table; | ||
| 266 | |||
| 265 | struct ipoib_neigh_hash { | 267 | struct ipoib_neigh_hash { |
| 268 | struct ipoib_neigh_table *ntbl; | ||
| 266 | struct ipoib_neigh __rcu **buckets; | 269 | struct ipoib_neigh __rcu **buckets; |
| 267 | struct rcu_head rcu; | 270 | struct rcu_head rcu; |
| 268 | u32 mask; | 271 | u32 mask; |
| @@ -271,9 +274,9 @@ struct ipoib_neigh_hash { | |||
| 271 | 274 | ||
| 272 | struct ipoib_neigh_table { | 275 | struct ipoib_neigh_table { |
| 273 | struct ipoib_neigh_hash __rcu *htbl; | 276 | struct ipoib_neigh_hash __rcu *htbl; |
| 274 | rwlock_t rwlock; | ||
| 275 | atomic_t entries; | 277 | atomic_t entries; |
| 276 | struct completion flushed; | 278 | struct completion flushed; |
| 279 | struct completion deleted; | ||
| 277 | }; | 280 | }; |
| 278 | 281 | ||
| 279 | /* | 282 | /* |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 3e2085a3ee47..1e19b5ae7c47 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c | |||
| @@ -546,15 +546,15 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr, | |||
| 546 | struct ipoib_neigh *neigh; | 546 | struct ipoib_neigh *neigh; |
| 547 | unsigned long flags; | 547 | unsigned long flags; |
| 548 | 548 | ||
| 549 | spin_lock_irqsave(&priv->lock, flags); | ||
| 549 | neigh = ipoib_neigh_alloc(daddr, dev); | 550 | neigh = ipoib_neigh_alloc(daddr, dev); |
| 550 | if (!neigh) { | 551 | if (!neigh) { |
| 552 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 551 | ++dev->stats.tx_dropped; | 553 | ++dev->stats.tx_dropped; |
| 552 | dev_kfree_skb_any(skb); | 554 | dev_kfree_skb_any(skb); |
| 553 | return; | 555 | return; |
| 554 | } | 556 | } |
| 555 | 557 | ||
| 556 | spin_lock_irqsave(&priv->lock, flags); | ||
| 557 | |||
| 558 | path = __path_find(dev, daddr + 4); | 558 | path = __path_find(dev, daddr + 4); |
| 559 | if (!path) { | 559 | if (!path) { |
| 560 | path = path_rec_create(dev, daddr + 4); | 560 | path = path_rec_create(dev, daddr + 4); |
| @@ -863,10 +863,10 @@ static void __ipoib_reap_neigh(struct ipoib_dev_priv *priv) | |||
| 863 | if (test_bit(IPOIB_STOP_NEIGH_GC, &priv->flags)) | 863 | if (test_bit(IPOIB_STOP_NEIGH_GC, &priv->flags)) |
| 864 | return; | 864 | return; |
| 865 | 865 | ||
| 866 | write_lock_bh(&ntbl->rwlock); | 866 | spin_lock_irqsave(&priv->lock, flags); |
| 867 | 867 | ||
| 868 | htbl = rcu_dereference_protected(ntbl->htbl, | 868 | htbl = rcu_dereference_protected(ntbl->htbl, |
| 869 | lockdep_is_held(&ntbl->rwlock)); | 869 | lockdep_is_held(&priv->lock)); |
| 870 | 870 | ||
| 871 | if (!htbl) | 871 | if (!htbl) |
| 872 | goto out_unlock; | 872 | goto out_unlock; |
| @@ -883,16 +883,14 @@ static void __ipoib_reap_neigh(struct ipoib_dev_priv *priv) | |||
| 883 | struct ipoib_neigh __rcu **np = &htbl->buckets[i]; | 883 | struct ipoib_neigh __rcu **np = &htbl->buckets[i]; |
| 884 | 884 | ||
| 885 | while ((neigh = rcu_dereference_protected(*np, | 885 | while ((neigh = rcu_dereference_protected(*np, |
| 886 | lockdep_is_held(&ntbl->rwlock))) != NULL) { | 886 | lockdep_is_held(&priv->lock))) != NULL) { |
| 887 | /* was the neigh idle for two GC periods */ | 887 | /* was the neigh idle for two GC periods */ |
| 888 | if (time_after(neigh_obsolete, neigh->alive)) { | 888 | if (time_after(neigh_obsolete, neigh->alive)) { |
| 889 | rcu_assign_pointer(*np, | 889 | rcu_assign_pointer(*np, |
| 890 | rcu_dereference_protected(neigh->hnext, | 890 | rcu_dereference_protected(neigh->hnext, |
| 891 | lockdep_is_held(&ntbl->rwlock))); | 891 | lockdep_is_held(&priv->lock))); |
| 892 | /* remove from path/mc list */ | 892 | /* remove from path/mc list */ |
| 893 | spin_lock_irqsave(&priv->lock, flags); | ||
| 894 | list_del(&neigh->list); | 893 | list_del(&neigh->list); |
| 895 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 896 | call_rcu(&neigh->rcu, ipoib_neigh_reclaim); | 894 | call_rcu(&neigh->rcu, ipoib_neigh_reclaim); |
| 897 | } else { | 895 | } else { |
| 898 | np = &neigh->hnext; | 896 | np = &neigh->hnext; |
| @@ -902,7 +900,7 @@ static void __ipoib_reap_neigh(struct ipoib_dev_priv *priv) | |||
| 902 | } | 900 | } |
| 903 | 901 | ||
| 904 | out_unlock: | 902 | out_unlock: |
| 905 | write_unlock_bh(&ntbl->rwlock); | 903 | spin_unlock_irqrestore(&priv->lock, flags); |
| 906 | } | 904 | } |
| 907 | 905 | ||
| 908 | static void ipoib_reap_neigh(struct work_struct *work) | 906 | static void ipoib_reap_neigh(struct work_struct *work) |
| @@ -947,10 +945,8 @@ struct ipoib_neigh *ipoib_neigh_alloc(u8 *daddr, | |||
| 947 | struct ipoib_neigh *neigh; | 945 | struct ipoib_neigh *neigh; |
| 948 | u32 hash_val; | 946 | u32 hash_val; |
| 949 | 947 | ||
| 950 | write_lock_bh(&ntbl->rwlock); | ||
| 951 | |||
| 952 | htbl = rcu_dereference_protected(ntbl->htbl, | 948 | htbl = rcu_dereference_protected(ntbl->htbl, |
| 953 | lockdep_is_held(&ntbl->rwlock)); | 949 | lockdep_is_held(&priv->lock)); |
| 954 | if (!htbl) { | 950 | if (!htbl) { |
| 955 | neigh = NULL; | 951 | neigh = NULL; |
| 956 | goto out_unlock; | 952 | goto out_unlock; |
| @@ -961,10 +957,10 @@ struct ipoib_neigh *ipoib_neigh_alloc(u8 *daddr, | |||
| 961 | */ | 957 | */ |
| 962 | hash_val = ipoib_addr_hash(htbl, daddr); | 958 | hash_val = ipoib_addr_hash(htbl, daddr); |
| 963 | for (neigh = rcu_dereference_protected(htbl->buckets[hash_val], | 959 | for (neigh = rcu_dereference_protected(htbl->buckets[hash_val], |
| 964 | lockdep_is_held(&ntbl->rwlock)); | 960 | lockdep_is_held(&priv->lock)); |
| 965 | neigh != NULL; | 961 | neigh != NULL; |
| 966 | neigh = rcu_dereference_protected(neigh->hnext, | 962 | neigh = rcu_dereference_protected(neigh->hnext, |
| 967 | lockdep_is_held(&ntbl->rwlock))) { | 963 | lockdep_is_held(&priv->lock))) { |
| 968 | if (memcmp(daddr, neigh->daddr, INFINIBAND_ALEN) == 0) { | 964 | if (memcmp(daddr, neigh->daddr, INFINIBAND_ALEN) == 0) { |
| 969 | /* found, take one ref on behalf of the caller */ | 965 | /* found, take one ref on behalf of the caller */ |
| 970 | if (!atomic_inc_not_zero(&neigh->refcnt)) { | 966 | if (!atomic_inc_not_zero(&neigh->refcnt)) { |
| @@ -987,12 +983,11 @@ struct ipoib_neigh *ipoib_neigh_alloc(u8 *daddr, | |||
| 987 | /* put in hash */ | 983 | /* put in hash */ |
| 988 | rcu_assign_pointer(neigh->hnext, | 984 | rcu_assign_pointer(neigh->hnext, |
| 989 | rcu_dereference_protected(htbl->buckets[hash_val], | 985 | rcu_dereference_protected(htbl->buckets[hash_val], |
| 990 | lockdep_is_held(&ntbl->rwlock))); | 986 | lockdep_is_held(&priv->lock))); |
| 991 | rcu_assign_pointer(htbl->buckets[hash_val], neigh); | 987 | rcu_assign_pointer(htbl->buckets[hash_val], neigh); |
| 992 | atomic_inc(&ntbl->entries); | 988 | atomic_inc(&ntbl->entries); |
| 993 | 989 | ||
| 994 | out_unlock: | 990 | out_unlock: |
| 995 | write_unlock_bh(&ntbl->rwlock); | ||
| 996 | 991 | ||
| 997 | return neigh; | 992 | return neigh; |
| 998 | } | 993 | } |
| @@ -1040,35 +1035,29 @@ void ipoib_neigh_free(struct ipoib_neigh *neigh) | |||
| 1040 | struct ipoib_neigh *n; | 1035 | struct ipoib_neigh *n; |
| 1041 | u32 hash_val; | 1036 | u32 hash_val; |
| 1042 | 1037 | ||
| 1043 | write_lock_bh(&ntbl->rwlock); | ||
| 1044 | |||
| 1045 | htbl = rcu_dereference_protected(ntbl->htbl, | 1038 | htbl = rcu_dereference_protected(ntbl->htbl, |
| 1046 | lockdep_is_held(&ntbl->rwlock)); | 1039 | lockdep_is_held(&priv->lock)); |
| 1047 | if (!htbl) | 1040 | if (!htbl) |
| 1048 | goto out_unlock; | 1041 | return; |
| 1049 | 1042 | ||
| 1050 | hash_val = ipoib_addr_hash(htbl, neigh->daddr); | 1043 | hash_val = ipoib_addr_hash(htbl, neigh->daddr); |
| 1051 | np = &htbl->buckets[hash_val]; | 1044 | np = &htbl->buckets[hash_val]; |
| 1052 | for (n = rcu_dereference_protected(*np, | 1045 | for (n = rcu_dereference_protected(*np, |
| 1053 | lockdep_is_held(&ntbl->rwlock)); | 1046 | lockdep_is_held(&priv->lock)); |
| 1054 | n != NULL; | 1047 | n != NULL; |
| 1055 | n = rcu_dereference_protected(*np, | 1048 | n = rcu_dereference_protected(*np, |
| 1056 | lockdep_is_held(&ntbl->rwlock))) { | 1049 | lockdep_is_held(&priv->lock))) { |
| 1057 | if (n == neigh) { | 1050 | if (n == neigh) { |
| 1058 | /* found */ | 1051 | /* found */ |
| 1059 | rcu_assign_pointer(*np, | 1052 | rcu_assign_pointer(*np, |
| 1060 | rcu_dereference_protected(neigh->hnext, | 1053 | rcu_dereference_protected(neigh->hnext, |
| 1061 | lockdep_is_held(&ntbl->rwlock))); | 1054 | lockdep_is_held(&priv->lock))); |
| 1062 | call_rcu(&neigh->rcu, ipoib_neigh_reclaim); | 1055 | call_rcu(&neigh->rcu, ipoib_neigh_reclaim); |
| 1063 | goto out_unlock; | 1056 | return; |
| 1064 | } else { | 1057 | } else { |
| 1065 | np = &n->hnext; | 1058 | np = &n->hnext; |
| 1066 | } | 1059 | } |
| 1067 | } | 1060 | } |
| 1068 | |||
| 1069 | out_unlock: | ||
| 1070 | write_unlock_bh(&ntbl->rwlock); | ||
| 1071 | |||
| 1072 | } | 1061 | } |
| 1073 | 1062 | ||
| 1074 | static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv) | 1063 | static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv) |
| @@ -1080,7 +1069,6 @@ static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv) | |||
| 1080 | 1069 | ||
| 1081 | clear_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags); | 1070 | clear_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags); |
| 1082 | ntbl->htbl = NULL; | 1071 | ntbl->htbl = NULL; |
| 1083 | rwlock_init(&ntbl->rwlock); | ||
| 1084 | htbl = kzalloc(sizeof(*htbl), GFP_KERNEL); | 1072 | htbl = kzalloc(sizeof(*htbl), GFP_KERNEL); |
| 1085 | if (!htbl) | 1073 | if (!htbl) |
| 1086 | return -ENOMEM; | 1074 | return -ENOMEM; |
| @@ -1095,6 +1083,7 @@ static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv) | |||
| 1095 | htbl->mask = (size - 1); | 1083 | htbl->mask = (size - 1); |
| 1096 | htbl->buckets = buckets; | 1084 | htbl->buckets = buckets; |
| 1097 | ntbl->htbl = htbl; | 1085 | ntbl->htbl = htbl; |
| 1086 | htbl->ntbl = ntbl; | ||
| 1098 | atomic_set(&ntbl->entries, 0); | 1087 | atomic_set(&ntbl->entries, 0); |
| 1099 | 1088 | ||
| 1100 | /* start garbage collection */ | 1089 | /* start garbage collection */ |
| @@ -1111,9 +1100,11 @@ static void neigh_hash_free_rcu(struct rcu_head *head) | |||
| 1111 | struct ipoib_neigh_hash, | 1100 | struct ipoib_neigh_hash, |
| 1112 | rcu); | 1101 | rcu); |
| 1113 | struct ipoib_neigh __rcu **buckets = htbl->buckets; | 1102 | struct ipoib_neigh __rcu **buckets = htbl->buckets; |
| 1103 | struct ipoib_neigh_table *ntbl = htbl->ntbl; | ||
| 1114 | 1104 | ||
| 1115 | kfree(buckets); | 1105 | kfree(buckets); |
| 1116 | kfree(htbl); | 1106 | kfree(htbl); |
| 1107 | complete(&ntbl->deleted); | ||
| 1117 | } | 1108 | } |
| 1118 | 1109 | ||
| 1119 | void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid) | 1110 | void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid) |
| @@ -1125,10 +1116,10 @@ void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid) | |||
| 1125 | int i; | 1116 | int i; |
| 1126 | 1117 | ||
| 1127 | /* remove all neigh connected to a given path or mcast */ | 1118 | /* remove all neigh connected to a given path or mcast */ |
| 1128 | write_lock_bh(&ntbl->rwlock); | 1119 | spin_lock_irqsave(&priv->lock, flags); |
| 1129 | 1120 | ||
| 1130 | htbl = rcu_dereference_protected(ntbl->htbl, | 1121 | htbl = rcu_dereference_protected(ntbl->htbl, |
| 1131 | lockdep_is_held(&ntbl->rwlock)); | 1122 | lockdep_is_held(&priv->lock)); |
| 1132 | 1123 | ||
| 1133 | if (!htbl) | 1124 | if (!htbl) |
| 1134 | goto out_unlock; | 1125 | goto out_unlock; |
| @@ -1138,16 +1129,14 @@ void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid) | |||
| 1138 | struct ipoib_neigh __rcu **np = &htbl->buckets[i]; | 1129 | struct ipoib_neigh __rcu **np = &htbl->buckets[i]; |
| 1139 | 1130 | ||
| 1140 | while ((neigh = rcu_dereference_protected(*np, | 1131 | while ((neigh = rcu_dereference_protected(*np, |
| 1141 | lockdep_is_held(&ntbl->rwlock))) != NULL) { | 1132 | lockdep_is_held(&priv->lock))) != NULL) { |
| 1142 | /* delete neighs belong to this parent */ | 1133 | /* delete neighs belong to this parent */ |
| 1143 | if (!memcmp(gid, neigh->daddr + 4, sizeof (union ib_gid))) { | 1134 | if (!memcmp(gid, neigh->daddr + 4, sizeof (union ib_gid))) { |
| 1144 | rcu_assign_pointer(*np, | 1135 | rcu_assign_pointer(*np, |
| 1145 | rcu_dereference_protected(neigh->hnext, | 1136 | rcu_dereference_protected(neigh->hnext, |
| 1146 | lockdep_is_held(&ntbl->rwlock))); | 1137 | lockdep_is_held(&priv->lock))); |
| 1147 | /* remove from parent list */ | 1138 | /* remove from parent list */ |
| 1148 | spin_lock_irqsave(&priv->lock, flags); | ||
| 1149 | list_del(&neigh->list); | 1139 | list_del(&neigh->list); |
| 1150 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 1151 | call_rcu(&neigh->rcu, ipoib_neigh_reclaim); | 1140 | call_rcu(&neigh->rcu, ipoib_neigh_reclaim); |
| 1152 | } else { | 1141 | } else { |
| 1153 | np = &neigh->hnext; | 1142 | np = &neigh->hnext; |
| @@ -1156,7 +1145,7 @@ void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid) | |||
| 1156 | } | 1145 | } |
| 1157 | } | 1146 | } |
| 1158 | out_unlock: | 1147 | out_unlock: |
| 1159 | write_unlock_bh(&ntbl->rwlock); | 1148 | spin_unlock_irqrestore(&priv->lock, flags); |
| 1160 | } | 1149 | } |
| 1161 | 1150 | ||
| 1162 | static void ipoib_flush_neighs(struct ipoib_dev_priv *priv) | 1151 | static void ipoib_flush_neighs(struct ipoib_dev_priv *priv) |
| @@ -1164,37 +1153,44 @@ static void ipoib_flush_neighs(struct ipoib_dev_priv *priv) | |||
| 1164 | struct ipoib_neigh_table *ntbl = &priv->ntbl; | 1153 | struct ipoib_neigh_table *ntbl = &priv->ntbl; |
| 1165 | struct ipoib_neigh_hash *htbl; | 1154 | struct ipoib_neigh_hash *htbl; |
| 1166 | unsigned long flags; | 1155 | unsigned long flags; |
| 1167 | int i; | 1156 | int i, wait_flushed = 0; |
| 1168 | 1157 | ||
| 1169 | write_lock_bh(&ntbl->rwlock); | 1158 | init_completion(&priv->ntbl.flushed); |
| 1159 | |||
| 1160 | spin_lock_irqsave(&priv->lock, flags); | ||
| 1170 | 1161 | ||
| 1171 | htbl = rcu_dereference_protected(ntbl->htbl, | 1162 | htbl = rcu_dereference_protected(ntbl->htbl, |
| 1172 | lockdep_is_held(&ntbl->rwlock)); | 1163 | lockdep_is_held(&priv->lock)); |
| 1173 | if (!htbl) | 1164 | if (!htbl) |
| 1174 | goto out_unlock; | 1165 | goto out_unlock; |
| 1175 | 1166 | ||
| 1167 | wait_flushed = atomic_read(&priv->ntbl.entries); | ||
| 1168 | if (!wait_flushed) | ||
| 1169 | goto free_htbl; | ||
| 1170 | |||
| 1176 | for (i = 0; i < htbl->size; i++) { | 1171 | for (i = 0; i < htbl->size; i++) { |
| 1177 | struct ipoib_neigh *neigh; | 1172 | struct ipoib_neigh *neigh; |
| 1178 | struct ipoib_neigh __rcu **np = &htbl->buckets[i]; | 1173 | struct ipoib_neigh __rcu **np = &htbl->buckets[i]; |
| 1179 | 1174 | ||
| 1180 | while ((neigh = rcu_dereference_protected(*np, | 1175 | while ((neigh = rcu_dereference_protected(*np, |
| 1181 | lockdep_is_held(&ntbl->rwlock))) != NULL) { | 1176 | lockdep_is_held(&priv->lock))) != NULL) { |
| 1182 | rcu_assign_pointer(*np, | 1177 | rcu_assign_pointer(*np, |
| 1183 | rcu_dereference_protected(neigh->hnext, | 1178 | rcu_dereference_protected(neigh->hnext, |
| 1184 | lockdep_is_held(&ntbl->rwlock))); | 1179 | lockdep_is_held(&priv->lock))); |
| 1185 | /* remove from path/mc list */ | 1180 | /* remove from path/mc list */ |
| 1186 | spin_lock_irqsave(&priv->lock, flags); | ||
| 1187 | list_del(&neigh->list); | 1181 | list_del(&neigh->list); |
| 1188 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 1189 | call_rcu(&neigh->rcu, ipoib_neigh_reclaim); | 1182 | call_rcu(&neigh->rcu, ipoib_neigh_reclaim); |
| 1190 | } | 1183 | } |
| 1191 | } | 1184 | } |
| 1192 | 1185 | ||
| 1186 | free_htbl: | ||
| 1193 | rcu_assign_pointer(ntbl->htbl, NULL); | 1187 | rcu_assign_pointer(ntbl->htbl, NULL); |
| 1194 | call_rcu(&htbl->rcu, neigh_hash_free_rcu); | 1188 | call_rcu(&htbl->rcu, neigh_hash_free_rcu); |
| 1195 | 1189 | ||
| 1196 | out_unlock: | 1190 | out_unlock: |
| 1197 | write_unlock_bh(&ntbl->rwlock); | 1191 | spin_unlock_irqrestore(&priv->lock, flags); |
| 1192 | if (wait_flushed) | ||
| 1193 | wait_for_completion(&priv->ntbl.flushed); | ||
| 1198 | } | 1194 | } |
| 1199 | 1195 | ||
| 1200 | static void ipoib_neigh_hash_uninit(struct net_device *dev) | 1196 | static void ipoib_neigh_hash_uninit(struct net_device *dev) |
| @@ -1203,7 +1199,7 @@ static void ipoib_neigh_hash_uninit(struct net_device *dev) | |||
| 1203 | int stopped; | 1199 | int stopped; |
| 1204 | 1200 | ||
| 1205 | ipoib_dbg(priv, "ipoib_neigh_hash_uninit\n"); | 1201 | ipoib_dbg(priv, "ipoib_neigh_hash_uninit\n"); |
| 1206 | init_completion(&priv->ntbl.flushed); | 1202 | init_completion(&priv->ntbl.deleted); |
| 1207 | set_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags); | 1203 | set_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags); |
| 1208 | 1204 | ||
| 1209 | /* Stop GC if called at init fail need to cancel work */ | 1205 | /* Stop GC if called at init fail need to cancel work */ |
| @@ -1211,10 +1207,9 @@ static void ipoib_neigh_hash_uninit(struct net_device *dev) | |||
| 1211 | if (!stopped) | 1207 | if (!stopped) |
| 1212 | cancel_delayed_work(&priv->neigh_reap_task); | 1208 | cancel_delayed_work(&priv->neigh_reap_task); |
| 1213 | 1209 | ||
| 1214 | if (atomic_read(&priv->ntbl.entries)) { | 1210 | ipoib_flush_neighs(priv); |
| 1215 | ipoib_flush_neighs(priv); | 1211 | |
| 1216 | wait_for_completion(&priv->ntbl.flushed); | 1212 | wait_for_completion(&priv->ntbl.deleted); |
| 1217 | } | ||
| 1218 | } | 1213 | } |
| 1219 | 1214 | ||
| 1220 | 1215 | ||
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 13f4aa7593c8..75367249f447 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c | |||
| @@ -707,9 +707,7 @@ out: | |||
| 707 | neigh = ipoib_neigh_get(dev, daddr); | 707 | neigh = ipoib_neigh_get(dev, daddr); |
| 708 | spin_lock_irqsave(&priv->lock, flags); | 708 | spin_lock_irqsave(&priv->lock, flags); |
| 709 | if (!neigh) { | 709 | if (!neigh) { |
| 710 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 711 | neigh = ipoib_neigh_alloc(daddr, dev); | 710 | neigh = ipoib_neigh_alloc(daddr, dev); |
| 712 | spin_lock_irqsave(&priv->lock, flags); | ||
| 713 | if (neigh) { | 711 | if (neigh) { |
| 714 | kref_get(&mcast->ah->ref); | 712 | kref_get(&mcast->ah->ref); |
| 715 | neigh->ah = mcast->ah; | 713 | neigh->ah = mcast->ah; |
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 6c58bfff01a3..118d0300f1fb 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
| @@ -54,16 +54,9 @@ struct evdev_client { | |||
| 54 | static struct evdev *evdev_table[EVDEV_MINORS]; | 54 | static struct evdev *evdev_table[EVDEV_MINORS]; |
| 55 | static DEFINE_MUTEX(evdev_table_mutex); | 55 | static DEFINE_MUTEX(evdev_table_mutex); |
| 56 | 56 | ||
| 57 | static void evdev_pass_event(struct evdev_client *client, | 57 | static void __pass_event(struct evdev_client *client, |
| 58 | struct input_event *event, | 58 | const struct input_event *event) |
| 59 | ktime_t mono, ktime_t real) | ||
| 60 | { | 59 | { |
| 61 | event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? | ||
| 62 | mono : real); | ||
| 63 | |||
| 64 | /* Interrupts are disabled, just acquire the lock. */ | ||
| 65 | spin_lock(&client->buffer_lock); | ||
| 66 | |||
| 67 | client->buffer[client->head++] = *event; | 60 | client->buffer[client->head++] = *event; |
| 68 | client->head &= client->bufsize - 1; | 61 | client->head &= client->bufsize - 1; |
| 69 | 62 | ||
| @@ -86,42 +79,74 @@ static void evdev_pass_event(struct evdev_client *client, | |||
| 86 | client->packet_head = client->head; | 79 | client->packet_head = client->head; |
| 87 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | 80 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
| 88 | } | 81 | } |
| 82 | } | ||
| 83 | |||
| 84 | static void evdev_pass_values(struct evdev_client *client, | ||
| 85 | const struct input_value *vals, unsigned int count, | ||
| 86 | ktime_t mono, ktime_t real) | ||
| 87 | { | ||
| 88 | struct evdev *evdev = client->evdev; | ||
| 89 | const struct input_value *v; | ||
| 90 | struct input_event event; | ||
| 91 | bool wakeup = false; | ||
| 92 | |||
| 93 | event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? | ||
| 94 | mono : real); | ||
| 95 | |||
| 96 | /* Interrupts are disabled, just acquire the lock. */ | ||
| 97 | spin_lock(&client->buffer_lock); | ||
| 98 | |||
| 99 | for (v = vals; v != vals + count; v++) { | ||
| 100 | event.type = v->type; | ||
| 101 | event.code = v->code; | ||
| 102 | event.value = v->value; | ||
| 103 | __pass_event(client, &event); | ||
| 104 | if (v->type == EV_SYN && v->code == SYN_REPORT) | ||
| 105 | wakeup = true; | ||
| 106 | } | ||
| 89 | 107 | ||
| 90 | spin_unlock(&client->buffer_lock); | 108 | spin_unlock(&client->buffer_lock); |
| 109 | |||
| 110 | if (wakeup) | ||
| 111 | wake_up_interruptible(&evdev->wait); | ||
| 91 | } | 112 | } |
| 92 | 113 | ||
| 93 | /* | 114 | /* |
| 94 | * Pass incoming event to all connected clients. | 115 | * Pass incoming events to all connected clients. |
| 95 | */ | 116 | */ |
| 96 | static void evdev_event(struct input_handle *handle, | 117 | static void evdev_events(struct input_handle *handle, |
| 97 | unsigned int type, unsigned int code, int value) | 118 | const struct input_value *vals, unsigned int count) |
| 98 | { | 119 | { |
| 99 | struct evdev *evdev = handle->private; | 120 | struct evdev *evdev = handle->private; |
| 100 | struct evdev_client *client; | 121 | struct evdev_client *client; |
| 101 | struct input_event event; | ||
| 102 | ktime_t time_mono, time_real; | 122 | ktime_t time_mono, time_real; |
| 103 | 123 | ||
| 104 | time_mono = ktime_get(); | 124 | time_mono = ktime_get(); |
| 105 | time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); | 125 | time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); |
| 106 | 126 | ||
| 107 | event.type = type; | ||
| 108 | event.code = code; | ||
| 109 | event.value = value; | ||
| 110 | |||
| 111 | rcu_read_lock(); | 127 | rcu_read_lock(); |
| 112 | 128 | ||
| 113 | client = rcu_dereference(evdev->grab); | 129 | client = rcu_dereference(evdev->grab); |
| 114 | 130 | ||
| 115 | if (client) | 131 | if (client) |
| 116 | evdev_pass_event(client, &event, time_mono, time_real); | 132 | evdev_pass_values(client, vals, count, time_mono, time_real); |
| 117 | else | 133 | else |
| 118 | list_for_each_entry_rcu(client, &evdev->client_list, node) | 134 | list_for_each_entry_rcu(client, &evdev->client_list, node) |
| 119 | evdev_pass_event(client, &event, time_mono, time_real); | 135 | evdev_pass_values(client, vals, count, |
| 136 | time_mono, time_real); | ||
| 120 | 137 | ||
| 121 | rcu_read_unlock(); | 138 | rcu_read_unlock(); |
| 139 | } | ||
| 122 | 140 | ||
| 123 | if (type == EV_SYN && code == SYN_REPORT) | 141 | /* |
| 124 | wake_up_interruptible(&evdev->wait); | 142 | * Pass incoming event to all connected clients. |
| 143 | */ | ||
| 144 | static void evdev_event(struct input_handle *handle, | ||
| 145 | unsigned int type, unsigned int code, int value) | ||
| 146 | { | ||
| 147 | struct input_value vals[] = { { type, code, value } }; | ||
| 148 | |||
| 149 | evdev_events(handle, vals, 1); | ||
| 125 | } | 150 | } |
| 126 | 151 | ||
| 127 | static int evdev_fasync(int fd, struct file *file, int on) | 152 | static int evdev_fasync(int fd, struct file *file, int on) |
| @@ -653,20 +678,22 @@ static int evdev_handle_mt_request(struct input_dev *dev, | |||
| 653 | unsigned int size, | 678 | unsigned int size, |
| 654 | int __user *ip) | 679 | int __user *ip) |
| 655 | { | 680 | { |
| 656 | const struct input_mt_slot *mt = dev->mt; | 681 | const struct input_mt *mt = dev->mt; |
| 657 | unsigned int code; | 682 | unsigned int code; |
| 658 | int max_slots; | 683 | int max_slots; |
| 659 | int i; | 684 | int i; |
| 660 | 685 | ||
| 661 | if (get_user(code, &ip[0])) | 686 | if (get_user(code, &ip[0])) |
| 662 | return -EFAULT; | 687 | return -EFAULT; |
| 663 | if (!input_is_mt_value(code)) | 688 | if (!mt || !input_is_mt_value(code)) |
| 664 | return -EINVAL; | 689 | return -EINVAL; |
| 665 | 690 | ||
| 666 | max_slots = (size - sizeof(__u32)) / sizeof(__s32); | 691 | max_slots = (size - sizeof(__u32)) / sizeof(__s32); |
| 667 | for (i = 0; i < dev->mtsize && i < max_slots; i++) | 692 | for (i = 0; i < mt->num_slots && i < max_slots; i++) { |
| 668 | if (put_user(input_mt_get_value(&mt[i], code), &ip[1 + i])) | 693 | int value = input_mt_get_value(&mt->slots[i], code); |
| 694 | if (put_user(value, &ip[1 + i])) | ||
| 669 | return -EFAULT; | 695 | return -EFAULT; |
| 696 | } | ||
| 670 | 697 | ||
| 671 | return 0; | 698 | return 0; |
| 672 | } | 699 | } |
| @@ -1048,6 +1075,7 @@ MODULE_DEVICE_TABLE(input, evdev_ids); | |||
| 1048 | 1075 | ||
| 1049 | static struct input_handler evdev_handler = { | 1076 | static struct input_handler evdev_handler = { |
| 1050 | .event = evdev_event, | 1077 | .event = evdev_event, |
| 1078 | .events = evdev_events, | ||
| 1051 | .connect = evdev_connect, | 1079 | .connect = evdev_connect, |
| 1052 | .disconnect = evdev_disconnect, | 1080 | .disconnect = evdev_disconnect, |
| 1053 | .fops = &evdev_fops, | 1081 | .fops = &evdev_fops, |
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index 70a16c7da8cc..c0ec7d42c3be 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c | |||
| @@ -14,6 +14,14 @@ | |||
| 14 | 14 | ||
| 15 | #define TRKID_SGN ((TRKID_MAX + 1) >> 1) | 15 | #define TRKID_SGN ((TRKID_MAX + 1) >> 1) |
| 16 | 16 | ||
| 17 | static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src) | ||
| 18 | { | ||
| 19 | if (dev->absinfo && test_bit(src, dev->absbit)) { | ||
| 20 | dev->absinfo[dst] = dev->absinfo[src]; | ||
| 21 | dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst); | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 17 | /** | 25 | /** |
| 18 | * input_mt_init_slots() - initialize MT input slots | 26 | * input_mt_init_slots() - initialize MT input slots |
| 19 | * @dev: input device supporting MT events and finger tracking | 27 | * @dev: input device supporting MT events and finger tracking |
| @@ -25,29 +33,63 @@ | |||
| 25 | * May be called repeatedly. Returns -EINVAL if attempting to | 33 | * May be called repeatedly. Returns -EINVAL if attempting to |
| 26 | * reinitialize with a different number of slots. | 34 | * reinitialize with a different number of slots. |
| 27 | */ | 35 | */ |
| 28 | int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots) | 36 | int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots, |
| 37 | unsigned int flags) | ||
| 29 | { | 38 | { |
| 39 | struct input_mt *mt = dev->mt; | ||
| 30 | int i; | 40 | int i; |
| 31 | 41 | ||
| 32 | if (!num_slots) | 42 | if (!num_slots) |
| 33 | return 0; | 43 | return 0; |
| 34 | if (dev->mt) | 44 | if (mt) |
| 35 | return dev->mtsize != num_slots ? -EINVAL : 0; | 45 | return mt->num_slots != num_slots ? -EINVAL : 0; |
| 36 | 46 | ||
| 37 | dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL); | 47 | mt = kzalloc(sizeof(*mt) + num_slots * sizeof(*mt->slots), GFP_KERNEL); |
| 38 | if (!dev->mt) | 48 | if (!mt) |
| 39 | return -ENOMEM; | 49 | goto err_mem; |
| 40 | 50 | ||
| 41 | dev->mtsize = num_slots; | 51 | mt->num_slots = num_slots; |
| 52 | mt->flags = flags; | ||
| 42 | input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0); | 53 | input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0); |
| 43 | input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0); | 54 | input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0); |
| 44 | input_set_events_per_packet(dev, 6 * num_slots); | 55 | |
| 56 | if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) { | ||
| 57 | __set_bit(EV_KEY, dev->evbit); | ||
| 58 | __set_bit(BTN_TOUCH, dev->keybit); | ||
| 59 | |||
| 60 | copy_abs(dev, ABS_X, ABS_MT_POSITION_X); | ||
| 61 | copy_abs(dev, ABS_Y, ABS_MT_POSITION_Y); | ||
| 62 | copy_abs(dev, ABS_PRESSURE, ABS_MT_PRESSURE); | ||
| 63 | } | ||
| 64 | if (flags & INPUT_MT_POINTER) { | ||
| 65 | __set_bit(BTN_TOOL_FINGER, dev->keybit); | ||
| 66 | __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); | ||
| 67 | if (num_slots >= 3) | ||
| 68 | __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); | ||
| 69 | if (num_slots >= 4) | ||
| 70 | __set_bit(BTN_TOOL_QUADTAP, dev->keybit); | ||
| 71 | if (num_slots >= 5) | ||
| 72 | __set_bit(BTN_TOOL_QUINTTAP, dev->keybit); | ||
| 73 | __set_bit(INPUT_PROP_POINTER, dev->propbit); | ||
| 74 | } | ||
| 75 | if (flags & INPUT_MT_DIRECT) | ||
| 76 | __set_bit(INPUT_PROP_DIRECT, dev->propbit); | ||
| 77 | if (flags & INPUT_MT_TRACK) { | ||
| 78 | unsigned int n2 = num_slots * num_slots; | ||
| 79 | mt->red = kcalloc(n2, sizeof(*mt->red), GFP_KERNEL); | ||
| 80 | if (!mt->red) | ||
| 81 | goto err_mem; | ||
| 82 | } | ||
| 45 | 83 | ||
| 46 | /* Mark slots as 'unused' */ | 84 | /* Mark slots as 'unused' */ |
| 47 | for (i = 0; i < num_slots; i++) | 85 | for (i = 0; i < num_slots; i++) |
| 48 | input_mt_set_value(&dev->mt[i], ABS_MT_TRACKING_ID, -1); | 86 | input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1); |
| 49 | 87 | ||
| 88 | dev->mt = mt; | ||
| 50 | return 0; | 89 | return 0; |
| 90 | err_mem: | ||
| 91 | kfree(mt); | ||
| 92 | return -ENOMEM; | ||
| 51 | } | 93 | } |
| 52 | EXPORT_SYMBOL(input_mt_init_slots); | 94 | EXPORT_SYMBOL(input_mt_init_slots); |
| 53 | 95 | ||
| @@ -60,11 +102,11 @@ EXPORT_SYMBOL(input_mt_init_slots); | |||
| 60 | */ | 102 | */ |
| 61 | void input_mt_destroy_slots(struct input_dev *dev) | 103 | void input_mt_destroy_slots(struct input_dev *dev) |
| 62 | { | 104 | { |
| 63 | kfree(dev->mt); | 105 | if (dev->mt) { |
| 106 | kfree(dev->mt->red); | ||
| 107 | kfree(dev->mt); | ||
| 108 | } | ||
| 64 | dev->mt = NULL; | 109 | dev->mt = NULL; |
| 65 | dev->mtsize = 0; | ||
| 66 | dev->slot = 0; | ||
| 67 | dev->trkid = 0; | ||
| 68 | } | 110 | } |
| 69 | EXPORT_SYMBOL(input_mt_destroy_slots); | 111 | EXPORT_SYMBOL(input_mt_destroy_slots); |
| 70 | 112 | ||
| @@ -83,18 +125,24 @@ EXPORT_SYMBOL(input_mt_destroy_slots); | |||
| 83 | void input_mt_report_slot_state(struct input_dev *dev, | 125 | void input_mt_report_slot_state(struct input_dev *dev, |
| 84 | unsigned int tool_type, bool active) | 126 | unsigned int tool_type, bool active) |
| 85 | { | 127 | { |
| 86 | struct input_mt_slot *mt; | 128 | struct input_mt *mt = dev->mt; |
| 129 | struct input_mt_slot *slot; | ||
| 87 | int id; | 130 | int id; |
| 88 | 131 | ||
| 89 | if (!dev->mt || !active) { | 132 | if (!mt) |
| 133 | return; | ||
| 134 | |||
| 135 | slot = &mt->slots[mt->slot]; | ||
| 136 | slot->frame = mt->frame; | ||
| 137 | |||
| 138 | if (!active) { | ||
| 90 | input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); | 139 | input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); |
| 91 | return; | 140 | return; |
| 92 | } | 141 | } |
| 93 | 142 | ||
| 94 | mt = &dev->mt[dev->slot]; | 143 | id = input_mt_get_value(slot, ABS_MT_TRACKING_ID); |
| 95 | id = input_mt_get_value(mt, ABS_MT_TRACKING_ID); | 144 | if (id < 0 || input_mt_get_value(slot, ABS_MT_TOOL_TYPE) != tool_type) |
| 96 | if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type) | 145 | id = input_mt_new_trkid(mt); |
| 97 | id = input_mt_new_trkid(dev); | ||
| 98 | 146 | ||
| 99 | input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id); | 147 | input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id); |
| 100 | input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type); | 148 | input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type); |
| @@ -135,13 +183,19 @@ EXPORT_SYMBOL(input_mt_report_finger_count); | |||
| 135 | */ | 183 | */ |
| 136 | void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) | 184 | void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) |
| 137 | { | 185 | { |
| 138 | struct input_mt_slot *oldest = NULL; | 186 | struct input_mt *mt = dev->mt; |
| 139 | int oldid = dev->trkid; | 187 | struct input_mt_slot *oldest; |
| 140 | int count = 0; | 188 | int oldid, count, i; |
| 141 | int i; | 189 | |
| 190 | if (!mt) | ||
| 191 | return; | ||
| 192 | |||
| 193 | oldest = 0; | ||
| 194 | oldid = mt->trkid; | ||
| 195 | count = 0; | ||
| 142 | 196 | ||
| 143 | for (i = 0; i < dev->mtsize; ++i) { | 197 | for (i = 0; i < mt->num_slots; ++i) { |
| 144 | struct input_mt_slot *ps = &dev->mt[i]; | 198 | struct input_mt_slot *ps = &mt->slots[i]; |
| 145 | int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID); | 199 | int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID); |
| 146 | 200 | ||
| 147 | if (id < 0) | 201 | if (id < 0) |
| @@ -160,13 +214,208 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) | |||
| 160 | if (oldest) { | 214 | if (oldest) { |
| 161 | int x = input_mt_get_value(oldest, ABS_MT_POSITION_X); | 215 | int x = input_mt_get_value(oldest, ABS_MT_POSITION_X); |
| 162 | int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y); | 216 | int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y); |
| 163 | int p = input_mt_get_value(oldest, ABS_MT_PRESSURE); | ||
| 164 | 217 | ||
| 165 | input_event(dev, EV_ABS, ABS_X, x); | 218 | input_event(dev, EV_ABS, ABS_X, x); |
| 166 | input_event(dev, EV_ABS, ABS_Y, y); | 219 | input_event(dev, EV_ABS, ABS_Y, y); |
| 167 | input_event(dev, EV_ABS, ABS_PRESSURE, p); | 220 | |
| 221 | if (test_bit(ABS_MT_PRESSURE, dev->absbit)) { | ||
| 222 | int p = input_mt_get_value(oldest, ABS_MT_PRESSURE); | ||
| 223 | input_event(dev, EV_ABS, ABS_PRESSURE, p); | ||
| 224 | } | ||
| 168 | } else { | 225 | } else { |
| 169 | input_event(dev, EV_ABS, ABS_PRESSURE, 0); | 226 | if (test_bit(ABS_MT_PRESSURE, dev->absbit)) |
| 227 | input_event(dev, EV_ABS, ABS_PRESSURE, 0); | ||
| 170 | } | 228 | } |
| 171 | } | 229 | } |
| 172 | EXPORT_SYMBOL(input_mt_report_pointer_emulation); | 230 | EXPORT_SYMBOL(input_mt_report_pointer_emulation); |
| 231 | |||
| 232 | /** | ||
| 233 | * input_mt_sync_frame() - synchronize mt frame | ||
| 234 | * @dev: input device with allocated MT slots | ||
| 235 | * | ||
| 236 | * Close the frame and prepare the internal state for a new one. | ||
| 237 | * Depending on the flags, marks unused slots as inactive and performs | ||
| 238 | * pointer emulation. | ||
| 239 | */ | ||
| 240 | void input_mt_sync_frame(struct input_dev *dev) | ||
| 241 | { | ||
| 242 | struct input_mt *mt = dev->mt; | ||
| 243 | struct input_mt_slot *s; | ||
| 244 | |||
| 245 | if (!mt) | ||
| 246 | return; | ||
| 247 | |||
| 248 | if (mt->flags & INPUT_MT_DROP_UNUSED) { | ||
| 249 | for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { | ||
| 250 | if (s->frame == mt->frame) | ||
| 251 | continue; | ||
| 252 | input_mt_slot(dev, s - mt->slots); | ||
| 253 | input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | input_mt_report_pointer_emulation(dev, (mt->flags & INPUT_MT_POINTER)); | ||
| 258 | |||
| 259 | mt->frame++; | ||
| 260 | } | ||
| 261 | EXPORT_SYMBOL(input_mt_sync_frame); | ||
| 262 | |||
| 263 | static int adjust_dual(int *begin, int step, int *end, int eq) | ||
| 264 | { | ||
| 265 | int f, *p, s, c; | ||
| 266 | |||
| 267 | if (begin == end) | ||
| 268 | return 0; | ||
| 269 | |||
| 270 | f = *begin; | ||
| 271 | p = begin + step; | ||
| 272 | s = p == end ? f + 1 : *p; | ||
| 273 | |||
| 274 | for (; p != end; p += step) | ||
| 275 | if (*p < f) | ||
| 276 | s = f, f = *p; | ||
| 277 | else if (*p < s) | ||
| 278 | s = *p; | ||
| 279 | |||
| 280 | c = (f + s + 1) / 2; | ||
| 281 | if (c == 0 || (c > 0 && !eq)) | ||
| 282 | return 0; | ||
| 283 | if (s < 0) | ||
| 284 | c *= 2; | ||
| 285 | |||
| 286 | for (p = begin; p != end; p += step) | ||
| 287 | *p -= c; | ||
| 288 | |||
| 289 | return (c < s && s <= 0) || (f >= 0 && f < c); | ||
| 290 | } | ||
| 291 | |||
| 292 | static void find_reduced_matrix(int *w, int nr, int nc, int nrc) | ||
| 293 | { | ||
| 294 | int i, k, sum; | ||
| 295 | |||
| 296 | for (k = 0; k < nrc; k++) { | ||
| 297 | for (i = 0; i < nr; i++) | ||
| 298 | adjust_dual(w + i, nr, w + i + nrc, nr <= nc); | ||
| 299 | sum = 0; | ||
| 300 | for (i = 0; i < nrc; i += nr) | ||
| 301 | sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr); | ||
| 302 | if (!sum) | ||
| 303 | break; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 307 | static int input_mt_set_matrix(struct input_mt *mt, | ||
| 308 | const struct input_mt_pos *pos, int num_pos) | ||
| 309 | { | ||
| 310 | const struct input_mt_pos *p; | ||
| 311 | struct input_mt_slot *s; | ||
| 312 | int *w = mt->red; | ||
| 313 | int x, y; | ||
| 314 | |||
| 315 | for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { | ||
| 316 | if (!input_mt_is_active(s)) | ||
| 317 | continue; | ||
| 318 | x = input_mt_get_value(s, ABS_MT_POSITION_X); | ||
| 319 | y = input_mt_get_value(s, ABS_MT_POSITION_Y); | ||
| 320 | for (p = pos; p != pos + num_pos; p++) { | ||
| 321 | int dx = x - p->x, dy = y - p->y; | ||
| 322 | *w++ = dx * dx + dy * dy; | ||
| 323 | } | ||
| 324 | } | ||
| 325 | |||
| 326 | return w - mt->red; | ||
| 327 | } | ||
| 328 | |||
| 329 | static void input_mt_set_slots(struct input_mt *mt, | ||
| 330 | int *slots, int num_pos) | ||
| 331 | { | ||
| 332 | struct input_mt_slot *s; | ||
| 333 | int *w = mt->red, *p; | ||
| 334 | |||
| 335 | for (p = slots; p != slots + num_pos; p++) | ||
| 336 | *p = -1; | ||
| 337 | |||
| 338 | for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { | ||
| 339 | if (!input_mt_is_active(s)) | ||
| 340 | continue; | ||
| 341 | for (p = slots; p != slots + num_pos; p++) | ||
| 342 | if (*w++ < 0) | ||
| 343 | *p = s - mt->slots; | ||
| 344 | } | ||
| 345 | |||
| 346 | for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { | ||
| 347 | if (input_mt_is_active(s)) | ||
| 348 | continue; | ||
| 349 | for (p = slots; p != slots + num_pos; p++) | ||
| 350 | if (*p < 0) { | ||
| 351 | *p = s - mt->slots; | ||
| 352 | break; | ||
| 353 | } | ||
| 354 | } | ||
| 355 | } | ||
| 356 | |||
| 357 | /** | ||
| 358 | * input_mt_assign_slots() - perform a best-match assignment | ||
| 359 | * @dev: input device with allocated MT slots | ||
| 360 | * @slots: the slot assignment to be filled | ||
| 361 | * @pos: the position array to match | ||
| 362 | * @num_pos: number of positions | ||
| 363 | * | ||
| 364 | * Performs a best match against the current contacts and returns | ||
| 365 | * the slot assignment list. New contacts are assigned to unused | ||
| 366 | * slots. | ||
| 367 | * | ||
| 368 | * Returns zero on success, or negative error in case of failure. | ||
| 369 | */ | ||
| 370 | int input_mt_assign_slots(struct input_dev *dev, int *slots, | ||
| 371 | const struct input_mt_pos *pos, int num_pos) | ||
| 372 | { | ||
| 373 | struct input_mt *mt = dev->mt; | ||
| 374 | int nrc; | ||
| 375 | |||
| 376 | if (!mt || !mt->red) | ||
| 377 | return -ENXIO; | ||
| 378 | if (num_pos > mt->num_slots) | ||
| 379 | return -EINVAL; | ||
| 380 | if (num_pos < 1) | ||
| 381 | return 0; | ||
| 382 | |||
| 383 | nrc = input_mt_set_matrix(mt, pos, num_pos); | ||
| 384 | find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc); | ||
| 385 | input_mt_set_slots(mt, slots, num_pos); | ||
| 386 | |||
| 387 | return 0; | ||
| 388 | } | ||
| 389 | EXPORT_SYMBOL(input_mt_assign_slots); | ||
| 390 | |||
| 391 | /** | ||
| 392 | * input_mt_get_slot_by_key() - return slot matching key | ||
| 393 | * @dev: input device with allocated MT slots | ||
| 394 | * @key: the key of the sought slot | ||
| 395 | * | ||
| 396 | * Returns the slot of the given key, if it exists, otherwise | ||
| 397 | * set the key on the first unused slot and return. | ||
| 398 | * | ||
| 399 | * If no available slot can be found, -1 is returned. | ||
| 400 | */ | ||
| 401 | int input_mt_get_slot_by_key(struct input_dev *dev, int key) | ||
| 402 | { | ||
| 403 | struct input_mt *mt = dev->mt; | ||
| 404 | struct input_mt_slot *s; | ||
| 405 | |||
| 406 | if (!mt) | ||
| 407 | return -1; | ||
| 408 | |||
| 409 | for (s = mt->slots; s != mt->slots + mt->num_slots; s++) | ||
| 410 | if (input_mt_is_active(s) && s->key == key) | ||
| 411 | return s - mt->slots; | ||
| 412 | |||
| 413 | for (s = mt->slots; s != mt->slots + mt->num_slots; s++) | ||
| 414 | if (!input_mt_is_active(s)) { | ||
| 415 | s->key = key; | ||
| 416 | return s - mt->slots; | ||
| 417 | } | ||
| 418 | |||
| 419 | return -1; | ||
| 420 | } | ||
| 421 | EXPORT_SYMBOL(input_mt_get_slot_by_key); | ||
diff --git a/drivers/input/input.c b/drivers/input/input.c index 8921c6180c51..5244f3d05b12 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
| @@ -47,6 +47,8 @@ static DEFINE_MUTEX(input_mutex); | |||
| 47 | 47 | ||
| 48 | static struct input_handler *input_table[8]; | 48 | static struct input_handler *input_table[8]; |
| 49 | 49 | ||
| 50 | static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 }; | ||
| 51 | |||
| 50 | static inline int is_event_supported(unsigned int code, | 52 | static inline int is_event_supported(unsigned int code, |
| 51 | unsigned long *bm, unsigned int max) | 53 | unsigned long *bm, unsigned int max) |
| 52 | { | 54 | { |
| @@ -69,42 +71,102 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz) | |||
| 69 | return value; | 71 | return value; |
| 70 | } | 72 | } |
| 71 | 73 | ||
| 74 | static void input_start_autorepeat(struct input_dev *dev, int code) | ||
| 75 | { | ||
| 76 | if (test_bit(EV_REP, dev->evbit) && | ||
| 77 | dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && | ||
| 78 | dev->timer.data) { | ||
| 79 | dev->repeat_key = code; | ||
| 80 | mod_timer(&dev->timer, | ||
| 81 | jiffies + msecs_to_jiffies(dev->rep[REP_DELAY])); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | static void input_stop_autorepeat(struct input_dev *dev) | ||
| 86 | { | ||
| 87 | del_timer(&dev->timer); | ||
| 88 | } | ||
| 89 | |||
| 72 | /* | 90 | /* |
| 73 | * Pass event first through all filters and then, if event has not been | 91 | * Pass event first through all filters and then, if event has not been |
| 74 | * filtered out, through all open handles. This function is called with | 92 | * filtered out, through all open handles. This function is called with |
| 75 | * dev->event_lock held and interrupts disabled. | 93 | * dev->event_lock held and interrupts disabled. |
| 76 | */ | 94 | */ |
| 77 | static void input_pass_event(struct input_dev *dev, | 95 | static unsigned int input_to_handler(struct input_handle *handle, |
| 78 | unsigned int type, unsigned int code, int value) | 96 | struct input_value *vals, unsigned int count) |
| 97 | { | ||
| 98 | struct input_handler *handler = handle->handler; | ||
| 99 | struct input_value *end = vals; | ||
| 100 | struct input_value *v; | ||
| 101 | |||
| 102 | for (v = vals; v != vals + count; v++) { | ||
| 103 | if (handler->filter && | ||
| 104 | handler->filter(handle, v->type, v->code, v->value)) | ||
| 105 | continue; | ||
| 106 | if (end != v) | ||
| 107 | *end = *v; | ||
| 108 | end++; | ||
| 109 | } | ||
| 110 | |||
| 111 | count = end - vals; | ||
| 112 | if (!count) | ||
| 113 | return 0; | ||
| 114 | |||
| 115 | if (handler->events) | ||
| 116 | handler->events(handle, vals, count); | ||
| 117 | else if (handler->event) | ||
| 118 | for (v = vals; v != end; v++) | ||
| 119 | handler->event(handle, v->type, v->code, v->value); | ||
| 120 | |||
| 121 | return count; | ||
| 122 | } | ||
| 123 | |||
| 124 | /* | ||
| 125 | * Pass values first through all filters and then, if event has not been | ||
| 126 | * filtered out, through all open handles. This function is called with | ||
| 127 | * dev->event_lock held and interrupts disabled. | ||
| 128 | */ | ||
| 129 | static void input_pass_values(struct input_dev *dev, | ||
| 130 | struct input_value *vals, unsigned int count) | ||
| 79 | { | 131 | { |
| 80 | struct input_handler *handler; | ||
| 81 | struct input_handle *handle; | 132 | struct input_handle *handle; |
| 133 | struct input_value *v; | ||
| 134 | |||
| 135 | if (!count) | ||
| 136 | return; | ||
| 82 | 137 | ||
| 83 | rcu_read_lock(); | 138 | rcu_read_lock(); |
| 84 | 139 | ||
| 85 | handle = rcu_dereference(dev->grab); | 140 | handle = rcu_dereference(dev->grab); |
| 86 | if (handle) | 141 | if (handle) { |
| 87 | handle->handler->event(handle, type, code, value); | 142 | count = input_to_handler(handle, vals, count); |
| 88 | else { | 143 | } else { |
| 89 | bool filtered = false; | 144 | list_for_each_entry_rcu(handle, &dev->h_list, d_node) |
| 90 | 145 | if (handle->open) | |
| 91 | list_for_each_entry_rcu(handle, &dev->h_list, d_node) { | 146 | count = input_to_handler(handle, vals, count); |
| 92 | if (!handle->open) | 147 | } |
| 93 | continue; | ||
| 94 | 148 | ||
| 95 | handler = handle->handler; | 149 | rcu_read_unlock(); |
| 96 | if (!handler->filter) { | ||
| 97 | if (filtered) | ||
| 98 | break; | ||
| 99 | 150 | ||
| 100 | handler->event(handle, type, code, value); | 151 | add_input_randomness(vals->type, vals->code, vals->value); |
| 101 | 152 | ||
| 102 | } else if (handler->filter(handle, type, code, value)) | 153 | /* trigger auto repeat for key events */ |
| 103 | filtered = true; | 154 | for (v = vals; v != vals + count; v++) { |
| 155 | if (v->type == EV_KEY && v->value != 2) { | ||
| 156 | if (v->value) | ||
| 157 | input_start_autorepeat(dev, v->code); | ||
| 158 | else | ||
| 159 | input_stop_autorepeat(dev); | ||
| 104 | } | 160 | } |
| 105 | } | 161 | } |
| 162 | } | ||
| 106 | 163 | ||
| 107 | rcu_read_unlock(); | 164 | static void input_pass_event(struct input_dev *dev, |
| 165 | unsigned int type, unsigned int code, int value) | ||
| 166 | { | ||
| 167 | struct input_value vals[] = { { type, code, value } }; | ||
| 168 | |||
| 169 | input_pass_values(dev, vals, ARRAY_SIZE(vals)); | ||
| 108 | } | 170 | } |
| 109 | 171 | ||
| 110 | /* | 172 | /* |
| @@ -121,18 +183,12 @@ static void input_repeat_key(unsigned long data) | |||
| 121 | 183 | ||
| 122 | if (test_bit(dev->repeat_key, dev->key) && | 184 | if (test_bit(dev->repeat_key, dev->key) && |
| 123 | is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) { | 185 | is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) { |
| 186 | struct input_value vals[] = { | ||
| 187 | { EV_KEY, dev->repeat_key, 2 }, | ||
| 188 | input_value_sync | ||
| 189 | }; | ||
| 124 | 190 | ||
| 125 | input_pass_event(dev, EV_KEY, dev->repeat_key, 2); | 191 | input_pass_values(dev, vals, ARRAY_SIZE(vals)); |
| 126 | |||
| 127 | if (dev->sync) { | ||
| 128 | /* | ||
| 129 | * Only send SYN_REPORT if we are not in a middle | ||
| 130 | * of driver parsing a new hardware packet. | ||
| 131 | * Otherwise assume that the driver will send | ||
| 132 | * SYN_REPORT once it's done. | ||
| 133 | */ | ||
| 134 | input_pass_event(dev, EV_SYN, SYN_REPORT, 1); | ||
| 135 | } | ||
| 136 | 192 | ||
| 137 | if (dev->rep[REP_PERIOD]) | 193 | if (dev->rep[REP_PERIOD]) |
| 138 | mod_timer(&dev->timer, jiffies + | 194 | mod_timer(&dev->timer, jiffies + |
| @@ -142,30 +198,17 @@ static void input_repeat_key(unsigned long data) | |||
| 142 | spin_unlock_irqrestore(&dev->event_lock, flags); | 198 | spin_unlock_irqrestore(&dev->event_lock, flags); |
| 143 | } | 199 | } |
| 144 | 200 | ||
| 145 | static void input_start_autorepeat(struct input_dev *dev, int code) | ||
| 146 | { | ||
| 147 | if (test_bit(EV_REP, dev->evbit) && | ||
| 148 | dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && | ||
| 149 | dev->timer.data) { | ||
| 150 | dev->repeat_key = code; | ||
| 151 | mod_timer(&dev->timer, | ||
| 152 | jiffies + msecs_to_jiffies(dev->rep[REP_DELAY])); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | static void input_stop_autorepeat(struct input_dev *dev) | ||
| 157 | { | ||
| 158 | del_timer(&dev->timer); | ||
| 159 | } | ||
| 160 | |||
| 161 | #define INPUT_IGNORE_EVENT 0 | 201 | #define INPUT_IGNORE_EVENT 0 |
| 162 | #define INPUT_PASS_TO_HANDLERS 1 | 202 | #define INPUT_PASS_TO_HANDLERS 1 |
| 163 | #define INPUT_PASS_TO_DEVICE 2 | 203 | #define INPUT_PASS_TO_DEVICE 2 |
| 204 | #define INPUT_SLOT 4 | ||
| 205 | #define INPUT_FLUSH 8 | ||
| 164 | #define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) | 206 | #define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) |
| 165 | 207 | ||
| 166 | static int input_handle_abs_event(struct input_dev *dev, | 208 | static int input_handle_abs_event(struct input_dev *dev, |
| 167 | unsigned int code, int *pval) | 209 | unsigned int code, int *pval) |
| 168 | { | 210 | { |
| 211 | struct input_mt *mt = dev->mt; | ||
| 169 | bool is_mt_event; | 212 | bool is_mt_event; |
| 170 | int *pold; | 213 | int *pold; |
| 171 | 214 | ||
| @@ -174,8 +217,8 @@ static int input_handle_abs_event(struct input_dev *dev, | |||
| 174 | * "Stage" the event; we'll flush it later, when we | 217 | * "Stage" the event; we'll flush it later, when we |
| 175 | * get actual touch data. | 218 | * get actual touch data. |
| 176 | */ | 219 | */ |
| 177 | if (*pval >= 0 && *pval < dev->mtsize) | 220 | if (mt && *pval >= 0 && *pval < mt->num_slots) |
| 178 | dev->slot = *pval; | 221 | mt->slot = *pval; |
| 179 | 222 | ||
| 180 | return INPUT_IGNORE_EVENT; | 223 | return INPUT_IGNORE_EVENT; |
| 181 | } | 224 | } |
| @@ -184,9 +227,8 @@ static int input_handle_abs_event(struct input_dev *dev, | |||
| 184 | 227 | ||
| 185 | if (!is_mt_event) { | 228 | if (!is_mt_event) { |
| 186 | pold = &dev->absinfo[code].value; | 229 | pold = &dev->absinfo[code].value; |
| 187 | } else if (dev->mt) { | 230 | } else if (mt) { |
| 188 | struct input_mt_slot *mtslot = &dev->mt[dev->slot]; | 231 | pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST]; |
| 189 | pold = &mtslot->abs[code - ABS_MT_FIRST]; | ||
| 190 | } else { | 232 | } else { |
| 191 | /* | 233 | /* |
| 192 | * Bypass filtering for multi-touch events when | 234 | * Bypass filtering for multi-touch events when |
| @@ -205,16 +247,16 @@ static int input_handle_abs_event(struct input_dev *dev, | |||
| 205 | } | 247 | } |
| 206 | 248 | ||
| 207 | /* Flush pending "slot" event */ | 249 | /* Flush pending "slot" event */ |
| 208 | if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) { | 250 | if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) { |
| 209 | input_abs_set_val(dev, ABS_MT_SLOT, dev->slot); | 251 | input_abs_set_val(dev, ABS_MT_SLOT, mt->slot); |
| 210 | input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot); | 252 | return INPUT_PASS_TO_HANDLERS | INPUT_SLOT; |
| 211 | } | 253 | } |
| 212 | 254 | ||
| 213 | return INPUT_PASS_TO_HANDLERS; | 255 | return INPUT_PASS_TO_HANDLERS; |
| 214 | } | 256 | } |
| 215 | 257 | ||
| 216 | static void input_handle_event(struct input_dev *dev, | 258 | static int input_get_disposition(struct input_dev *dev, |
| 217 | unsigned int type, unsigned int code, int value) | 259 | unsigned int type, unsigned int code, int value) |
| 218 | { | 260 | { |
| 219 | int disposition = INPUT_IGNORE_EVENT; | 261 | int disposition = INPUT_IGNORE_EVENT; |
| 220 | 262 | ||
| @@ -227,37 +269,34 @@ static void input_handle_event(struct input_dev *dev, | |||
| 227 | break; | 269 | break; |
| 228 | 270 | ||
| 229 | case SYN_REPORT: | 271 | case SYN_REPORT: |
| 230 | if (!dev->sync) { | 272 | disposition = INPUT_PASS_TO_HANDLERS | INPUT_FLUSH; |
| 231 | dev->sync = true; | ||
| 232 | disposition = INPUT_PASS_TO_HANDLERS; | ||
| 233 | } | ||
| 234 | break; | 273 | break; |
| 235 | case SYN_MT_REPORT: | 274 | case SYN_MT_REPORT: |
| 236 | dev->sync = false; | ||
| 237 | disposition = INPUT_PASS_TO_HANDLERS; | 275 | disposition = INPUT_PASS_TO_HANDLERS; |
| 238 | break; | 276 | break; |
| 239 | } | 277 | } |
| 240 | break; | 278 | break; |
| 241 | 279 | ||
| 242 | case EV_KEY: | 280 | case EV_KEY: |
| 243 | if (is_event_supported(code, dev->keybit, KEY_MAX) && | 281 | if (is_event_supported(code, dev->keybit, KEY_MAX)) { |
| 244 | !!test_bit(code, dev->key) != value) { | ||
| 245 | 282 | ||
| 246 | if (value != 2) { | 283 | /* auto-repeat bypasses state updates */ |
| 247 | __change_bit(code, dev->key); | 284 | if (value == 2) { |
| 248 | if (value) | 285 | disposition = INPUT_PASS_TO_HANDLERS; |
| 249 | input_start_autorepeat(dev, code); | 286 | break; |
| 250 | else | ||
| 251 | input_stop_autorepeat(dev); | ||
| 252 | } | 287 | } |
| 253 | 288 | ||
| 254 | disposition = INPUT_PASS_TO_HANDLERS; | 289 | if (!!test_bit(code, dev->key) != !!value) { |
| 290 | |||
| 291 | __change_bit(code, dev->key); | ||
| 292 | disposition = INPUT_PASS_TO_HANDLERS; | ||
| 293 | } | ||
| 255 | } | 294 | } |
| 256 | break; | 295 | break; |
| 257 | 296 | ||
| 258 | case EV_SW: | 297 | case EV_SW: |
| 259 | if (is_event_supported(code, dev->swbit, SW_MAX) && | 298 | if (is_event_supported(code, dev->swbit, SW_MAX) && |
| 260 | !!test_bit(code, dev->sw) != value) { | 299 | !!test_bit(code, dev->sw) != !!value) { |
| 261 | 300 | ||
| 262 | __change_bit(code, dev->sw); | 301 | __change_bit(code, dev->sw); |
| 263 | disposition = INPUT_PASS_TO_HANDLERS; | 302 | disposition = INPUT_PASS_TO_HANDLERS; |
| @@ -284,7 +323,7 @@ static void input_handle_event(struct input_dev *dev, | |||
| 284 | 323 | ||
| 285 | case EV_LED: | 324 | case EV_LED: |
| 286 | if (is_event_supported(code, dev->ledbit, LED_MAX) && | 325 | if (is_event_supported(code, dev->ledbit, LED_MAX) && |
| 287 | !!test_bit(code, dev->led) != value) { | 326 | !!test_bit(code, dev->led) != !!value) { |
| 288 | 327 | ||
| 289 | __change_bit(code, dev->led); | 328 | __change_bit(code, dev->led); |
| 290 | disposition = INPUT_PASS_TO_ALL; | 329 | disposition = INPUT_PASS_TO_ALL; |
| @@ -317,14 +356,48 @@ static void input_handle_event(struct input_dev *dev, | |||
| 317 | break; | 356 | break; |
| 318 | } | 357 | } |
| 319 | 358 | ||
| 320 | if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) | 359 | return disposition; |
| 321 | dev->sync = false; | 360 | } |
| 361 | |||
| 362 | static void input_handle_event(struct input_dev *dev, | ||
| 363 | unsigned int type, unsigned int code, int value) | ||
| 364 | { | ||
| 365 | int disposition; | ||
| 366 | |||
| 367 | disposition = input_get_disposition(dev, type, code, value); | ||
| 322 | 368 | ||
| 323 | if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) | 369 | if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) |
| 324 | dev->event(dev, type, code, value); | 370 | dev->event(dev, type, code, value); |
| 325 | 371 | ||
| 326 | if (disposition & INPUT_PASS_TO_HANDLERS) | 372 | if (!dev->vals) |
| 327 | input_pass_event(dev, type, code, value); | 373 | return; |
| 374 | |||
| 375 | if (disposition & INPUT_PASS_TO_HANDLERS) { | ||
| 376 | struct input_value *v; | ||
| 377 | |||
| 378 | if (disposition & INPUT_SLOT) { | ||
| 379 | v = &dev->vals[dev->num_vals++]; | ||
| 380 | v->type = EV_ABS; | ||
| 381 | v->code = ABS_MT_SLOT; | ||
| 382 | v->value = dev->mt->slot; | ||
| 383 | } | ||
| 384 | |||
| 385 | v = &dev->vals[dev->num_vals++]; | ||
| 386 | v->type = type; | ||
| 387 | v->code = code; | ||
| 388 | v->value = value; | ||
| 389 | } | ||
| 390 | |||
| 391 | if (disposition & INPUT_FLUSH) { | ||
| 392 | if (dev->num_vals >= 2) | ||
| 393 | input_pass_values(dev, dev->vals, dev->num_vals); | ||
| 394 | dev->num_vals = 0; | ||
| 395 | } else if (dev->num_vals >= dev->max_vals - 2) { | ||
| 396 | dev->vals[dev->num_vals++] = input_value_sync; | ||
| 397 | input_pass_values(dev, dev->vals, dev->num_vals); | ||
| 398 | dev->num_vals = 0; | ||
| 399 | } | ||
| 400 | |||
| 328 | } | 401 | } |
| 329 | 402 | ||
| 330 | /** | 403 | /** |
| @@ -352,7 +425,6 @@ void input_event(struct input_dev *dev, | |||
| 352 | if (is_event_supported(type, dev->evbit, EV_MAX)) { | 425 | if (is_event_supported(type, dev->evbit, EV_MAX)) { |
| 353 | 426 | ||
| 354 | spin_lock_irqsave(&dev->event_lock, flags); | 427 | spin_lock_irqsave(&dev->event_lock, flags); |
| 355 | add_input_randomness(type, code, value); | ||
| 356 | input_handle_event(dev, type, code, value); | 428 | input_handle_event(dev, type, code, value); |
| 357 | spin_unlock_irqrestore(&dev->event_lock, flags); | 429 | spin_unlock_irqrestore(&dev->event_lock, flags); |
| 358 | } | 430 | } |
| @@ -831,10 +903,12 @@ int input_set_keycode(struct input_dev *dev, | |||
| 831 | if (test_bit(EV_KEY, dev->evbit) && | 903 | if (test_bit(EV_KEY, dev->evbit) && |
| 832 | !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && | 904 | !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && |
| 833 | __test_and_clear_bit(old_keycode, dev->key)) { | 905 | __test_and_clear_bit(old_keycode, dev->key)) { |
| 906 | struct input_value vals[] = { | ||
| 907 | { EV_KEY, old_keycode, 0 }, | ||
| 908 | input_value_sync | ||
| 909 | }; | ||
| 834 | 910 | ||
| 835 | input_pass_event(dev, EV_KEY, old_keycode, 0); | 911 | input_pass_values(dev, vals, ARRAY_SIZE(vals)); |
| 836 | if (dev->sync) | ||
| 837 | input_pass_event(dev, EV_SYN, SYN_REPORT, 1); | ||
| 838 | } | 912 | } |
| 839 | 913 | ||
| 840 | out: | 914 | out: |
| @@ -1416,6 +1490,7 @@ static void input_dev_release(struct device *device) | |||
| 1416 | input_ff_destroy(dev); | 1490 | input_ff_destroy(dev); |
| 1417 | input_mt_destroy_slots(dev); | 1491 | input_mt_destroy_slots(dev); |
| 1418 | kfree(dev->absinfo); | 1492 | kfree(dev->absinfo); |
| 1493 | kfree(dev->vals); | ||
| 1419 | kfree(dev); | 1494 | kfree(dev); |
| 1420 | 1495 | ||
| 1421 | module_put(THIS_MODULE); | 1496 | module_put(THIS_MODULE); |
| @@ -1751,8 +1826,8 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev) | |||
| 1751 | int i; | 1826 | int i; |
| 1752 | unsigned int events; | 1827 | unsigned int events; |
| 1753 | 1828 | ||
| 1754 | if (dev->mtsize) { | 1829 | if (dev->mt) { |
| 1755 | mt_slots = dev->mtsize; | 1830 | mt_slots = dev->mt->num_slots; |
| 1756 | } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) { | 1831 | } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) { |
| 1757 | mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum - | 1832 | mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum - |
| 1758 | dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1, | 1833 | dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1, |
| @@ -1778,6 +1853,9 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev) | |||
| 1778 | if (test_bit(i, dev->relbit)) | 1853 | if (test_bit(i, dev->relbit)) |
| 1779 | events++; | 1854 | events++; |
| 1780 | 1855 | ||
| 1856 | /* Make room for KEY and MSC events */ | ||
| 1857 | events += 7; | ||
| 1858 | |||
| 1781 | return events; | 1859 | return events; |
| 1782 | } | 1860 | } |
| 1783 | 1861 | ||
| @@ -1816,6 +1894,7 @@ int input_register_device(struct input_dev *dev) | |||
| 1816 | { | 1894 | { |
| 1817 | static atomic_t input_no = ATOMIC_INIT(0); | 1895 | static atomic_t input_no = ATOMIC_INIT(0); |
| 1818 | struct input_handler *handler; | 1896 | struct input_handler *handler; |
| 1897 | unsigned int packet_size; | ||
| 1819 | const char *path; | 1898 | const char *path; |
| 1820 | int error; | 1899 | int error; |
| 1821 | 1900 | ||
| @@ -1828,9 +1907,14 @@ int input_register_device(struct input_dev *dev) | |||
| 1828 | /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ | 1907 | /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ |
| 1829 | input_cleanse_bitmasks(dev); | 1908 | input_cleanse_bitmasks(dev); |
| 1830 | 1909 | ||
| 1831 | if (!dev->hint_events_per_packet) | 1910 | packet_size = input_estimate_events_per_packet(dev); |
| 1832 | dev->hint_events_per_packet = | 1911 | if (dev->hint_events_per_packet < packet_size) |
| 1833 | input_estimate_events_per_packet(dev); | 1912 | dev->hint_events_per_packet = packet_size; |
| 1913 | |||
| 1914 | dev->max_vals = max(dev->hint_events_per_packet, packet_size) + 2; | ||
| 1915 | dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL); | ||
| 1916 | if (!dev->vals) | ||
| 1917 | return -ENOMEM; | ||
| 1834 | 1918 | ||
| 1835 | /* | 1919 | /* |
| 1836 | * If delay and period are pre-set by the driver, then autorepeating | 1920 | * If delay and period are pre-set by the driver, then autorepeating |
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index ce68e361558c..cdc252612c0b 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c | |||
| @@ -516,9 +516,9 @@ static int __devinit imx_keypad_probe(struct platform_device *pdev) | |||
| 516 | input_set_drvdata(input_dev, keypad); | 516 | input_set_drvdata(input_dev, keypad); |
| 517 | 517 | ||
| 518 | /* Ensure that the keypad will stay dormant until opened */ | 518 | /* Ensure that the keypad will stay dormant until opened */ |
| 519 | clk_enable(keypad->clk); | 519 | clk_prepare_enable(keypad->clk); |
| 520 | imx_keypad_inhibit(keypad); | 520 | imx_keypad_inhibit(keypad); |
| 521 | clk_disable(keypad->clk); | 521 | clk_disable_unprepare(keypad->clk); |
| 522 | 522 | ||
| 523 | error = request_irq(irq, imx_keypad_irq_handler, 0, | 523 | error = request_irq(irq, imx_keypad_irq_handler, 0, |
| 524 | pdev->name, keypad); | 524 | pdev->name, keypad); |
diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c index f06231b7cab1..84ec691c05aa 100644 --- a/drivers/input/misc/ab8500-ponkey.c +++ b/drivers/input/misc/ab8500-ponkey.c | |||
| @@ -74,8 +74,8 @@ static int __devinit ab8500_ponkey_probe(struct platform_device *pdev) | |||
| 74 | 74 | ||
| 75 | ponkey->idev = input; | 75 | ponkey->idev = input; |
| 76 | ponkey->ab8500 = ab8500; | 76 | ponkey->ab8500 = ab8500; |
| 77 | ponkey->irq_dbf = ab8500_irq_get_virq(ab8500, irq_dbf); | 77 | ponkey->irq_dbf = irq_dbf; |
| 78 | ponkey->irq_dbr = ab8500_irq_get_virq(ab8500, irq_dbr); | 78 | ponkey->irq_dbr = irq_dbr; |
| 79 | 79 | ||
| 80 | input->name = "AB8500 POn(PowerOn) Key"; | 80 | input->name = "AB8500 POn(PowerOn) Key"; |
| 81 | input->dev.parent = &pdev->dev; | 81 | input->dev.parent = &pdev->dev; |
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 736056897e50..6b1797503e34 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c | |||
| @@ -405,7 +405,7 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu | |||
| 405 | goto exit; | 405 | goto exit; |
| 406 | if (test_bit(ABS_MT_SLOT, dev->absbit)) { | 406 | if (test_bit(ABS_MT_SLOT, dev->absbit)) { |
| 407 | int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1; | 407 | int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1; |
| 408 | input_mt_init_slots(dev, nslot); | 408 | input_mt_init_slots(dev, nslot, 0); |
| 409 | } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { | 409 | } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { |
| 410 | input_set_events_per_packet(dev, 60); | 410 | input_set_events_per_packet(dev, 60); |
| 411 | } | 411 | } |
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 4a1347e91bdc..cf5af1f495ec 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
| @@ -1620,7 +1620,7 @@ int alps_init(struct psmouse *psmouse) | |||
| 1620 | case ALPS_PROTO_V3: | 1620 | case ALPS_PROTO_V3: |
| 1621 | case ALPS_PROTO_V4: | 1621 | case ALPS_PROTO_V4: |
| 1622 | set_bit(INPUT_PROP_SEMI_MT, dev1->propbit); | 1622 | set_bit(INPUT_PROP_SEMI_MT, dev1->propbit); |
| 1623 | input_mt_init_slots(dev1, 2); | 1623 | input_mt_init_slots(dev1, 2, 0); |
| 1624 | input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0); | 1624 | input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0); |
| 1625 | input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0); | 1625 | input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0); |
| 1626 | 1626 | ||
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index d528c23e194f..3a78f235fa3e 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #include <linux/usb/input.h> | 40 | #include <linux/usb/input.h> |
| 41 | #include <linux/hid.h> | 41 | #include <linux/hid.h> |
| 42 | #include <linux/mutex.h> | 42 | #include <linux/mutex.h> |
| 43 | #include <linux/input/mt.h> | ||
| 43 | 44 | ||
| 44 | #define USB_VENDOR_ID_APPLE 0x05ac | 45 | #define USB_VENDOR_ID_APPLE 0x05ac |
| 45 | 46 | ||
| @@ -183,26 +184,26 @@ struct tp_finger { | |||
| 183 | __le16 abs_y; /* absolute y coodinate */ | 184 | __le16 abs_y; /* absolute y coodinate */ |
| 184 | __le16 rel_x; /* relative x coodinate */ | 185 | __le16 rel_x; /* relative x coodinate */ |
| 185 | __le16 rel_y; /* relative y coodinate */ | 186 | __le16 rel_y; /* relative y coodinate */ |
| 186 | __le16 size_major; /* finger size, major axis? */ | 187 | __le16 tool_major; /* tool area, major axis */ |
| 187 | __le16 size_minor; /* finger size, minor axis? */ | 188 | __le16 tool_minor; /* tool area, minor axis */ |
| 188 | __le16 orientation; /* 16384 when point, else 15 bit angle */ | 189 | __le16 orientation; /* 16384 when point, else 15 bit angle */ |
| 189 | __le16 force_major; /* trackpad force, major axis? */ | 190 | __le16 touch_major; /* touch area, major axis */ |
| 190 | __le16 force_minor; /* trackpad force, minor axis? */ | 191 | __le16 touch_minor; /* touch area, minor axis */ |
| 191 | __le16 unused[3]; /* zeros */ | 192 | __le16 unused[3]; /* zeros */ |
| 192 | __le16 multi; /* one finger: varies, more fingers: constant */ | 193 | __le16 multi; /* one finger: varies, more fingers: constant */ |
| 193 | } __attribute__((packed,aligned(2))); | 194 | } __attribute__((packed,aligned(2))); |
| 194 | 195 | ||
| 195 | /* trackpad finger data size, empirically at least ten fingers */ | 196 | /* trackpad finger data size, empirically at least ten fingers */ |
| 197 | #define MAX_FINGERS 16 | ||
| 196 | #define SIZEOF_FINGER sizeof(struct tp_finger) | 198 | #define SIZEOF_FINGER sizeof(struct tp_finger) |
| 197 | #define SIZEOF_ALL_FINGERS (16 * SIZEOF_FINGER) | 199 | #define SIZEOF_ALL_FINGERS (MAX_FINGERS * SIZEOF_FINGER) |
| 198 | #define MAX_FINGER_ORIENTATION 16384 | 200 | #define MAX_FINGER_ORIENTATION 16384 |
| 199 | 201 | ||
| 200 | /* device-specific parameters */ | 202 | /* device-specific parameters */ |
| 201 | struct bcm5974_param { | 203 | struct bcm5974_param { |
| 202 | int dim; /* logical dimension */ | 204 | int snratio; /* signal-to-noise ratio */ |
| 203 | int fuzz; /* logical noise value */ | 205 | int min; /* device minimum reading */ |
| 204 | int devmin; /* device minimum reading */ | 206 | int max; /* device maximum reading */ |
| 205 | int devmax; /* device maximum reading */ | ||
| 206 | }; | 207 | }; |
| 207 | 208 | ||
| 208 | /* device-specific configuration */ | 209 | /* device-specific configuration */ |
| @@ -219,6 +220,7 @@ struct bcm5974_config { | |||
| 219 | struct bcm5974_param w; /* finger width limits */ | 220 | struct bcm5974_param w; /* finger width limits */ |
| 220 | struct bcm5974_param x; /* horizontal limits */ | 221 | struct bcm5974_param x; /* horizontal limits */ |
| 221 | struct bcm5974_param y; /* vertical limits */ | 222 | struct bcm5974_param y; /* vertical limits */ |
| 223 | struct bcm5974_param o; /* orientation limits */ | ||
| 222 | }; | 224 | }; |
| 223 | 225 | ||
| 224 | /* logical device structure */ | 226 | /* logical device structure */ |
| @@ -234,23 +236,16 @@ struct bcm5974 { | |||
| 234 | struct bt_data *bt_data; /* button transferred data */ | 236 | struct bt_data *bt_data; /* button transferred data */ |
| 235 | struct urb *tp_urb; /* trackpad usb request block */ | 237 | struct urb *tp_urb; /* trackpad usb request block */ |
| 236 | u8 *tp_data; /* trackpad transferred data */ | 238 | u8 *tp_data; /* trackpad transferred data */ |
| 237 | int fingers; /* number of fingers on trackpad */ | 239 | const struct tp_finger *index[MAX_FINGERS]; /* finger index data */ |
| 240 | struct input_mt_pos pos[MAX_FINGERS]; /* position array */ | ||
| 241 | int slots[MAX_FINGERS]; /* slot assignments */ | ||
| 238 | }; | 242 | }; |
| 239 | 243 | ||
| 240 | /* logical dimensions */ | ||
| 241 | #define DIM_PRESSURE 256 /* maximum finger pressure */ | ||
| 242 | #define DIM_WIDTH 16 /* maximum finger width */ | ||
| 243 | #define DIM_X 1280 /* maximum trackpad x value */ | ||
| 244 | #define DIM_Y 800 /* maximum trackpad y value */ | ||
| 245 | |||
| 246 | /* logical signal quality */ | 244 | /* logical signal quality */ |
| 247 | #define SN_PRESSURE 45 /* pressure signal-to-noise ratio */ | 245 | #define SN_PRESSURE 45 /* pressure signal-to-noise ratio */ |
| 248 | #define SN_WIDTH 100 /* width signal-to-noise ratio */ | 246 | #define SN_WIDTH 25 /* width signal-to-noise ratio */ |
| 249 | #define SN_COORD 250 /* coordinate signal-to-noise ratio */ | 247 | #define SN_COORD 250 /* coordinate signal-to-noise ratio */ |
| 250 | 248 | #define SN_ORIENT 10 /* orientation signal-to-noise ratio */ | |
| 251 | /* pressure thresholds */ | ||
| 252 | #define PRESSURE_LOW (2 * DIM_PRESSURE / SN_PRESSURE) | ||
| 253 | #define PRESSURE_HIGH (3 * PRESSURE_LOW) | ||
| 254 | 249 | ||
| 255 | /* device constants */ | 250 | /* device constants */ |
| 256 | static const struct bcm5974_config bcm5974_config_table[] = { | 251 | static const struct bcm5974_config bcm5974_config_table[] = { |
| @@ -261,10 +256,11 @@ static const struct bcm5974_config bcm5974_config_table[] = { | |||
| 261 | 0, | 256 | 0, |
| 262 | 0x84, sizeof(struct bt_data), | 257 | 0x84, sizeof(struct bt_data), |
| 263 | 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS, | 258 | 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS, |
| 264 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, | 259 | { SN_PRESSURE, 0, 256 }, |
| 265 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | 260 | { SN_WIDTH, 0, 2048 }, |
| 266 | { DIM_X, DIM_X / SN_COORD, -4824, 5342 }, | 261 | { SN_COORD, -4824, 5342 }, |
| 267 | { DIM_Y, DIM_Y / SN_COORD, -172, 5820 } | 262 | { SN_COORD, -172, 5820 }, |
| 263 | { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } | ||
| 268 | }, | 264 | }, |
| 269 | { | 265 | { |
| 270 | USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, | 266 | USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, |
| @@ -273,10 +269,11 @@ static const struct bcm5974_config bcm5974_config_table[] = { | |||
| 273 | 0, | 269 | 0, |
| 274 | 0x84, sizeof(struct bt_data), | 270 | 0x84, sizeof(struct bt_data), |
| 275 | 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS, | 271 | 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS, |
| 276 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, | 272 | { SN_PRESSURE, 0, 256 }, |
| 277 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | 273 | { SN_WIDTH, 0, 2048 }, |
| 278 | { DIM_X, DIM_X / SN_COORD, -4824, 4824 }, | 274 | { SN_COORD, -4824, 4824 }, |
| 279 | { DIM_Y, DIM_Y / SN_COORD, -172, 4290 } | 275 | { SN_COORD, -172, 4290 }, |
| 276 | { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } | ||
| 280 | }, | 277 | }, |
| 281 | { | 278 | { |
| 282 | USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI, | 279 | USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI, |
| @@ -285,10 +282,11 @@ static const struct bcm5974_config bcm5974_config_table[] = { | |||
| 285 | HAS_INTEGRATED_BUTTON, | 282 | HAS_INTEGRATED_BUTTON, |
| 286 | 0x84, sizeof(struct bt_data), | 283 | 0x84, sizeof(struct bt_data), |
| 287 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, | 284 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, |
| 288 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, | 285 | { SN_PRESSURE, 0, 300 }, |
| 289 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | 286 | { SN_WIDTH, 0, 2048 }, |
| 290 | { DIM_X, DIM_X / SN_COORD, -4460, 5166 }, | 287 | { SN_COORD, -4460, 5166 }, |
| 291 | { DIM_Y, DIM_Y / SN_COORD, -75, 6700 } | 288 | { SN_COORD, -75, 6700 }, |
| 289 | { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } | ||
| 292 | }, | 290 | }, |
| 293 | { | 291 | { |
| 294 | USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI, | 292 | USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI, |
| @@ -297,10 +295,11 @@ static const struct bcm5974_config bcm5974_config_table[] = { | |||
| 297 | HAS_INTEGRATED_BUTTON, | 295 | HAS_INTEGRATED_BUTTON, |
| 298 | 0x84, sizeof(struct bt_data), | 296 | 0x84, sizeof(struct bt_data), |
| 299 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, | 297 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, |
| 300 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, | 298 | { SN_PRESSURE, 0, 300 }, |
| 301 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | 299 | { SN_WIDTH, 0, 2048 }, |
| 302 | { DIM_X, DIM_X / SN_COORD, -4620, 5140 }, | 300 | { SN_COORD, -4620, 5140 }, |
| 303 | { DIM_Y, DIM_Y / SN_COORD, -150, 6600 } | 301 | { SN_COORD, -150, 6600 }, |
| 302 | { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } | ||
| 304 | }, | 303 | }, |
| 305 | { | 304 | { |
| 306 | USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI, | 305 | USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI, |
| @@ -309,10 +308,11 @@ static const struct bcm5974_config bcm5974_config_table[] = { | |||
| 309 | HAS_INTEGRATED_BUTTON, | 308 | HAS_INTEGRATED_BUTTON, |
| 310 | 0x84, sizeof(struct bt_data), | 309 | 0x84, sizeof(struct bt_data), |
| 311 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, | 310 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, |
| 312 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, | 311 | { SN_PRESSURE, 0, 300 }, |
| 313 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | 312 | { SN_WIDTH, 0, 2048 }, |
| 314 | { DIM_X, DIM_X / SN_COORD, -4616, 5112 }, | 313 | { SN_COORD, -4616, 5112 }, |
| 315 | { DIM_Y, DIM_Y / SN_COORD, -142, 5234 } | 314 | { SN_COORD, -142, 5234 }, |
| 315 | { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } | ||
| 316 | }, | 316 | }, |
| 317 | { | 317 | { |
| 318 | USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI, | 318 | USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI, |
| @@ -321,10 +321,11 @@ static const struct bcm5974_config bcm5974_config_table[] = { | |||
| 321 | HAS_INTEGRATED_BUTTON, | 321 | HAS_INTEGRATED_BUTTON, |
| 322 | 0x84, sizeof(struct bt_data), | 322 | 0x84, sizeof(struct bt_data), |
| 323 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, | 323 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, |
| 324 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, | 324 | { SN_PRESSURE, 0, 300 }, |
| 325 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | 325 | { SN_WIDTH, 0, 2048 }, |
| 326 | { DIM_X, DIM_X / SN_COORD, -4415, 5050 }, | 326 | { SN_COORD, -4415, 5050 }, |
| 327 | { DIM_Y, DIM_Y / SN_COORD, -55, 6680 } | 327 | { SN_COORD, -55, 6680 }, |
| 328 | { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } | ||
| 328 | }, | 329 | }, |
| 329 | { | 330 | { |
| 330 | USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI, | 331 | USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI, |
| @@ -333,10 +334,11 @@ static const struct bcm5974_config bcm5974_config_table[] = { | |||
| 333 | HAS_INTEGRATED_BUTTON, | 334 | HAS_INTEGRATED_BUTTON, |
| 334 | 0x84, sizeof(struct bt_data), | 335 | 0x84, sizeof(struct bt_data), |
| 335 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, | 336 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, |
| 336 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, | 337 | { SN_PRESSURE, 0, 300 }, |
| 337 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | 338 | { SN_WIDTH, 0, 2048 }, |
| 338 | { DIM_X, DIM_X / SN_COORD, -4620, 5140 }, | 339 | { SN_COORD, -4620, 5140 }, |
| 339 | { DIM_Y, DIM_Y / SN_COORD, -150, 6600 } | 340 | { SN_COORD, -150, 6600 }, |
| 341 | { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } | ||
| 340 | }, | 342 | }, |
| 341 | { | 343 | { |
| 342 | USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI, | 344 | USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI, |
| @@ -345,10 +347,11 @@ static const struct bcm5974_config bcm5974_config_table[] = { | |||
| 345 | HAS_INTEGRATED_BUTTON, | 347 | HAS_INTEGRATED_BUTTON, |
| 346 | 0x84, sizeof(struct bt_data), | 348 | 0x84, sizeof(struct bt_data), |
| 347 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, | 349 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, |
| 348 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, | 350 | { SN_PRESSURE, 0, 300 }, |
| 349 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | 351 | { SN_WIDTH, 0, 2048 }, |
| 350 | { DIM_X, DIM_X / SN_COORD, -4750, 5280 }, | 352 | { SN_COORD, -4750, 5280 }, |
| 351 | { DIM_Y, DIM_Y / SN_COORD, -150, 6730 } | 353 | { SN_COORD, -150, 6730 }, |
| 354 | { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } | ||
| 352 | }, | 355 | }, |
| 353 | { | 356 | { |
| 354 | USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI, | 357 | USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI, |
| @@ -357,10 +360,11 @@ static const struct bcm5974_config bcm5974_config_table[] = { | |||
| 357 | HAS_INTEGRATED_BUTTON, | 360 | HAS_INTEGRATED_BUTTON, |
| 358 | 0x84, sizeof(struct bt_data), | 361 | 0x84, sizeof(struct bt_data), |
| 359 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, | 362 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, |
| 360 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, | 363 | { SN_PRESSURE, 0, 300 }, |
| 361 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | 364 | { SN_WIDTH, 0, 2048 }, |
| 362 | { DIM_X, DIM_X / SN_COORD, -4620, 5140 }, | 365 | { SN_COORD, -4620, 5140 }, |
| 363 | { DIM_Y, DIM_Y / SN_COORD, -150, 6600 } | 366 | { SN_COORD, -150, 6600 }, |
| 367 | { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } | ||
| 364 | }, | 368 | }, |
| 365 | { | 369 | { |
| 366 | USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI, | 370 | USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI, |
| @@ -369,10 +373,11 @@ static const struct bcm5974_config bcm5974_config_table[] = { | |||
| 369 | HAS_INTEGRATED_BUTTON, | 373 | HAS_INTEGRATED_BUTTON, |
| 370 | 0x84, sizeof(struct bt_data), | 374 | 0x84, sizeof(struct bt_data), |
| 371 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, | 375 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, |
| 372 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, | 376 | { SN_PRESSURE, 0, 300 }, |
| 373 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | 377 | { SN_WIDTH, 0, 2048 }, |
| 374 | { DIM_X, DIM_X / SN_COORD, -4750, 5280 }, | 378 | { SN_COORD, -4750, 5280 }, |
| 375 | { DIM_Y, DIM_Y / SN_COORD, -150, 6730 } | 379 | { SN_COORD, -150, 6730 }, |
| 380 | { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } | ||
| 376 | }, | 381 | }, |
| 377 | {} | 382 | {} |
| 378 | }; | 383 | }; |
| @@ -396,18 +401,11 @@ static inline int raw2int(__le16 x) | |||
| 396 | return (signed short)le16_to_cpu(x); | 401 | return (signed short)le16_to_cpu(x); |
| 397 | } | 402 | } |
| 398 | 403 | ||
| 399 | /* scale device data to logical dimensions (asserts devmin < devmax) */ | 404 | static void set_abs(struct input_dev *input, unsigned int code, |
| 400 | static inline int int2scale(const struct bcm5974_param *p, int x) | 405 | const struct bcm5974_param *p) |
| 401 | { | ||
| 402 | return x * p->dim / (p->devmax - p->devmin); | ||
| 403 | } | ||
| 404 | |||
| 405 | /* all logical value ranges are [0,dim). */ | ||
| 406 | static inline int int2bound(const struct bcm5974_param *p, int x) | ||
| 407 | { | 406 | { |
| 408 | int s = int2scale(p, x); | 407 | int fuzz = p->snratio ? (p->max - p->min) / p->snratio : 0; |
| 409 | 408 | input_set_abs_params(input, code, p->min, p->max, fuzz, 0); | |
| 410 | return clamp_val(s, 0, p->dim - 1); | ||
| 411 | } | 409 | } |
| 412 | 410 | ||
| 413 | /* setup which logical events to report */ | 411 | /* setup which logical events to report */ |
| @@ -416,48 +414,30 @@ static void setup_events_to_report(struct input_dev *input_dev, | |||
| 416 | { | 414 | { |
| 417 | __set_bit(EV_ABS, input_dev->evbit); | 415 | __set_bit(EV_ABS, input_dev->evbit); |
| 418 | 416 | ||
| 419 | input_set_abs_params(input_dev, ABS_PRESSURE, | 417 | /* for synaptics only */ |
| 420 | 0, cfg->p.dim, cfg->p.fuzz, 0); | 418 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 256, 5, 0); |
| 421 | input_set_abs_params(input_dev, ABS_TOOL_WIDTH, | 419 | input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 16, 0, 0); |
| 422 | 0, cfg->w.dim, cfg->w.fuzz, 0); | ||
| 423 | input_set_abs_params(input_dev, ABS_X, | ||
| 424 | 0, cfg->x.dim, cfg->x.fuzz, 0); | ||
| 425 | input_set_abs_params(input_dev, ABS_Y, | ||
| 426 | 0, cfg->y.dim, cfg->y.fuzz, 0); | ||
| 427 | 420 | ||
| 428 | /* finger touch area */ | 421 | /* finger touch area */ |
| 429 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, | 422 | set_abs(input_dev, ABS_MT_TOUCH_MAJOR, &cfg->w); |
| 430 | cfg->w.devmin, cfg->w.devmax, 0, 0); | 423 | set_abs(input_dev, ABS_MT_TOUCH_MINOR, &cfg->w); |
| 431 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, | ||
| 432 | cfg->w.devmin, cfg->w.devmax, 0, 0); | ||
| 433 | /* finger approach area */ | 424 | /* finger approach area */ |
| 434 | input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, | 425 | set_abs(input_dev, ABS_MT_WIDTH_MAJOR, &cfg->w); |
| 435 | cfg->w.devmin, cfg->w.devmax, 0, 0); | 426 | set_abs(input_dev, ABS_MT_WIDTH_MINOR, &cfg->w); |
| 436 | input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR, | ||
| 437 | cfg->w.devmin, cfg->w.devmax, 0, 0); | ||
| 438 | /* finger orientation */ | 427 | /* finger orientation */ |
| 439 | input_set_abs_params(input_dev, ABS_MT_ORIENTATION, | 428 | set_abs(input_dev, ABS_MT_ORIENTATION, &cfg->o); |
| 440 | -MAX_FINGER_ORIENTATION, | ||
| 441 | MAX_FINGER_ORIENTATION, 0, 0); | ||
| 442 | /* finger position */ | 429 | /* finger position */ |
| 443 | input_set_abs_params(input_dev, ABS_MT_POSITION_X, | 430 | set_abs(input_dev, ABS_MT_POSITION_X, &cfg->x); |
| 444 | cfg->x.devmin, cfg->x.devmax, 0, 0); | 431 | set_abs(input_dev, ABS_MT_POSITION_Y, &cfg->y); |
| 445 | input_set_abs_params(input_dev, ABS_MT_POSITION_Y, | ||
| 446 | cfg->y.devmin, cfg->y.devmax, 0, 0); | ||
| 447 | 432 | ||
| 448 | __set_bit(EV_KEY, input_dev->evbit); | 433 | __set_bit(EV_KEY, input_dev->evbit); |
| 449 | __set_bit(BTN_TOUCH, input_dev->keybit); | ||
| 450 | __set_bit(BTN_TOOL_FINGER, input_dev->keybit); | ||
| 451 | __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); | ||
| 452 | __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); | ||
| 453 | __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit); | ||
| 454 | __set_bit(BTN_LEFT, input_dev->keybit); | 434 | __set_bit(BTN_LEFT, input_dev->keybit); |
| 455 | 435 | ||
| 456 | __set_bit(INPUT_PROP_POINTER, input_dev->propbit); | ||
| 457 | if (cfg->caps & HAS_INTEGRATED_BUTTON) | 436 | if (cfg->caps & HAS_INTEGRATED_BUTTON) |
| 458 | __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit); | 437 | __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit); |
| 459 | 438 | ||
| 460 | input_set_events_per_packet(input_dev, 60); | 439 | input_mt_init_slots(input_dev, MAX_FINGERS, |
| 440 | INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK); | ||
| 461 | } | 441 | } |
| 462 | 442 | ||
| 463 | /* report button data as logical button state */ | 443 | /* report button data as logical button state */ |
| @@ -477,24 +457,44 @@ static int report_bt_state(struct bcm5974 *dev, int size) | |||
| 477 | return 0; | 457 | return 0; |
| 478 | } | 458 | } |
| 479 | 459 | ||
| 480 | static void report_finger_data(struct input_dev *input, | 460 | static void report_finger_data(struct input_dev *input, int slot, |
| 481 | const struct bcm5974_config *cfg, | 461 | const struct input_mt_pos *pos, |
| 482 | const struct tp_finger *f) | 462 | const struct tp_finger *f) |
| 483 | { | 463 | { |
| 464 | input_mt_slot(input, slot); | ||
| 465 | input_mt_report_slot_state(input, MT_TOOL_FINGER, true); | ||
| 466 | |||
| 484 | input_report_abs(input, ABS_MT_TOUCH_MAJOR, | 467 | input_report_abs(input, ABS_MT_TOUCH_MAJOR, |
| 485 | raw2int(f->force_major) << 1); | 468 | raw2int(f->touch_major) << 1); |
| 486 | input_report_abs(input, ABS_MT_TOUCH_MINOR, | 469 | input_report_abs(input, ABS_MT_TOUCH_MINOR, |
| 487 | raw2int(f->force_minor) << 1); | 470 | raw2int(f->touch_minor) << 1); |
| 488 | input_report_abs(input, ABS_MT_WIDTH_MAJOR, | 471 | input_report_abs(input, ABS_MT_WIDTH_MAJOR, |
| 489 | raw2int(f->size_major) << 1); | 472 | raw2int(f->tool_major) << 1); |
| 490 | input_report_abs(input, ABS_MT_WIDTH_MINOR, | 473 | input_report_abs(input, ABS_MT_WIDTH_MINOR, |
| 491 | raw2int(f->size_minor) << 1); | 474 | raw2int(f->tool_minor) << 1); |
| 492 | input_report_abs(input, ABS_MT_ORIENTATION, | 475 | input_report_abs(input, ABS_MT_ORIENTATION, |
| 493 | MAX_FINGER_ORIENTATION - raw2int(f->orientation)); | 476 | MAX_FINGER_ORIENTATION - raw2int(f->orientation)); |
| 494 | input_report_abs(input, ABS_MT_POSITION_X, raw2int(f->abs_x)); | 477 | input_report_abs(input, ABS_MT_POSITION_X, pos->x); |
| 495 | input_report_abs(input, ABS_MT_POSITION_Y, | 478 | input_report_abs(input, ABS_MT_POSITION_Y, pos->y); |
| 496 | cfg->y.devmin + cfg->y.devmax - raw2int(f->abs_y)); | 479 | } |
| 497 | input_mt_sync(input); | 480 | |
| 481 | static void report_synaptics_data(struct input_dev *input, | ||
| 482 | const struct bcm5974_config *cfg, | ||
| 483 | const struct tp_finger *f, int raw_n) | ||
| 484 | { | ||
| 485 | int abs_p = 0, abs_w = 0; | ||
| 486 | |||
| 487 | if (raw_n) { | ||
| 488 | int p = raw2int(f->touch_major); | ||
| 489 | int w = raw2int(f->tool_major); | ||
| 490 | if (p > 0 && raw2int(f->origin)) { | ||
| 491 | abs_p = clamp_val(256 * p / cfg->p.max, 0, 255); | ||
| 492 | abs_w = clamp_val(16 * w / cfg->w.max, 0, 15); | ||
| 493 | } | ||
| 494 | } | ||
| 495 | |||
| 496 | input_report_abs(input, ABS_PRESSURE, abs_p); | ||
| 497 | input_report_abs(input, ABS_TOOL_WIDTH, abs_w); | ||
| 498 | } | 498 | } |
| 499 | 499 | ||
| 500 | /* report trackpad data as logical trackpad state */ | 500 | /* report trackpad data as logical trackpad state */ |
| @@ -503,9 +503,7 @@ static int report_tp_state(struct bcm5974 *dev, int size) | |||
| 503 | const struct bcm5974_config *c = &dev->cfg; | 503 | const struct bcm5974_config *c = &dev->cfg; |
| 504 | const struct tp_finger *f; | 504 | const struct tp_finger *f; |
| 505 | struct input_dev *input = dev->input; | 505 | struct input_dev *input = dev->input; |
| 506 | int raw_p, raw_w, raw_x, raw_y, raw_n, i; | 506 | int raw_n, i, n = 0; |
| 507 | int ptest, origin, ibt = 0, nmin = 0, nmax = 0; | ||
| 508 | int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0; | ||
| 509 | 507 | ||
| 510 | if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0) | 508 | if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0) |
| 511 | return -EIO; | 509 | return -EIO; |
| @@ -514,76 +512,29 @@ static int report_tp_state(struct bcm5974 *dev, int size) | |||
| 514 | f = (const struct tp_finger *)(dev->tp_data + c->tp_offset); | 512 | f = (const struct tp_finger *)(dev->tp_data + c->tp_offset); |
| 515 | raw_n = (size - c->tp_offset) / SIZEOF_FINGER; | 513 | raw_n = (size - c->tp_offset) / SIZEOF_FINGER; |
| 516 | 514 | ||
| 517 | /* always track the first finger; when detached, start over */ | 515 | for (i = 0; i < raw_n; i++) { |
| 518 | if (raw_n) { | 516 | if (raw2int(f[i].touch_major) == 0) |
| 519 | 517 | continue; | |
| 520 | /* report raw trackpad data */ | 518 | dev->pos[n].x = raw2int(f[i].abs_x); |
| 521 | for (i = 0; i < raw_n; i++) | 519 | dev->pos[n].y = c->y.min + c->y.max - raw2int(f[i].abs_y); |
| 522 | report_finger_data(input, c, &f[i]); | 520 | dev->index[n++] = &f[i]; |
| 523 | |||
| 524 | raw_p = raw2int(f->force_major); | ||
| 525 | raw_w = raw2int(f->size_major); | ||
| 526 | raw_x = raw2int(f->abs_x); | ||
| 527 | raw_y = raw2int(f->abs_y); | ||
| 528 | |||
| 529 | dprintk(9, | ||
| 530 | "bcm5974: " | ||
| 531 | "raw: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n", | ||
| 532 | raw_p, raw_w, raw_x, raw_y, raw_n); | ||
| 533 | |||
| 534 | ptest = int2bound(&c->p, raw_p); | ||
| 535 | origin = raw2int(f->origin); | ||
| 536 | |||
| 537 | /* while tracking finger still valid, count all fingers */ | ||
| 538 | if (ptest > PRESSURE_LOW && origin) { | ||
| 539 | abs_p = ptest; | ||
| 540 | abs_w = int2bound(&c->w, raw_w); | ||
| 541 | abs_x = int2bound(&c->x, raw_x - c->x.devmin); | ||
| 542 | abs_y = int2bound(&c->y, c->y.devmax - raw_y); | ||
| 543 | while (raw_n--) { | ||
| 544 | ptest = int2bound(&c->p, | ||
| 545 | raw2int(f->force_major)); | ||
| 546 | if (ptest > PRESSURE_LOW) | ||
| 547 | nmax++; | ||
| 548 | if (ptest > PRESSURE_HIGH) | ||
| 549 | nmin++; | ||
| 550 | f++; | ||
| 551 | } | ||
| 552 | } | ||
| 553 | } | 521 | } |
| 554 | 522 | ||
| 555 | /* set the integrated button if applicable */ | 523 | input_mt_assign_slots(input, dev->slots, dev->pos, n); |
| 556 | if (c->tp_type == TYPE2) | ||
| 557 | ibt = raw2int(dev->tp_data[BUTTON_TYPE2]); | ||
| 558 | |||
| 559 | if (dev->fingers < nmin) | ||
| 560 | dev->fingers = nmin; | ||
| 561 | if (dev->fingers > nmax) | ||
| 562 | dev->fingers = nmax; | ||
| 563 | |||
| 564 | input_report_key(input, BTN_TOUCH, dev->fingers > 0); | ||
| 565 | input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1); | ||
| 566 | input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2); | ||
| 567 | input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers == 3); | ||
| 568 | input_report_key(input, BTN_TOOL_QUADTAP, dev->fingers > 3); | ||
| 569 | |||
| 570 | input_report_abs(input, ABS_PRESSURE, abs_p); | ||
| 571 | input_report_abs(input, ABS_TOOL_WIDTH, abs_w); | ||
| 572 | 524 | ||
| 573 | if (abs_p) { | 525 | for (i = 0; i < n; i++) |
| 574 | input_report_abs(input, ABS_X, abs_x); | 526 | report_finger_data(input, dev->slots[i], |
| 575 | input_report_abs(input, ABS_Y, abs_y); | 527 | &dev->pos[i], dev->index[i]); |
| 576 | 528 | ||
| 577 | dprintk(8, | 529 | input_mt_sync_frame(input); |
| 578 | "bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d " | ||
| 579 | "nmin: %d nmax: %d n: %d ibt: %d\n", abs_p, abs_w, | ||
| 580 | abs_x, abs_y, nmin, nmax, dev->fingers, ibt); | ||
| 581 | 530 | ||
| 582 | } | 531 | report_synaptics_data(input, c, f, raw_n); |
| 583 | 532 | ||
| 584 | /* type 2 reports button events via ibt only */ | 533 | /* type 2 reports button events via ibt only */ |
| 585 | if (c->tp_type == TYPE2) | 534 | if (c->tp_type == TYPE2) { |
| 535 | int ibt = raw2int(dev->tp_data[BUTTON_TYPE2]); | ||
| 586 | input_report_key(input, BTN_LEFT, ibt); | 536 | input_report_key(input, BTN_LEFT, ibt); |
| 537 | } | ||
| 587 | 538 | ||
| 588 | input_sync(input); | 539 | input_sync(input); |
| 589 | 540 | ||
| @@ -742,9 +693,11 @@ static int bcm5974_start_traffic(struct bcm5974 *dev) | |||
| 742 | goto err_out; | 693 | goto err_out; |
| 743 | } | 694 | } |
| 744 | 695 | ||
| 745 | error = usb_submit_urb(dev->bt_urb, GFP_KERNEL); | 696 | if (dev->bt_urb) { |
| 746 | if (error) | 697 | error = usb_submit_urb(dev->bt_urb, GFP_KERNEL); |
| 747 | goto err_reset_mode; | 698 | if (error) |
| 699 | goto err_reset_mode; | ||
| 700 | } | ||
| 748 | 701 | ||
| 749 | error = usb_submit_urb(dev->tp_urb, GFP_KERNEL); | 702 | error = usb_submit_urb(dev->tp_urb, GFP_KERNEL); |
| 750 | if (error) | 703 | if (error) |
| @@ -868,19 +821,23 @@ static int bcm5974_probe(struct usb_interface *iface, | |||
| 868 | mutex_init(&dev->pm_mutex); | 821 | mutex_init(&dev->pm_mutex); |
| 869 | 822 | ||
| 870 | /* setup urbs */ | 823 | /* setup urbs */ |
| 871 | dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL); | 824 | if (cfg->tp_type == TYPE1) { |
| 872 | if (!dev->bt_urb) | 825 | dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL); |
| 873 | goto err_free_devs; | 826 | if (!dev->bt_urb) |
| 827 | goto err_free_devs; | ||
| 828 | } | ||
| 874 | 829 | ||
| 875 | dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL); | 830 | dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL); |
| 876 | if (!dev->tp_urb) | 831 | if (!dev->tp_urb) |
| 877 | goto err_free_bt_urb; | 832 | goto err_free_bt_urb; |
| 878 | 833 | ||
| 879 | dev->bt_data = usb_alloc_coherent(dev->udev, | 834 | if (dev->bt_urb) { |
| 835 | dev->bt_data = usb_alloc_coherent(dev->udev, | ||
| 880 | dev->cfg.bt_datalen, GFP_KERNEL, | 836 | dev->cfg.bt_datalen, GFP_KERNEL, |
| 881 | &dev->bt_urb->transfer_dma); | 837 | &dev->bt_urb->transfer_dma); |
| 882 | if (!dev->bt_data) | 838 | if (!dev->bt_data) |
| 883 | goto err_free_urb; | 839 | goto err_free_urb; |
| 840 | } | ||
| 884 | 841 | ||
| 885 | dev->tp_data = usb_alloc_coherent(dev->udev, | 842 | dev->tp_data = usb_alloc_coherent(dev->udev, |
| 886 | dev->cfg.tp_datalen, GFP_KERNEL, | 843 | dev->cfg.tp_datalen, GFP_KERNEL, |
| @@ -888,10 +845,11 @@ static int bcm5974_probe(struct usb_interface *iface, | |||
| 888 | if (!dev->tp_data) | 845 | if (!dev->tp_data) |
| 889 | goto err_free_bt_buffer; | 846 | goto err_free_bt_buffer; |
| 890 | 847 | ||
| 891 | usb_fill_int_urb(dev->bt_urb, udev, | 848 | if (dev->bt_urb) |
| 892 | usb_rcvintpipe(udev, cfg->bt_ep), | 849 | usb_fill_int_urb(dev->bt_urb, udev, |
| 893 | dev->bt_data, dev->cfg.bt_datalen, | 850 | usb_rcvintpipe(udev, cfg->bt_ep), |
| 894 | bcm5974_irq_button, dev, 1); | 851 | dev->bt_data, dev->cfg.bt_datalen, |
| 852 | bcm5974_irq_button, dev, 1); | ||
| 895 | 853 | ||
| 896 | usb_fill_int_urb(dev->tp_urb, udev, | 854 | usb_fill_int_urb(dev->tp_urb, udev, |
| 897 | usb_rcvintpipe(udev, cfg->tp_ep), | 855 | usb_rcvintpipe(udev, cfg->tp_ep), |
| @@ -929,8 +887,9 @@ err_free_buffer: | |||
| 929 | usb_free_coherent(dev->udev, dev->cfg.tp_datalen, | 887 | usb_free_coherent(dev->udev, dev->cfg.tp_datalen, |
| 930 | dev->tp_data, dev->tp_urb->transfer_dma); | 888 | dev->tp_data, dev->tp_urb->transfer_dma); |
| 931 | err_free_bt_buffer: | 889 | err_free_bt_buffer: |
| 932 | usb_free_coherent(dev->udev, dev->cfg.bt_datalen, | 890 | if (dev->bt_urb) |
| 933 | dev->bt_data, dev->bt_urb->transfer_dma); | 891 | usb_free_coherent(dev->udev, dev->cfg.bt_datalen, |
| 892 | dev->bt_data, dev->bt_urb->transfer_dma); | ||
| 934 | err_free_urb: | 893 | err_free_urb: |
| 935 | usb_free_urb(dev->tp_urb); | 894 | usb_free_urb(dev->tp_urb); |
| 936 | err_free_bt_urb: | 895 | err_free_bt_urb: |
| @@ -951,8 +910,9 @@ static void bcm5974_disconnect(struct usb_interface *iface) | |||
| 951 | input_unregister_device(dev->input); | 910 | input_unregister_device(dev->input); |
| 952 | usb_free_coherent(dev->udev, dev->cfg.tp_datalen, | 911 | usb_free_coherent(dev->udev, dev->cfg.tp_datalen, |
| 953 | dev->tp_data, dev->tp_urb->transfer_dma); | 912 | dev->tp_data, dev->tp_urb->transfer_dma); |
| 954 | usb_free_coherent(dev->udev, dev->cfg.bt_datalen, | 913 | if (dev->bt_urb) |
| 955 | dev->bt_data, dev->bt_urb->transfer_dma); | 914 | usb_free_coherent(dev->udev, dev->cfg.bt_datalen, |
| 915 | dev->bt_data, dev->bt_urb->transfer_dma); | ||
| 956 | usb_free_urb(dev->tp_urb); | 916 | usb_free_urb(dev->tp_urb); |
| 957 | usb_free_urb(dev->bt_urb); | 917 | usb_free_urb(dev->bt_urb); |
| 958 | kfree(dev); | 918 | kfree(dev); |
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 479011004a11..1e8e42fb03a4 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c | |||
| @@ -1004,7 +1004,7 @@ static int elantech_set_input_params(struct psmouse *psmouse) | |||
| 1004 | input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, | 1004 | input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, |
| 1005 | ETP_WMAX_V2, 0, 0); | 1005 | ETP_WMAX_V2, 0, 0); |
| 1006 | } | 1006 | } |
| 1007 | input_mt_init_slots(dev, 2); | 1007 | input_mt_init_slots(dev, 2, 0); |
| 1008 | input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); | 1008 | input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); |
| 1009 | input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); | 1009 | input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); |
| 1010 | break; | 1010 | break; |
| @@ -1035,7 +1035,7 @@ static int elantech_set_input_params(struct psmouse *psmouse) | |||
| 1035 | input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, | 1035 | input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, |
| 1036 | ETP_WMAX_V2, 0, 0); | 1036 | ETP_WMAX_V2, 0, 0); |
| 1037 | /* Multitouch capable pad, up to 5 fingers. */ | 1037 | /* Multitouch capable pad, up to 5 fingers. */ |
| 1038 | input_mt_init_slots(dev, ETP_MAX_FINGERS); | 1038 | input_mt_init_slots(dev, ETP_MAX_FINGERS, 0); |
| 1039 | input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); | 1039 | input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); |
| 1040 | input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); | 1040 | input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); |
| 1041 | input_abs_set_res(dev, ABS_MT_POSITION_X, x_res); | 1041 | input_abs_set_res(dev, ABS_MT_POSITION_X, x_res); |
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c index 3f5649f19082..e582922bacf7 100644 --- a/drivers/input/mouse/sentelic.c +++ b/drivers/input/mouse/sentelic.c | |||
| @@ -721,6 +721,17 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) | |||
| 721 | 721 | ||
| 722 | switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) { | 722 | switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) { |
| 723 | case FSP_PKT_TYPE_ABS: | 723 | case FSP_PKT_TYPE_ABS: |
| 724 | |||
| 725 | if ((packet[0] == 0x48 || packet[0] == 0x49) && | ||
| 726 | packet[1] == 0 && packet[2] == 0) { | ||
| 727 | /* | ||
| 728 | * Ignore coordinate noise when finger leaving the | ||
| 729 | * surface, otherwise cursor may jump to upper-left | ||
| 730 | * corner. | ||
| 731 | */ | ||
| 732 | packet[3] &= 0xf0; | ||
| 733 | } | ||
| 734 | |||
| 724 | abs_x = GET_ABS_X(packet); | 735 | abs_x = GET_ABS_X(packet); |
| 725 | abs_y = GET_ABS_Y(packet); | 736 | abs_y = GET_ABS_Y(packet); |
| 726 | 737 | ||
| @@ -960,7 +971,7 @@ static int fsp_set_input_params(struct psmouse *psmouse) | |||
| 960 | 971 | ||
| 961 | input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0); | 972 | input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0); |
| 962 | input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0); | 973 | input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0); |
| 963 | input_mt_init_slots(dev, 2); | 974 | input_mt_init_slots(dev, 2, 0); |
| 964 | input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0); | 975 | input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0); |
| 965 | input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0); | 976 | input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0); |
| 966 | } | 977 | } |
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 14eaecea2b70..37033ade79d3 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c | |||
| @@ -1232,7 +1232,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) | |||
| 1232 | input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); | 1232 | input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); |
| 1233 | 1233 | ||
| 1234 | if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { | 1234 | if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { |
| 1235 | input_mt_init_slots(dev, 2); | 1235 | input_mt_init_slots(dev, 2, 0); |
| 1236 | set_abs_position_params(dev, priv, ABS_MT_POSITION_X, | 1236 | set_abs_position_params(dev, priv, ABS_MT_POSITION_X, |
| 1237 | ABS_MT_POSITION_Y); | 1237 | ABS_MT_POSITION_Y); |
| 1238 | /* Image sensors can report per-contact pressure */ | 1238 | /* Image sensors can report per-contact pressure */ |
| @@ -1244,7 +1244,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) | |||
| 1244 | } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { | 1244 | } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { |
| 1245 | /* Non-image sensors with AGM use semi-mt */ | 1245 | /* Non-image sensors with AGM use semi-mt */ |
| 1246 | __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); | 1246 | __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); |
| 1247 | input_mt_init_slots(dev, 2); | 1247 | input_mt_init_slots(dev, 2, 0); |
| 1248 | set_abs_position_params(dev, priv, ABS_MT_POSITION_X, | 1248 | set_abs_position_params(dev, priv, ABS_MT_POSITION_X, |
| 1249 | ABS_MT_POSITION_Y); | 1249 | ABS_MT_POSITION_Y); |
| 1250 | } | 1250 | } |
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 2ffd110bd5bc..2e77246c2e5a 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c | |||
| @@ -72,7 +72,7 @@ static int amba_kmi_open(struct serio *io) | |||
| 72 | unsigned int divisor; | 72 | unsigned int divisor; |
| 73 | int ret; | 73 | int ret; |
| 74 | 74 | ||
| 75 | ret = clk_enable(kmi->clk); | 75 | ret = clk_prepare_enable(kmi->clk); |
| 76 | if (ret) | 76 | if (ret) |
| 77 | goto out; | 77 | goto out; |
| 78 | 78 | ||
| @@ -92,7 +92,7 @@ static int amba_kmi_open(struct serio *io) | |||
| 92 | return 0; | 92 | return 0; |
| 93 | 93 | ||
| 94 | clk_disable: | 94 | clk_disable: |
| 95 | clk_disable(kmi->clk); | 95 | clk_disable_unprepare(kmi->clk); |
| 96 | out: | 96 | out: |
| 97 | return ret; | 97 | return ret; |
| 98 | } | 98 | } |
| @@ -104,7 +104,7 @@ static void amba_kmi_close(struct serio *io) | |||
| 104 | writeb(0, KMICR); | 104 | writeb(0, KMICR); |
| 105 | 105 | ||
| 106 | free_irq(kmi->irq, kmi); | 106 | free_irq(kmi->irq, kmi); |
| 107 | clk_disable(kmi->clk); | 107 | clk_disable_unprepare(kmi->clk); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | static int __devinit amba_kmi_probe(struct amba_device *dev, | 110 | static int __devinit amba_kmi_probe(struct amba_device *dev, |
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 6918773ce024..d6cc77a53c7e 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h | |||
| @@ -335,6 +335,12 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { | |||
| 335 | }, | 335 | }, |
| 336 | { | 336 | { |
| 337 | .matches = { | 337 | .matches = { |
| 338 | DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | ||
| 339 | DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE C850D"), | ||
| 340 | }, | ||
| 341 | }, | ||
| 342 | { | ||
| 343 | .matches = { | ||
| 338 | DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), | 344 | DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), |
| 339 | DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"), | 345 | DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"), |
| 340 | }, | 346 | }, |
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 532d067a9e07..2a81ce375f75 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c | |||
| @@ -1530,7 +1530,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, | |||
| 1530 | __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); | 1530 | __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); |
| 1531 | __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit); | 1531 | __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit); |
| 1532 | 1532 | ||
| 1533 | input_mt_init_slots(input_dev, features->touch_max); | 1533 | input_mt_init_slots(input_dev, features->touch_max, 0); |
| 1534 | 1534 | ||
| 1535 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, | 1535 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, |
| 1536 | 0, 255, 0, 0); | 1536 | 0, 255, 0, 0); |
| @@ -1575,7 +1575,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, | |||
| 1575 | 1575 | ||
| 1576 | case TABLETPC2FG: | 1576 | case TABLETPC2FG: |
| 1577 | if (features->device_type == BTN_TOOL_FINGER) { | 1577 | if (features->device_type == BTN_TOOL_FINGER) { |
| 1578 | input_mt_init_slots(input_dev, features->touch_max); | 1578 | input_mt_init_slots(input_dev, features->touch_max, 0); |
| 1579 | input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, | 1579 | input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, |
| 1580 | 0, MT_TOOL_MAX, 0, 0); | 1580 | 0, MT_TOOL_MAX, 0, 0); |
| 1581 | input_set_abs_params(input_dev, ABS_MT_POSITION_X, | 1581 | input_set_abs_params(input_dev, ABS_MT_POSITION_X, |
| @@ -1631,7 +1631,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, | |||
| 1631 | 1631 | ||
| 1632 | __set_bit(BTN_TOOL_FINGER, input_dev->keybit); | 1632 | __set_bit(BTN_TOOL_FINGER, input_dev->keybit); |
| 1633 | __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); | 1633 | __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); |
| 1634 | input_mt_init_slots(input_dev, features->touch_max); | 1634 | input_mt_init_slots(input_dev, features->touch_max, 0); |
| 1635 | 1635 | ||
| 1636 | if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { | 1636 | if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { |
| 1637 | __set_bit(BTN_TOOL_TRIPLETAP, | 1637 | __set_bit(BTN_TOOL_TRIPLETAP, |
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 4623cc69fc60..e92615d0b1b0 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c | |||
| @@ -1152,7 +1152,7 @@ static int __devinit mxt_probe(struct i2c_client *client, | |||
| 1152 | 1152 | ||
| 1153 | /* For multi touch */ | 1153 | /* For multi touch */ |
| 1154 | num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1; | 1154 | num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1; |
| 1155 | error = input_mt_init_slots(input_dev, num_mt_slots); | 1155 | error = input_mt_init_slots(input_dev, num_mt_slots, 0); |
| 1156 | if (error) | 1156 | if (error) |
| 1157 | goto err_free_object; | 1157 | goto err_free_object; |
| 1158 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, | 1158 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, |
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c index f030d9ec795d..8e60437ac85b 100644 --- a/drivers/input/touchscreen/cyttsp_core.c +++ b/drivers/input/touchscreen/cyttsp_core.c | |||
| @@ -571,7 +571,7 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, | |||
| 571 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, | 571 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, |
| 572 | 0, CY_MAXZ, 0, 0); | 572 | 0, CY_MAXZ, 0, 0); |
| 573 | 573 | ||
| 574 | input_mt_init_slots(input_dev, CY_MAX_ID); | 574 | input_mt_init_slots(input_dev, CY_MAX_ID, 0); |
| 575 | 575 | ||
| 576 | error = request_threaded_irq(ts->irq, NULL, cyttsp_irq, | 576 | error = request_threaded_irq(ts->irq, NULL, cyttsp_irq, |
| 577 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 577 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index b06a5e3a665e..099d144ab7c9 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c | |||
| @@ -566,9 +566,12 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, | |||
| 566 | } | 566 | } |
| 567 | 567 | ||
| 568 | read = min_t(size_t, count, tsdata->raw_bufsize - *off); | 568 | read = min_t(size_t, count, tsdata->raw_bufsize - *off); |
| 569 | error = copy_to_user(buf, tsdata->raw_buffer + *off, read); | 569 | if (copy_to_user(buf, tsdata->raw_buffer + *off, read)) { |
| 570 | if (!error) | 570 | error = -EFAULT; |
| 571 | *off += read; | 571 | goto out; |
| 572 | } | ||
| 573 | |||
| 574 | *off += read; | ||
| 572 | out: | 575 | out: |
| 573 | mutex_unlock(&tsdata->mutex); | 576 | mutex_unlock(&tsdata->mutex); |
| 574 | return error ?: read; | 577 | return error ?: read; |
| @@ -779,7 +782,7 @@ static int __devinit edt_ft5x06_ts_probe(struct i2c_client *client, | |||
| 779 | 0, tsdata->num_x * 64 - 1, 0, 0); | 782 | 0, tsdata->num_x * 64 - 1, 0, 0); |
| 780 | input_set_abs_params(input, ABS_MT_POSITION_Y, | 783 | input_set_abs_params(input, ABS_MT_POSITION_Y, |
| 781 | 0, tsdata->num_y * 64 - 1, 0, 0); | 784 | 0, tsdata->num_y * 64 - 1, 0, 0); |
| 782 | error = input_mt_init_slots(input, MAX_SUPPORT_POINTS); | 785 | error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0); |
| 783 | if (error) { | 786 | if (error) { |
| 784 | dev_err(&client->dev, "Unable to init MT slots.\n"); | 787 | dev_err(&client->dev, "Unable to init MT slots.\n"); |
| 785 | goto err_free_mem; | 788 | goto err_free_mem; |
diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index 70524dd34f42..c1e3460f1195 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c | |||
| @@ -204,7 +204,7 @@ static int __devinit egalax_ts_probe(struct i2c_client *client, | |||
| 204 | ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0); | 204 | ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0); |
| 205 | input_set_abs_params(input_dev, | 205 | input_set_abs_params(input_dev, |
| 206 | ABS_MT_POSITION_X, 0, EGALAX_MAX_Y, 0, 0); | 206 | ABS_MT_POSITION_X, 0, EGALAX_MAX_Y, 0, 0); |
| 207 | input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS); | 207 | input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS, 0); |
| 208 | 208 | ||
| 209 | input_set_drvdata(input_dev, ts); | 209 | input_set_drvdata(input_dev, ts); |
| 210 | 210 | ||
diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index c0044175a921..4ac69760ec08 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c | |||
| @@ -252,7 +252,7 @@ static int __devinit ili210x_i2c_probe(struct i2c_client *client, | |||
| 252 | input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0); | 252 | input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0); |
| 253 | 253 | ||
| 254 | /* Multi touch */ | 254 | /* Multi touch */ |
| 255 | input_mt_init_slots(input, MAX_TOUCHES); | 255 | input_mt_init_slots(input, MAX_TOUCHES, 0); |
| 256 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0); | 256 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0); |
| 257 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0); | 257 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0); |
| 258 | 258 | ||
diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 49c44bbf548d..560cf09d1c5a 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c | |||
| @@ -404,7 +404,7 @@ static int __devinit mms114_probe(struct i2c_client *client, | |||
| 404 | input_set_abs_params(input_dev, ABS_Y, 0, data->pdata->y_size, 0, 0); | 404 | input_set_abs_params(input_dev, ABS_Y, 0, data->pdata->y_size, 0, 0); |
| 405 | 405 | ||
| 406 | /* For multi touch */ | 406 | /* For multi touch */ |
| 407 | input_mt_init_slots(input_dev, MMS114_MAX_TOUCH); | 407 | input_mt_init_slots(input_dev, MMS114_MAX_TOUCH, 0); |
| 408 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, | 408 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, |
| 409 | 0, MMS114_MAX_AREA, 0, 0); | 409 | 0, MMS114_MAX_AREA, 0, 0); |
| 410 | input_set_abs_params(input_dev, ABS_MT_POSITION_X, | 410 | input_set_abs_params(input_dev, ABS_MT_POSITION_X, |
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c index 4ccde45b9da2..b49f0b836925 100644 --- a/drivers/input/touchscreen/penmount.c +++ b/drivers/input/touchscreen/penmount.c | |||
| @@ -264,7 +264,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) | |||
| 264 | input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0); | 264 | input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0); |
| 265 | 265 | ||
| 266 | if (pm->maxcontacts > 1) { | 266 | if (pm->maxcontacts > 1) { |
| 267 | input_mt_init_slots(pm->dev, pm->maxcontacts); | 267 | input_mt_init_slots(pm->dev, pm->maxcontacts, 0); |
| 268 | input_set_abs_params(pm->dev, | 268 | input_set_abs_params(pm->dev, |
| 269 | ABS_MT_POSITION_X, 0, max_x, 0, 0); | 269 | ABS_MT_POSITION_X, 0, max_x, 0, 0); |
| 270 | input_set_abs_params(pm->dev, | 270 | input_set_abs_params(pm->dev, |
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index e32709e0dd65..721fdb3597ca 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c | |||
| @@ -304,6 +304,45 @@ static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt) | |||
| 304 | #define EGALAX_PKT_TYPE_REPT 0x80 | 304 | #define EGALAX_PKT_TYPE_REPT 0x80 |
| 305 | #define EGALAX_PKT_TYPE_DIAG 0x0A | 305 | #define EGALAX_PKT_TYPE_DIAG 0x0A |
| 306 | 306 | ||
| 307 | static int egalax_init(struct usbtouch_usb *usbtouch) | ||
| 308 | { | ||
| 309 | int ret, i; | ||
| 310 | unsigned char *buf; | ||
| 311 | struct usb_device *udev = interface_to_usbdev(usbtouch->interface); | ||
| 312 | |||
| 313 | /* | ||
| 314 | * An eGalax diagnostic packet kicks the device into using the right | ||
| 315 | * protocol. We send a "check active" packet. The response will be | ||
| 316 | * read later and ignored. | ||
| 317 | */ | ||
| 318 | |||
| 319 | buf = kmalloc(3, GFP_KERNEL); | ||
| 320 | if (!buf) | ||
| 321 | return -ENOMEM; | ||
| 322 | |||
| 323 | buf[0] = EGALAX_PKT_TYPE_DIAG; | ||
| 324 | buf[1] = 1; /* length */ | ||
| 325 | buf[2] = 'A'; /* command - check active */ | ||
| 326 | |||
| 327 | for (i = 0; i < 3; i++) { | ||
| 328 | ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
| 329 | 0, | ||
| 330 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
| 331 | 0, 0, buf, 3, | ||
| 332 | USB_CTRL_SET_TIMEOUT); | ||
| 333 | if (ret >= 0) { | ||
| 334 | ret = 0; | ||
| 335 | break; | ||
| 336 | } | ||
| 337 | if (ret != -EPIPE) | ||
| 338 | break; | ||
| 339 | } | ||
| 340 | |||
| 341 | kfree(buf); | ||
| 342 | |||
| 343 | return ret; | ||
| 344 | } | ||
| 345 | |||
| 307 | static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt) | 346 | static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt) |
| 308 | { | 347 | { |
| 309 | if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT) | 348 | if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT) |
| @@ -1056,6 +1095,7 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { | |||
| 1056 | .process_pkt = usbtouch_process_multi, | 1095 | .process_pkt = usbtouch_process_multi, |
| 1057 | .get_pkt_len = egalax_get_pkt_len, | 1096 | .get_pkt_len = egalax_get_pkt_len, |
| 1058 | .read_data = egalax_read_data, | 1097 | .read_data = egalax_read_data, |
| 1098 | .init = egalax_init, | ||
| 1059 | }, | 1099 | }, |
| 1060 | #endif | 1100 | #endif |
| 1061 | 1101 | ||
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 8f9ad2f893b8..9a83be6b6584 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c | |||
| @@ -471,7 +471,7 @@ static int w8001_setup(struct w8001 *w8001) | |||
| 471 | case 5: | 471 | case 5: |
| 472 | w8001->pktlen = W8001_PKTLEN_TOUCH2FG; | 472 | w8001->pktlen = W8001_PKTLEN_TOUCH2FG; |
| 473 | 473 | ||
| 474 | input_mt_init_slots(dev, 2); | 474 | input_mt_init_slots(dev, 2, 0); |
| 475 | input_set_abs_params(dev, ABS_MT_POSITION_X, | 475 | input_set_abs_params(dev, ABS_MT_POSITION_X, |
| 476 | 0, touch.x, 0, 0); | 476 | 0, touch.x, 0, 0); |
| 477 | input_set_abs_params(dev, ABS_MT_POSITION_Y, | 477 | input_set_abs_params(dev, ABS_MT_POSITION_Y, |
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index b64502dfa9f4..e89daf1b21b4 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c | |||
| @@ -266,7 +266,7 @@ static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to) | |||
| 266 | 266 | ||
| 267 | static int iommu_init_device(struct device *dev) | 267 | static int iommu_init_device(struct device *dev) |
| 268 | { | 268 | { |
| 269 | struct pci_dev *dma_pdev, *pdev = to_pci_dev(dev); | 269 | struct pci_dev *dma_pdev = NULL, *pdev = to_pci_dev(dev); |
| 270 | struct iommu_dev_data *dev_data; | 270 | struct iommu_dev_data *dev_data; |
| 271 | struct iommu_group *group; | 271 | struct iommu_group *group; |
| 272 | u16 alias; | 272 | u16 alias; |
| @@ -293,7 +293,9 @@ static int iommu_init_device(struct device *dev) | |||
| 293 | dev_data->alias_data = alias_data; | 293 | dev_data->alias_data = alias_data; |
| 294 | 294 | ||
| 295 | dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff); | 295 | dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff); |
| 296 | } else | 296 | } |
| 297 | |||
| 298 | if (dma_pdev == NULL) | ||
| 297 | dma_pdev = pci_dev_get(pdev); | 299 | dma_pdev = pci_dev_get(pdev); |
| 298 | 300 | ||
| 299 | /* Account for quirked devices */ | 301 | /* Account for quirked devices */ |
diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c index fa6ca4733725..dceaec821b0e 100644 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ b/drivers/isdn/hardware/mISDN/avmfritz.c | |||
| @@ -857,8 +857,9 @@ avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | |||
| 857 | switch (cmd) { | 857 | switch (cmd) { |
| 858 | case CLOSE_CHANNEL: | 858 | case CLOSE_CHANNEL: |
| 859 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | 859 | test_and_clear_bit(FLG_OPEN, &bch->Flags); |
| 860 | cancel_work_sync(&bch->workq); | ||
| 860 | spin_lock_irqsave(&fc->lock, flags); | 861 | spin_lock_irqsave(&fc->lock, flags); |
| 861 | mISDN_freebchannel(bch); | 862 | mISDN_clear_bchannel(bch); |
| 862 | modehdlc(bch, ISDN_P_NONE); | 863 | modehdlc(bch, ISDN_P_NONE); |
| 863 | spin_unlock_irqrestore(&fc->lock, flags); | 864 | spin_unlock_irqrestore(&fc->lock, flags); |
| 864 | ch->protocol = ISDN_P_NONE; | 865 | ch->protocol = ISDN_P_NONE; |
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 5e402cf2e795..f02794203bb1 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c | |||
| @@ -5059,6 +5059,7 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev, | |||
| 5059 | printk(KERN_INFO | 5059 | printk(KERN_INFO |
| 5060 | "HFC-E1 #%d has overlapping B-channels on fragment #%d\n", | 5060 | "HFC-E1 #%d has overlapping B-channels on fragment #%d\n", |
| 5061 | E1_cnt + 1, pt); | 5061 | E1_cnt + 1, pt); |
| 5062 | kfree(hc); | ||
| 5062 | return -EINVAL; | 5063 | return -EINVAL; |
| 5063 | } | 5064 | } |
| 5064 | maskcheck |= hc->bmask[pt]; | 5065 | maskcheck |= hc->bmask[pt]; |
| @@ -5086,6 +5087,7 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev, | |||
| 5086 | if ((poll >> 1) > sizeof(hc->silence_data)) { | 5087 | if ((poll >> 1) > sizeof(hc->silence_data)) { |
| 5087 | printk(KERN_ERR "HFCMULTI error: silence_data too small, " | 5088 | printk(KERN_ERR "HFCMULTI error: silence_data too small, " |
| 5088 | "please fix\n"); | 5089 | "please fix\n"); |
| 5090 | kfree(hc); | ||
| 5089 | return -EINVAL; | 5091 | return -EINVAL; |
| 5090 | } | 5092 | } |
| 5091 | for (i = 0; i < (poll >> 1); i++) | 5093 | for (i = 0; i < (poll >> 1); i++) |
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c index 752e0825591f..ccd7d851be26 100644 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c | |||
| @@ -1406,8 +1406,9 @@ hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | |||
| 1406 | switch (cmd) { | 1406 | switch (cmd) { |
| 1407 | case CLOSE_CHANNEL: | 1407 | case CLOSE_CHANNEL: |
| 1408 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | 1408 | test_and_clear_bit(FLG_OPEN, &bch->Flags); |
| 1409 | cancel_work_sync(&bch->workq); | ||
| 1409 | spin_lock_irqsave(hx->ip->hwlock, flags); | 1410 | spin_lock_irqsave(hx->ip->hwlock, flags); |
| 1410 | mISDN_freebchannel(bch); | 1411 | mISDN_clear_bchannel(bch); |
| 1411 | hscx_mode(hx, ISDN_P_NONE); | 1412 | hscx_mode(hx, ISDN_P_NONE); |
| 1412 | spin_unlock_irqrestore(hx->ip->hwlock, flags); | 1413 | spin_unlock_irqrestore(hx->ip->hwlock, flags); |
| 1413 | ch->protocol = ISDN_P_NONE; | 1414 | ch->protocol = ISDN_P_NONE; |
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c index be5973ded6d6..182ecf0626c2 100644 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c | |||
| @@ -1588,8 +1588,9 @@ isar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | |||
| 1588 | switch (cmd) { | 1588 | switch (cmd) { |
| 1589 | case CLOSE_CHANNEL: | 1589 | case CLOSE_CHANNEL: |
| 1590 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | 1590 | test_and_clear_bit(FLG_OPEN, &bch->Flags); |
| 1591 | cancel_work_sync(&bch->workq); | ||
| 1591 | spin_lock_irqsave(ich->is->hwlock, flags); | 1592 | spin_lock_irqsave(ich->is->hwlock, flags); |
| 1592 | mISDN_freebchannel(bch); | 1593 | mISDN_clear_bchannel(bch); |
| 1593 | modeisar(ich, ISDN_P_NONE); | 1594 | modeisar(ich, ISDN_P_NONE); |
| 1594 | spin_unlock_irqrestore(ich->is->hwlock, flags); | 1595 | spin_unlock_irqrestore(ich->is->hwlock, flags); |
| 1595 | ch->protocol = ISDN_P_NONE; | 1596 | ch->protocol = ISDN_P_NONE; |
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index c3e3e7686273..9bcade59eb73 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c | |||
| @@ -812,8 +812,9 @@ nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | |||
| 812 | switch (cmd) { | 812 | switch (cmd) { |
| 813 | case CLOSE_CHANNEL: | 813 | case CLOSE_CHANNEL: |
| 814 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | 814 | test_and_clear_bit(FLG_OPEN, &bch->Flags); |
| 815 | cancel_work_sync(&bch->workq); | ||
| 815 | spin_lock_irqsave(&card->lock, flags); | 816 | spin_lock_irqsave(&card->lock, flags); |
| 816 | mISDN_freebchannel(bch); | 817 | mISDN_clear_bchannel(bch); |
| 817 | mode_tiger(bc, ISDN_P_NONE); | 818 | mode_tiger(bc, ISDN_P_NONE); |
| 818 | spin_unlock_irqrestore(&card->lock, flags); | 819 | spin_unlock_irqrestore(&card->lock, flags); |
| 819 | ch->protocol = ISDN_P_NONE; | 820 | ch->protocol = ISDN_P_NONE; |
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index 26a86b846099..335fe6455002 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c | |||
| @@ -1054,8 +1054,9 @@ w6692_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | |||
| 1054 | switch (cmd) { | 1054 | switch (cmd) { |
| 1055 | case CLOSE_CHANNEL: | 1055 | case CLOSE_CHANNEL: |
| 1056 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | 1056 | test_and_clear_bit(FLG_OPEN, &bch->Flags); |
| 1057 | cancel_work_sync(&bch->workq); | ||
| 1057 | spin_lock_irqsave(&card->lock, flags); | 1058 | spin_lock_irqsave(&card->lock, flags); |
| 1058 | mISDN_freebchannel(bch); | 1059 | mISDN_clear_bchannel(bch); |
| 1059 | w6692_mode(bc, ISDN_P_NONE); | 1060 | w6692_mode(bc, ISDN_P_NONE); |
| 1060 | spin_unlock_irqrestore(&card->lock, flags); | 1061 | spin_unlock_irqrestore(&card->lock, flags); |
| 1061 | ch->protocol = ISDN_P_NONE; | 1062 | ch->protocol = ISDN_P_NONE; |
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index ef34fd40867c..2602be23f341 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c | |||
| @@ -148,17 +148,16 @@ mISDN_clear_bchannel(struct bchannel *ch) | |||
| 148 | ch->next_minlen = ch->init_minlen; | 148 | ch->next_minlen = ch->init_minlen; |
| 149 | ch->maxlen = ch->init_maxlen; | 149 | ch->maxlen = ch->init_maxlen; |
| 150 | ch->next_maxlen = ch->init_maxlen; | 150 | ch->next_maxlen = ch->init_maxlen; |
| 151 | skb_queue_purge(&ch->rqueue); | ||
| 152 | ch->rcount = 0; | ||
| 151 | } | 153 | } |
| 152 | EXPORT_SYMBOL(mISDN_clear_bchannel); | 154 | EXPORT_SYMBOL(mISDN_clear_bchannel); |
| 153 | 155 | ||
| 154 | int | 156 | void |
| 155 | mISDN_freebchannel(struct bchannel *ch) | 157 | mISDN_freebchannel(struct bchannel *ch) |
| 156 | { | 158 | { |
| 159 | cancel_work_sync(&ch->workq); | ||
| 157 | mISDN_clear_bchannel(ch); | 160 | mISDN_clear_bchannel(ch); |
| 158 | skb_queue_purge(&ch->rqueue); | ||
| 159 | ch->rcount = 0; | ||
| 160 | flush_work_sync(&ch->workq); | ||
| 161 | return 0; | ||
| 162 | } | 161 | } |
| 163 | EXPORT_SYMBOL(mISDN_freebchannel); | 162 | EXPORT_SYMBOL(mISDN_freebchannel); |
| 164 | 163 | ||
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index 39809035320a..4af12e1844d5 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c | |||
| @@ -203,8 +203,8 @@ void lguest_arch_run_guest(struct lg_cpu *cpu) | |||
| 203 | * we set it now, so we can trap and pass that trap to the Guest if it | 203 | * we set it now, so we can trap and pass that trap to the Guest if it |
| 204 | * uses the FPU. | 204 | * uses the FPU. |
| 205 | */ | 205 | */ |
| 206 | if (cpu->ts) | 206 | if (cpu->ts && user_has_fpu()) |
| 207 | unlazy_fpu(current); | 207 | stts(); |
| 208 | 208 | ||
| 209 | /* | 209 | /* |
| 210 | * SYSENTER is an optimized way of doing system calls. We can't allow | 210 | * SYSENTER is an optimized way of doing system calls. We can't allow |
| @@ -234,6 +234,10 @@ void lguest_arch_run_guest(struct lg_cpu *cpu) | |||
| 234 | if (boot_cpu_has(X86_FEATURE_SEP)) | 234 | if (boot_cpu_has(X86_FEATURE_SEP)) |
| 235 | wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0); | 235 | wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0); |
| 236 | 236 | ||
| 237 | /* Clear the host TS bit if it was set above. */ | ||
| 238 | if (cpu->ts && user_has_fpu()) | ||
| 239 | clts(); | ||
| 240 | |||
| 237 | /* | 241 | /* |
| 238 | * If the Guest page faulted, then the cr2 register will tell us the | 242 | * If the Guest page faulted, then the cr2 register will tell us the |
| 239 | * bad virtual address. We have to grab this now, because once we | 243 | * bad virtual address. We have to grab this now, because once we |
| @@ -249,7 +253,7 @@ void lguest_arch_run_guest(struct lg_cpu *cpu) | |||
| 249 | * a different CPU. So all the critical stuff should be done | 253 | * a different CPU. So all the critical stuff should be done |
| 250 | * before this. | 254 | * before this. |
| 251 | */ | 255 | */ |
| 252 | else if (cpu->regs->trapnum == 7) | 256 | else if (cpu->regs->trapnum == 7 && !user_has_fpu()) |
| 253 | math_state_restore(); | 257 | math_state_restore(); |
| 254 | } | 258 | } |
| 255 | 259 | ||
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index d8abb90a6c2f..034233eefc82 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
| @@ -1555,6 +1555,7 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, | |||
| 1555 | unsigned long arg) | 1555 | unsigned long arg) |
| 1556 | { | 1556 | { |
| 1557 | struct multipath *m = ti->private; | 1557 | struct multipath *m = ti->private; |
| 1558 | struct pgpath *pgpath; | ||
| 1558 | struct block_device *bdev; | 1559 | struct block_device *bdev; |
| 1559 | fmode_t mode; | 1560 | fmode_t mode; |
| 1560 | unsigned long flags; | 1561 | unsigned long flags; |
| @@ -1570,12 +1571,14 @@ again: | |||
| 1570 | if (!m->current_pgpath) | 1571 | if (!m->current_pgpath) |
| 1571 | __choose_pgpath(m, 0); | 1572 | __choose_pgpath(m, 0); |
| 1572 | 1573 | ||
| 1573 | if (m->current_pgpath) { | 1574 | pgpath = m->current_pgpath; |
| 1574 | bdev = m->current_pgpath->path.dev->bdev; | 1575 | |
| 1575 | mode = m->current_pgpath->path.dev->mode; | 1576 | if (pgpath) { |
| 1577 | bdev = pgpath->path.dev->bdev; | ||
| 1578 | mode = pgpath->path.dev->mode; | ||
| 1576 | } | 1579 | } |
| 1577 | 1580 | ||
| 1578 | if (m->queue_io) | 1581 | if ((pgpath && m->queue_io) || (!pgpath && m->queue_if_no_path)) |
| 1579 | r = -EAGAIN; | 1582 | r = -EAGAIN; |
| 1580 | else if (!bdev) | 1583 | else if (!bdev) |
| 1581 | r = -EIO; | 1584 | r = -EIO; |
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index f90069029aae..100368eb7991 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c | |||
| @@ -1212,6 +1212,41 @@ struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector) | |||
| 1212 | return &t->targets[(KEYS_PER_NODE * n) + k]; | 1212 | return &t->targets[(KEYS_PER_NODE * n) + k]; |
| 1213 | } | 1213 | } |
| 1214 | 1214 | ||
| 1215 | static int count_device(struct dm_target *ti, struct dm_dev *dev, | ||
| 1216 | sector_t start, sector_t len, void *data) | ||
| 1217 | { | ||
| 1218 | unsigned *num_devices = data; | ||
| 1219 | |||
| 1220 | (*num_devices)++; | ||
| 1221 | |||
| 1222 | return 0; | ||
| 1223 | } | ||
| 1224 | |||
| 1225 | /* | ||
| 1226 | * Check whether a table has no data devices attached using each | ||
| 1227 | * target's iterate_devices method. | ||
| 1228 | * Returns false if the result is unknown because a target doesn't | ||
| 1229 | * support iterate_devices. | ||
| 1230 | */ | ||
| 1231 | bool dm_table_has_no_data_devices(struct dm_table *table) | ||
| 1232 | { | ||
| 1233 | struct dm_target *uninitialized_var(ti); | ||
| 1234 | unsigned i = 0, num_devices = 0; | ||
| 1235 | |||
| 1236 | while (i < dm_table_get_num_targets(table)) { | ||
| 1237 | ti = dm_table_get_target(table, i++); | ||
| 1238 | |||
| 1239 | if (!ti->type->iterate_devices) | ||
| 1240 | return false; | ||
| 1241 | |||
| 1242 | ti->type->iterate_devices(ti, count_device, &num_devices); | ||
| 1243 | if (num_devices) | ||
| 1244 | return false; | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | return true; | ||
| 1248 | } | ||
| 1249 | |||
| 1215 | /* | 1250 | /* |
| 1216 | * Establish the new table's queue_limits and validate them. | 1251 | * Establish the new table's queue_limits and validate them. |
| 1217 | */ | 1252 | */ |
| @@ -1354,17 +1389,25 @@ static int device_is_nonrot(struct dm_target *ti, struct dm_dev *dev, | |||
| 1354 | return q && blk_queue_nonrot(q); | 1389 | return q && blk_queue_nonrot(q); |
| 1355 | } | 1390 | } |
| 1356 | 1391 | ||
| 1357 | static bool dm_table_is_nonrot(struct dm_table *t) | 1392 | static int device_is_not_random(struct dm_target *ti, struct dm_dev *dev, |
| 1393 | sector_t start, sector_t len, void *data) | ||
| 1394 | { | ||
| 1395 | struct request_queue *q = bdev_get_queue(dev->bdev); | ||
| 1396 | |||
| 1397 | return q && !blk_queue_add_random(q); | ||
| 1398 | } | ||
| 1399 | |||
| 1400 | static bool dm_table_all_devices_attribute(struct dm_table *t, | ||
| 1401 | iterate_devices_callout_fn func) | ||
| 1358 | { | 1402 | { |
| 1359 | struct dm_target *ti; | 1403 | struct dm_target *ti; |
| 1360 | unsigned i = 0; | 1404 | unsigned i = 0; |
| 1361 | 1405 | ||
| 1362 | /* Ensure that all underlying device are non-rotational. */ | ||
| 1363 | while (i < dm_table_get_num_targets(t)) { | 1406 | while (i < dm_table_get_num_targets(t)) { |
| 1364 | ti = dm_table_get_target(t, i++); | 1407 | ti = dm_table_get_target(t, i++); |
| 1365 | 1408 | ||
| 1366 | if (!ti->type->iterate_devices || | 1409 | if (!ti->type->iterate_devices || |
| 1367 | !ti->type->iterate_devices(ti, device_is_nonrot, NULL)) | 1410 | !ti->type->iterate_devices(ti, func, NULL)) |
| 1368 | return 0; | 1411 | return 0; |
| 1369 | } | 1412 | } |
| 1370 | 1413 | ||
| @@ -1396,7 +1439,8 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, | |||
| 1396 | if (!dm_table_discard_zeroes_data(t)) | 1439 | if (!dm_table_discard_zeroes_data(t)) |
| 1397 | q->limits.discard_zeroes_data = 0; | 1440 | q->limits.discard_zeroes_data = 0; |
| 1398 | 1441 | ||
| 1399 | if (dm_table_is_nonrot(t)) | 1442 | /* Ensure that all underlying devices are non-rotational. */ |
| 1443 | if (dm_table_all_devices_attribute(t, device_is_nonrot)) | ||
| 1400 | queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q); | 1444 | queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q); |
| 1401 | else | 1445 | else |
| 1402 | queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, q); | 1446 | queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, q); |
| @@ -1404,6 +1448,15 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, | |||
| 1404 | dm_table_set_integrity(t); | 1448 | dm_table_set_integrity(t); |
| 1405 | 1449 | ||
| 1406 | /* | 1450 | /* |
| 1451 | * Determine whether or not this queue's I/O timings contribute | ||
| 1452 | * to the entropy pool, Only request-based targets use this. | ||
| 1453 | * Clear QUEUE_FLAG_ADD_RANDOM if any underlying device does not | ||
| 1454 | * have it set. | ||
| 1455 | */ | ||
| 1456 | if (blk_queue_add_random(q) && dm_table_all_devices_attribute(t, device_is_not_random)) | ||
| 1457 | queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, q); | ||
| 1458 | |||
| 1459 | /* | ||
| 1407 | * QUEUE_FLAG_STACKABLE must be set after all queue settings are | 1460 | * QUEUE_FLAG_STACKABLE must be set after all queue settings are |
| 1408 | * visible to other CPUs because, once the flag is set, incoming bios | 1461 | * visible to other CPUs because, once the flag is set, incoming bios |
| 1409 | * are processed by request-based dm, which refers to the queue | 1462 | * are processed by request-based dm, which refers to the queue |
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index af1fc3b2c2ad..c29410af1e22 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c | |||
| @@ -509,9 +509,9 @@ enum pool_mode { | |||
| 509 | struct pool_features { | 509 | struct pool_features { |
| 510 | enum pool_mode mode; | 510 | enum pool_mode mode; |
| 511 | 511 | ||
| 512 | unsigned zero_new_blocks:1; | 512 | bool zero_new_blocks:1; |
| 513 | unsigned discard_enabled:1; | 513 | bool discard_enabled:1; |
| 514 | unsigned discard_passdown:1; | 514 | bool discard_passdown:1; |
| 515 | }; | 515 | }; |
| 516 | 516 | ||
| 517 | struct thin_c; | 517 | struct thin_c; |
| @@ -580,7 +580,8 @@ struct pool_c { | |||
| 580 | struct dm_target_callbacks callbacks; | 580 | struct dm_target_callbacks callbacks; |
| 581 | 581 | ||
| 582 | dm_block_t low_water_blocks; | 582 | dm_block_t low_water_blocks; |
| 583 | struct pool_features pf; | 583 | struct pool_features requested_pf; /* Features requested during table load */ |
| 584 | struct pool_features adjusted_pf; /* Features used after adjusting for constituent devices */ | ||
| 584 | }; | 585 | }; |
| 585 | 586 | ||
| 586 | /* | 587 | /* |
| @@ -1839,6 +1840,47 @@ static void __requeue_bios(struct pool *pool) | |||
| 1839 | /*---------------------------------------------------------------- | 1840 | /*---------------------------------------------------------------- |
| 1840 | * Binding of control targets to a pool object | 1841 | * Binding of control targets to a pool object |
| 1841 | *--------------------------------------------------------------*/ | 1842 | *--------------------------------------------------------------*/ |
| 1843 | static bool data_dev_supports_discard(struct pool_c *pt) | ||
| 1844 | { | ||
| 1845 | struct request_queue *q = bdev_get_queue(pt->data_dev->bdev); | ||
| 1846 | |||
| 1847 | return q && blk_queue_discard(q); | ||
| 1848 | } | ||
| 1849 | |||
| 1850 | /* | ||
| 1851 | * If discard_passdown was enabled verify that the data device | ||
| 1852 | * supports discards. Disable discard_passdown if not. | ||
| 1853 | */ | ||
| 1854 | static void disable_passdown_if_not_supported(struct pool_c *pt) | ||
| 1855 | { | ||
| 1856 | struct pool *pool = pt->pool; | ||
| 1857 | struct block_device *data_bdev = pt->data_dev->bdev; | ||
| 1858 | struct queue_limits *data_limits = &bdev_get_queue(data_bdev)->limits; | ||
| 1859 | sector_t block_size = pool->sectors_per_block << SECTOR_SHIFT; | ||
| 1860 | const char *reason = NULL; | ||
| 1861 | char buf[BDEVNAME_SIZE]; | ||
| 1862 | |||
| 1863 | if (!pt->adjusted_pf.discard_passdown) | ||
| 1864 | return; | ||
| 1865 | |||
| 1866 | if (!data_dev_supports_discard(pt)) | ||
| 1867 | reason = "discard unsupported"; | ||
| 1868 | |||
| 1869 | else if (data_limits->max_discard_sectors < pool->sectors_per_block) | ||
| 1870 | reason = "max discard sectors smaller than a block"; | ||
| 1871 | |||
| 1872 | else if (data_limits->discard_granularity > block_size) | ||
| 1873 | reason = "discard granularity larger than a block"; | ||
| 1874 | |||
| 1875 | else if (block_size & (data_limits->discard_granularity - 1)) | ||
| 1876 | reason = "discard granularity not a factor of block size"; | ||
| 1877 | |||
| 1878 | if (reason) { | ||
| 1879 | DMWARN("Data device (%s) %s: Disabling discard passdown.", bdevname(data_bdev, buf), reason); | ||
| 1880 | pt->adjusted_pf.discard_passdown = false; | ||
| 1881 | } | ||
| 1882 | } | ||
| 1883 | |||
| 1842 | static int bind_control_target(struct pool *pool, struct dm_target *ti) | 1884 | static int bind_control_target(struct pool *pool, struct dm_target *ti) |
| 1843 | { | 1885 | { |
| 1844 | struct pool_c *pt = ti->private; | 1886 | struct pool_c *pt = ti->private; |
| @@ -1847,31 +1889,16 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti) | |||
| 1847 | * We want to make sure that degraded pools are never upgraded. | 1889 | * We want to make sure that degraded pools are never upgraded. |
| 1848 | */ | 1890 | */ |
| 1849 | enum pool_mode old_mode = pool->pf.mode; | 1891 | enum pool_mode old_mode = pool->pf.mode; |
| 1850 | enum pool_mode new_mode = pt->pf.mode; | 1892 | enum pool_mode new_mode = pt->adjusted_pf.mode; |
| 1851 | 1893 | ||
| 1852 | if (old_mode > new_mode) | 1894 | if (old_mode > new_mode) |
| 1853 | new_mode = old_mode; | 1895 | new_mode = old_mode; |
| 1854 | 1896 | ||
| 1855 | pool->ti = ti; | 1897 | pool->ti = ti; |
| 1856 | pool->low_water_blocks = pt->low_water_blocks; | 1898 | pool->low_water_blocks = pt->low_water_blocks; |
| 1857 | pool->pf = pt->pf; | 1899 | pool->pf = pt->adjusted_pf; |
| 1858 | set_pool_mode(pool, new_mode); | ||
| 1859 | 1900 | ||
| 1860 | /* | 1901 | set_pool_mode(pool, new_mode); |
| 1861 | * If discard_passdown was enabled verify that the data device | ||
| 1862 | * supports discards. Disable discard_passdown if not; otherwise | ||
| 1863 | * -EOPNOTSUPP will be returned. | ||
| 1864 | */ | ||
| 1865 | /* FIXME: pull this out into a sep fn. */ | ||
| 1866 | if (pt->pf.discard_passdown) { | ||
| 1867 | struct request_queue *q = bdev_get_queue(pt->data_dev->bdev); | ||
| 1868 | if (!q || !blk_queue_discard(q)) { | ||
| 1869 | char buf[BDEVNAME_SIZE]; | ||
| 1870 | DMWARN("Discard unsupported by data device (%s): Disabling discard passdown.", | ||
| 1871 | bdevname(pt->data_dev->bdev, buf)); | ||
| 1872 | pool->pf.discard_passdown = 0; | ||
| 1873 | } | ||
| 1874 | } | ||
| 1875 | 1902 | ||
| 1876 | return 0; | 1903 | return 0; |
| 1877 | } | 1904 | } |
| @@ -1889,9 +1916,9 @@ static void unbind_control_target(struct pool *pool, struct dm_target *ti) | |||
| 1889 | static void pool_features_init(struct pool_features *pf) | 1916 | static void pool_features_init(struct pool_features *pf) |
| 1890 | { | 1917 | { |
| 1891 | pf->mode = PM_WRITE; | 1918 | pf->mode = PM_WRITE; |
| 1892 | pf->zero_new_blocks = 1; | 1919 | pf->zero_new_blocks = true; |
| 1893 | pf->discard_enabled = 1; | 1920 | pf->discard_enabled = true; |
| 1894 | pf->discard_passdown = 1; | 1921 | pf->discard_passdown = true; |
| 1895 | } | 1922 | } |
| 1896 | 1923 | ||
| 1897 | static void __pool_destroy(struct pool *pool) | 1924 | static void __pool_destroy(struct pool *pool) |
| @@ -2119,13 +2146,13 @@ static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf, | |||
| 2119 | argc--; | 2146 | argc--; |
| 2120 | 2147 | ||
| 2121 | if (!strcasecmp(arg_name, "skip_block_zeroing")) | 2148 | if (!strcasecmp(arg_name, "skip_block_zeroing")) |
| 2122 | pf->zero_new_blocks = 0; | 2149 | pf->zero_new_blocks = false; |
| 2123 | 2150 | ||
| 2124 | else if (!strcasecmp(arg_name, "ignore_discard")) | 2151 | else if (!strcasecmp(arg_name, "ignore_discard")) |
| 2125 | pf->discard_enabled = 0; | 2152 | pf->discard_enabled = false; |
| 2126 | 2153 | ||
| 2127 | else if (!strcasecmp(arg_name, "no_discard_passdown")) | 2154 | else if (!strcasecmp(arg_name, "no_discard_passdown")) |
| 2128 | pf->discard_passdown = 0; | 2155 | pf->discard_passdown = false; |
| 2129 | 2156 | ||
| 2130 | else if (!strcasecmp(arg_name, "read_only")) | 2157 | else if (!strcasecmp(arg_name, "read_only")) |
| 2131 | pf->mode = PM_READ_ONLY; | 2158 | pf->mode = PM_READ_ONLY; |
| @@ -2259,8 +2286,9 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv) | |||
| 2259 | pt->metadata_dev = metadata_dev; | 2286 | pt->metadata_dev = metadata_dev; |
| 2260 | pt->data_dev = data_dev; | 2287 | pt->data_dev = data_dev; |
| 2261 | pt->low_water_blocks = low_water_blocks; | 2288 | pt->low_water_blocks = low_water_blocks; |
| 2262 | pt->pf = pf; | 2289 | pt->adjusted_pf = pt->requested_pf = pf; |
| 2263 | ti->num_flush_requests = 1; | 2290 | ti->num_flush_requests = 1; |
| 2291 | |||
| 2264 | /* | 2292 | /* |
| 2265 | * Only need to enable discards if the pool should pass | 2293 | * Only need to enable discards if the pool should pass |
| 2266 | * them down to the data device. The thin device's discard | 2294 | * them down to the data device. The thin device's discard |
| @@ -2268,12 +2296,14 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv) | |||
| 2268 | */ | 2296 | */ |
| 2269 | if (pf.discard_enabled && pf.discard_passdown) { | 2297 | if (pf.discard_enabled && pf.discard_passdown) { |
| 2270 | ti->num_discard_requests = 1; | 2298 | ti->num_discard_requests = 1; |
| 2299 | |||
| 2271 | /* | 2300 | /* |
| 2272 | * Setting 'discards_supported' circumvents the normal | 2301 | * Setting 'discards_supported' circumvents the normal |
| 2273 | * stacking of discard limits (this keeps the pool and | 2302 | * stacking of discard limits (this keeps the pool and |
| 2274 | * thin devices' discard limits consistent). | 2303 | * thin devices' discard limits consistent). |
| 2275 | */ | 2304 | */ |
| 2276 | ti->discards_supported = true; | 2305 | ti->discards_supported = true; |
| 2306 | ti->discard_zeroes_data_unsupported = true; | ||
| 2277 | } | 2307 | } |
| 2278 | ti->private = pt; | 2308 | ti->private = pt; |
| 2279 | 2309 | ||
| @@ -2703,7 +2733,7 @@ static int pool_status(struct dm_target *ti, status_type_t type, | |||
| 2703 | format_dev_t(buf2, pt->data_dev->bdev->bd_dev), | 2733 | format_dev_t(buf2, pt->data_dev->bdev->bd_dev), |
| 2704 | (unsigned long)pool->sectors_per_block, | 2734 | (unsigned long)pool->sectors_per_block, |
| 2705 | (unsigned long long)pt->low_water_blocks); | 2735 | (unsigned long long)pt->low_water_blocks); |
| 2706 | emit_flags(&pt->pf, result, sz, maxlen); | 2736 | emit_flags(&pt->requested_pf, result, sz, maxlen); |
| 2707 | break; | 2737 | break; |
| 2708 | } | 2738 | } |
| 2709 | 2739 | ||
| @@ -2732,20 +2762,21 @@ static int pool_merge(struct dm_target *ti, struct bvec_merge_data *bvm, | |||
| 2732 | return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); | 2762 | return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); |
| 2733 | } | 2763 | } |
| 2734 | 2764 | ||
| 2735 | static void set_discard_limits(struct pool *pool, struct queue_limits *limits) | 2765 | static void set_discard_limits(struct pool_c *pt, struct queue_limits *limits) |
| 2736 | { | 2766 | { |
| 2737 | /* | 2767 | struct pool *pool = pt->pool; |
| 2738 | * FIXME: these limits may be incompatible with the pool's data device | 2768 | struct queue_limits *data_limits; |
| 2739 | */ | 2769 | |
| 2740 | limits->max_discard_sectors = pool->sectors_per_block; | 2770 | limits->max_discard_sectors = pool->sectors_per_block; |
| 2741 | 2771 | ||
| 2742 | /* | 2772 | /* |
| 2743 | * This is just a hint, and not enforced. We have to cope with | 2773 | * discard_granularity is just a hint, and not enforced. |
| 2744 | * bios that cover a block partially. A discard that spans a block | ||
| 2745 | * boundary is not sent to this target. | ||
| 2746 | */ | 2774 | */ |
| 2747 | limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT; | 2775 | if (pt->adjusted_pf.discard_passdown) { |
| 2748 | limits->discard_zeroes_data = pool->pf.zero_new_blocks; | 2776 | data_limits = &bdev_get_queue(pt->data_dev->bdev)->limits; |
| 2777 | limits->discard_granularity = data_limits->discard_granularity; | ||
| 2778 | } else | ||
| 2779 | limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT; | ||
| 2749 | } | 2780 | } |
| 2750 | 2781 | ||
| 2751 | static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits) | 2782 | static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits) |
| @@ -2755,15 +2786,25 @@ static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits) | |||
| 2755 | 2786 | ||
| 2756 | blk_limits_io_min(limits, 0); | 2787 | blk_limits_io_min(limits, 0); |
| 2757 | blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT); | 2788 | blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT); |
| 2758 | if (pool->pf.discard_enabled) | 2789 | |
| 2759 | set_discard_limits(pool, limits); | 2790 | /* |
| 2791 | * pt->adjusted_pf is a staging area for the actual features to use. | ||
| 2792 | * They get transferred to the live pool in bind_control_target() | ||
| 2793 | * called from pool_preresume(). | ||
| 2794 | */ | ||
| 2795 | if (!pt->adjusted_pf.discard_enabled) | ||
| 2796 | return; | ||
| 2797 | |||
| 2798 | disable_passdown_if_not_supported(pt); | ||
| 2799 | |||
| 2800 | set_discard_limits(pt, limits); | ||
| 2760 | } | 2801 | } |
| 2761 | 2802 | ||
| 2762 | static struct target_type pool_target = { | 2803 | static struct target_type pool_target = { |
| 2763 | .name = "thin-pool", | 2804 | .name = "thin-pool", |
| 2764 | .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE | | 2805 | .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE | |
| 2765 | DM_TARGET_IMMUTABLE, | 2806 | DM_TARGET_IMMUTABLE, |
| 2766 | .version = {1, 3, 0}, | 2807 | .version = {1, 4, 0}, |
| 2767 | .module = THIS_MODULE, | 2808 | .module = THIS_MODULE, |
| 2768 | .ctr = pool_ctr, | 2809 | .ctr = pool_ctr, |
| 2769 | .dtr = pool_dtr, | 2810 | .dtr = pool_dtr, |
| @@ -3042,19 +3083,19 @@ static int thin_iterate_devices(struct dm_target *ti, | |||
| 3042 | return 0; | 3083 | return 0; |
| 3043 | } | 3084 | } |
| 3044 | 3085 | ||
| 3086 | /* | ||
| 3087 | * A thin device always inherits its queue limits from its pool. | ||
| 3088 | */ | ||
| 3045 | static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits) | 3089 | static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits) |
| 3046 | { | 3090 | { |
| 3047 | struct thin_c *tc = ti->private; | 3091 | struct thin_c *tc = ti->private; |
| 3048 | struct pool *pool = tc->pool; | ||
| 3049 | 3092 | ||
| 3050 | blk_limits_io_min(limits, 0); | 3093 | *limits = bdev_get_queue(tc->pool_dev->bdev)->limits; |
| 3051 | blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT); | ||
| 3052 | set_discard_limits(pool, limits); | ||
| 3053 | } | 3094 | } |
| 3054 | 3095 | ||
| 3055 | static struct target_type thin_target = { | 3096 | static struct target_type thin_target = { |
| 3056 | .name = "thin", | 3097 | .name = "thin", |
| 3057 | .version = {1, 3, 0}, | 3098 | .version = {1, 4, 0}, |
| 3058 | .module = THIS_MODULE, | 3099 | .module = THIS_MODULE, |
| 3059 | .ctr = thin_ctr, | 3100 | .ctr = thin_ctr, |
| 3060 | .dtr = thin_dtr, | 3101 | .dtr = thin_dtr, |
diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c index 254d19268ad2..892ae2766aa6 100644 --- a/drivers/md/dm-verity.c +++ b/drivers/md/dm-verity.c | |||
| @@ -718,8 +718,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) | |||
| 718 | v->hash_dev_block_bits = ffs(num) - 1; | 718 | v->hash_dev_block_bits = ffs(num) - 1; |
| 719 | 719 | ||
| 720 | if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 || | 720 | if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 || |
| 721 | num_ll << (v->data_dev_block_bits - SECTOR_SHIFT) != | 721 | (sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT)) |
| 722 | (sector_t)num_ll << (v->data_dev_block_bits - SECTOR_SHIFT)) { | 722 | >> (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll) { |
| 723 | ti->error = "Invalid data blocks"; | 723 | ti->error = "Invalid data blocks"; |
| 724 | r = -EINVAL; | 724 | r = -EINVAL; |
| 725 | goto bad; | 725 | goto bad; |
| @@ -733,8 +733,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) | |||
| 733 | } | 733 | } |
| 734 | 734 | ||
| 735 | if (sscanf(argv[6], "%llu%c", &num_ll, &dummy) != 1 || | 735 | if (sscanf(argv[6], "%llu%c", &num_ll, &dummy) != 1 || |
| 736 | num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT) != | 736 | (sector_t)(num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT)) |
| 737 | (sector_t)num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT)) { | 737 | >> (v->hash_dev_block_bits - SECTOR_SHIFT) != num_ll) { |
| 738 | ti->error = "Invalid hash start"; | 738 | ti->error = "Invalid hash start"; |
| 739 | r = -EINVAL; | 739 | r = -EINVAL; |
| 740 | goto bad; | 740 | goto bad; |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 4e09b6ff5b49..67ffa391edcf 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
| @@ -865,10 +865,14 @@ static void dm_done(struct request *clone, int error, bool mapped) | |||
| 865 | { | 865 | { |
| 866 | int r = error; | 866 | int r = error; |
| 867 | struct dm_rq_target_io *tio = clone->end_io_data; | 867 | struct dm_rq_target_io *tio = clone->end_io_data; |
| 868 | dm_request_endio_fn rq_end_io = tio->ti->type->rq_end_io; | 868 | dm_request_endio_fn rq_end_io = NULL; |
| 869 | 869 | ||
| 870 | if (mapped && rq_end_io) | 870 | if (tio->ti) { |
| 871 | r = rq_end_io(tio->ti, clone, error, &tio->info); | 871 | rq_end_io = tio->ti->type->rq_end_io; |
| 872 | |||
| 873 | if (mapped && rq_end_io) | ||
| 874 | r = rq_end_io(tio->ti, clone, error, &tio->info); | ||
| 875 | } | ||
| 872 | 876 | ||
| 873 | if (r <= 0) | 877 | if (r <= 0) |
| 874 | /* The target wants to complete the I/O */ | 878 | /* The target wants to complete the I/O */ |
| @@ -1588,15 +1592,6 @@ static int map_request(struct dm_target *ti, struct request *clone, | |||
| 1588 | int r, requeued = 0; | 1592 | int r, requeued = 0; |
| 1589 | struct dm_rq_target_io *tio = clone->end_io_data; | 1593 | struct dm_rq_target_io *tio = clone->end_io_data; |
| 1590 | 1594 | ||
| 1591 | /* | ||
| 1592 | * Hold the md reference here for the in-flight I/O. | ||
| 1593 | * We can't rely on the reference count by device opener, | ||
| 1594 | * because the device may be closed during the request completion | ||
| 1595 | * when all bios are completed. | ||
| 1596 | * See the comment in rq_completed() too. | ||
| 1597 | */ | ||
| 1598 | dm_get(md); | ||
| 1599 | |||
| 1600 | tio->ti = ti; | 1595 | tio->ti = ti; |
| 1601 | r = ti->type->map_rq(ti, clone, &tio->info); | 1596 | r = ti->type->map_rq(ti, clone, &tio->info); |
| 1602 | switch (r) { | 1597 | switch (r) { |
| @@ -1628,6 +1623,26 @@ static int map_request(struct dm_target *ti, struct request *clone, | |||
| 1628 | return requeued; | 1623 | return requeued; |
| 1629 | } | 1624 | } |
| 1630 | 1625 | ||
| 1626 | static struct request *dm_start_request(struct mapped_device *md, struct request *orig) | ||
| 1627 | { | ||
| 1628 | struct request *clone; | ||
| 1629 | |||
| 1630 | blk_start_request(orig); | ||
| 1631 | clone = orig->special; | ||
| 1632 | atomic_inc(&md->pending[rq_data_dir(clone)]); | ||
| 1633 | |||
| 1634 | /* | ||
| 1635 | * Hold the md reference here for the in-flight I/O. | ||
| 1636 | * We can't rely on the reference count by device opener, | ||
| 1637 | * because the device may be closed during the request completion | ||
| 1638 | * when all bios are completed. | ||
| 1639 | * See the comment in rq_completed() too. | ||
| 1640 | */ | ||
| 1641 | dm_get(md); | ||
| 1642 | |||
| 1643 | return clone; | ||
| 1644 | } | ||
| 1645 | |||
| 1631 | /* | 1646 | /* |
| 1632 | * q->request_fn for request-based dm. | 1647 | * q->request_fn for request-based dm. |
| 1633 | * Called with the queue lock held. | 1648 | * Called with the queue lock held. |
| @@ -1657,14 +1672,21 @@ static void dm_request_fn(struct request_queue *q) | |||
| 1657 | pos = blk_rq_pos(rq); | 1672 | pos = blk_rq_pos(rq); |
| 1658 | 1673 | ||
| 1659 | ti = dm_table_find_target(map, pos); | 1674 | ti = dm_table_find_target(map, pos); |
| 1660 | BUG_ON(!dm_target_is_valid(ti)); | 1675 | if (!dm_target_is_valid(ti)) { |
| 1676 | /* | ||
| 1677 | * Must perform setup, that dm_done() requires, | ||
| 1678 | * before calling dm_kill_unmapped_request | ||
| 1679 | */ | ||
| 1680 | DMERR_LIMIT("request attempted access beyond the end of device"); | ||
| 1681 | clone = dm_start_request(md, rq); | ||
| 1682 | dm_kill_unmapped_request(clone, -EIO); | ||
| 1683 | continue; | ||
| 1684 | } | ||
| 1661 | 1685 | ||
| 1662 | if (ti->type->busy && ti->type->busy(ti)) | 1686 | if (ti->type->busy && ti->type->busy(ti)) |
| 1663 | goto delay_and_out; | 1687 | goto delay_and_out; |
| 1664 | 1688 | ||
| 1665 | blk_start_request(rq); | 1689 | clone = dm_start_request(md, rq); |
| 1666 | clone = rq->special; | ||
| 1667 | atomic_inc(&md->pending[rq_data_dir(clone)]); | ||
| 1668 | 1690 | ||
| 1669 | spin_unlock(q->queue_lock); | 1691 | spin_unlock(q->queue_lock); |
| 1670 | if (map_request(ti, clone, md)) | 1692 | if (map_request(ti, clone, md)) |
| @@ -1684,8 +1706,6 @@ delay_and_out: | |||
| 1684 | blk_delay_queue(q, HZ / 10); | 1706 | blk_delay_queue(q, HZ / 10); |
| 1685 | out: | 1707 | out: |
| 1686 | dm_table_put(map); | 1708 | dm_table_put(map); |
| 1687 | |||
| 1688 | return; | ||
| 1689 | } | 1709 | } |
| 1690 | 1710 | ||
| 1691 | int dm_underlying_device_busy(struct request_queue *q) | 1711 | int dm_underlying_device_busy(struct request_queue *q) |
| @@ -2409,7 +2429,7 @@ static void dm_queue_flush(struct mapped_device *md) | |||
| 2409 | */ | 2429 | */ |
| 2410 | struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table) | 2430 | struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table) |
| 2411 | { | 2431 | { |
| 2412 | struct dm_table *map = ERR_PTR(-EINVAL); | 2432 | struct dm_table *live_map, *map = ERR_PTR(-EINVAL); |
| 2413 | struct queue_limits limits; | 2433 | struct queue_limits limits; |
| 2414 | int r; | 2434 | int r; |
| 2415 | 2435 | ||
| @@ -2419,6 +2439,19 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table) | |||
| 2419 | if (!dm_suspended_md(md)) | 2439 | if (!dm_suspended_md(md)) |
| 2420 | goto out; | 2440 | goto out; |
| 2421 | 2441 | ||
| 2442 | /* | ||
| 2443 | * If the new table has no data devices, retain the existing limits. | ||
| 2444 | * This helps multipath with queue_if_no_path if all paths disappear, | ||
| 2445 | * then new I/O is queued based on these limits, and then some paths | ||
| 2446 | * reappear. | ||
| 2447 | */ | ||
| 2448 | if (dm_table_has_no_data_devices(table)) { | ||
| 2449 | live_map = dm_get_live_table(md); | ||
| 2450 | if (live_map) | ||
| 2451 | limits = md->queue->limits; | ||
| 2452 | dm_table_put(live_map); | ||
| 2453 | } | ||
| 2454 | |||
| 2422 | r = dm_calculate_queue_limits(table, &limits); | 2455 | r = dm_calculate_queue_limits(table, &limits); |
| 2423 | if (r) { | 2456 | if (r) { |
| 2424 | map = ERR_PTR(r); | 2457 | map = ERR_PTR(r); |
diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 52eef493d266..6a99fefaa743 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h | |||
| @@ -54,6 +54,7 @@ void dm_table_event_callback(struct dm_table *t, | |||
| 54 | void (*fn)(void *), void *context); | 54 | void (*fn)(void *), void *context); |
| 55 | struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); | 55 | struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); |
| 56 | struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector); | 56 | struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector); |
| 57 | bool dm_table_has_no_data_devices(struct dm_table *table); | ||
| 57 | int dm_calculate_queue_limits(struct dm_table *table, | 58 | int dm_calculate_queue_limits(struct dm_table *table, |
| 58 | struct queue_limits *limits); | 59 | struct queue_limits *limits); |
| 59 | void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, | 60 | void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, |
diff --git a/drivers/md/md.c b/drivers/md/md.c index 3f6203a4c7ea..308e87b417e0 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
| @@ -7619,6 +7619,8 @@ static int remove_and_add_spares(struct mddev *mddev) | |||
| 7619 | } | 7619 | } |
| 7620 | } | 7620 | } |
| 7621 | } | 7621 | } |
| 7622 | if (removed) | ||
| 7623 | set_bit(MD_CHANGE_DEVS, &mddev->flags); | ||
| 7622 | return spares; | 7624 | return spares; |
| 7623 | } | 7625 | } |
| 7624 | 7626 | ||
| @@ -7632,9 +7634,11 @@ static void reap_sync_thread(struct mddev *mddev) | |||
| 7632 | !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { | 7634 | !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { |
| 7633 | /* success...*/ | 7635 | /* success...*/ |
| 7634 | /* activate any spares */ | 7636 | /* activate any spares */ |
| 7635 | if (mddev->pers->spare_active(mddev)) | 7637 | if (mddev->pers->spare_active(mddev)) { |
| 7636 | sysfs_notify(&mddev->kobj, NULL, | 7638 | sysfs_notify(&mddev->kobj, NULL, |
| 7637 | "degraded"); | 7639 | "degraded"); |
| 7640 | set_bit(MD_CHANGE_DEVS, &mddev->flags); | ||
| 7641 | } | ||
| 7638 | } | 7642 | } |
| 7639 | if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && | 7643 | if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && |
| 7640 | mddev->pers->finish_reshape) | 7644 | mddev->pers->finish_reshape) |
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 1c2eb38f3c51..0138a727c1f3 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c | |||
| @@ -1512,14 +1512,16 @@ static int _enough(struct r10conf *conf, struct geom *geo, int ignore) | |||
| 1512 | do { | 1512 | do { |
| 1513 | int n = conf->copies; | 1513 | int n = conf->copies; |
| 1514 | int cnt = 0; | 1514 | int cnt = 0; |
| 1515 | int this = first; | ||
| 1515 | while (n--) { | 1516 | while (n--) { |
| 1516 | if (conf->mirrors[first].rdev && | 1517 | if (conf->mirrors[this].rdev && |
| 1517 | first != ignore) | 1518 | this != ignore) |
| 1518 | cnt++; | 1519 | cnt++; |
| 1519 | first = (first+1) % geo->raid_disks; | 1520 | this = (this+1) % geo->raid_disks; |
| 1520 | } | 1521 | } |
| 1521 | if (cnt == 0) | 1522 | if (cnt == 0) |
| 1522 | return 0; | 1523 | return 0; |
| 1524 | first = (first + geo->near_copies) % geo->raid_disks; | ||
| 1523 | } while (first != 0); | 1525 | } while (first != 0); |
| 1524 | return 1; | 1526 | return 1; |
| 1525 | } | 1527 | } |
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index adda94df5eb2..0689173fd9f5 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
| @@ -393,6 +393,8 @@ static int calc_degraded(struct r5conf *conf) | |||
| 393 | degraded = 0; | 393 | degraded = 0; |
| 394 | for (i = 0; i < conf->previous_raid_disks; i++) { | 394 | for (i = 0; i < conf->previous_raid_disks; i++) { |
| 395 | struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); | 395 | struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); |
| 396 | if (rdev && test_bit(Faulty, &rdev->flags)) | ||
| 397 | rdev = rcu_dereference(conf->disks[i].replacement); | ||
| 396 | if (!rdev || test_bit(Faulty, &rdev->flags)) | 398 | if (!rdev || test_bit(Faulty, &rdev->flags)) |
| 397 | degraded++; | 399 | degraded++; |
| 398 | else if (test_bit(In_sync, &rdev->flags)) | 400 | else if (test_bit(In_sync, &rdev->flags)) |
| @@ -417,6 +419,8 @@ static int calc_degraded(struct r5conf *conf) | |||
| 417 | degraded2 = 0; | 419 | degraded2 = 0; |
| 418 | for (i = 0; i < conf->raid_disks; i++) { | 420 | for (i = 0; i < conf->raid_disks; i++) { |
| 419 | struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); | 421 | struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); |
| 422 | if (rdev && test_bit(Faulty, &rdev->flags)) | ||
| 423 | rdev = rcu_dereference(conf->disks[i].replacement); | ||
| 420 | if (!rdev || test_bit(Faulty, &rdev->flags)) | 424 | if (!rdev || test_bit(Faulty, &rdev->flags)) |
| 421 | degraded2++; | 425 | degraded2++; |
| 422 | else if (test_bit(In_sync, &rdev->flags)) | 426 | else if (test_bit(In_sync, &rdev->flags)) |
| @@ -1587,6 +1591,7 @@ static int resize_stripes(struct r5conf *conf, int newsize) | |||
| 1587 | #ifdef CONFIG_MULTICORE_RAID456 | 1591 | #ifdef CONFIG_MULTICORE_RAID456 |
| 1588 | init_waitqueue_head(&nsh->ops.wait_for_ops); | 1592 | init_waitqueue_head(&nsh->ops.wait_for_ops); |
| 1589 | #endif | 1593 | #endif |
| 1594 | spin_lock_init(&nsh->stripe_lock); | ||
| 1590 | 1595 | ||
| 1591 | list_add(&nsh->lru, &newstripes); | 1596 | list_add(&nsh->lru, &newstripes); |
| 1592 | } | 1597 | } |
| @@ -4192,7 +4197,7 @@ static void make_request(struct mddev *mddev, struct bio * bi) | |||
| 4192 | finish_wait(&conf->wait_for_overlap, &w); | 4197 | finish_wait(&conf->wait_for_overlap, &w); |
| 4193 | set_bit(STRIPE_HANDLE, &sh->state); | 4198 | set_bit(STRIPE_HANDLE, &sh->state); |
| 4194 | clear_bit(STRIPE_DELAYED, &sh->state); | 4199 | clear_bit(STRIPE_DELAYED, &sh->state); |
| 4195 | if ((bi->bi_rw & REQ_NOIDLE) && | 4200 | if ((bi->bi_rw & REQ_SYNC) && |
| 4196 | !test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) | 4201 | !test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) |
| 4197 | atomic_inc(&conf->preread_active_stripes); | 4202 | atomic_inc(&conf->preread_active_stripes); |
| 4198 | release_stripe_plug(mddev, sh); | 4203 | release_stripe_plug(mddev, sh); |
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c index b67a3018b136..ce229ea933d1 100644 --- a/drivers/mfd/88pm800.c +++ b/drivers/mfd/88pm800.c | |||
| @@ -470,7 +470,8 @@ static int __devinit device_800_init(struct pm80x_chip *chip, | |||
| 470 | 470 | ||
| 471 | ret = | 471 | ret = |
| 472 | mfd_add_devices(chip->dev, 0, &onkey_devs[0], | 472 | mfd_add_devices(chip->dev, 0, &onkey_devs[0], |
| 473 | ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0); | 473 | ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0, |
| 474 | NULL); | ||
| 474 | if (ret < 0) { | 475 | if (ret < 0) { |
| 475 | dev_err(chip->dev, "Failed to add onkey subdev\n"); | 476 | dev_err(chip->dev, "Failed to add onkey subdev\n"); |
| 476 | goto out_dev; | 477 | goto out_dev; |
| @@ -481,7 +482,7 @@ static int __devinit device_800_init(struct pm80x_chip *chip, | |||
| 481 | rtc_devs[0].platform_data = pdata->rtc; | 482 | rtc_devs[0].platform_data = pdata->rtc; |
| 482 | rtc_devs[0].pdata_size = sizeof(struct pm80x_rtc_pdata); | 483 | rtc_devs[0].pdata_size = sizeof(struct pm80x_rtc_pdata); |
| 483 | ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], | 484 | ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], |
| 484 | ARRAY_SIZE(rtc_devs), NULL, 0); | 485 | ARRAY_SIZE(rtc_devs), NULL, 0, NULL); |
| 485 | if (ret < 0) { | 486 | if (ret < 0) { |
| 486 | dev_err(chip->dev, "Failed to add rtc subdev\n"); | 487 | dev_err(chip->dev, "Failed to add rtc subdev\n"); |
| 487 | goto out_dev; | 488 | goto out_dev; |
diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c index 6146583589f6..c20a31136f04 100644 --- a/drivers/mfd/88pm805.c +++ b/drivers/mfd/88pm805.c | |||
| @@ -216,7 +216,8 @@ static int __devinit device_805_init(struct pm80x_chip *chip) | |||
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], | 218 | ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], |
| 219 | ARRAY_SIZE(codec_devs), &codec_resources[0], 0); | 219 | ARRAY_SIZE(codec_devs), &codec_resources[0], 0, |
| 220 | NULL); | ||
| 220 | if (ret < 0) { | 221 | if (ret < 0) { |
| 221 | dev_err(chip->dev, "Failed to add codec subdev\n"); | 222 | dev_err(chip->dev, "Failed to add codec subdev\n"); |
| 222 | goto out_codec; | 223 | goto out_codec; |
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index d09918cf1b15..b73f033b2c60 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c | |||
| @@ -637,7 +637,7 @@ static void __devinit device_bk_init(struct pm860x_chip *chip, | |||
| 637 | bk_devs[i].resources = &bk_resources[j]; | 637 | bk_devs[i].resources = &bk_resources[j]; |
| 638 | ret = mfd_add_devices(chip->dev, 0, | 638 | ret = mfd_add_devices(chip->dev, 0, |
| 639 | &bk_devs[i], 1, | 639 | &bk_devs[i], 1, |
| 640 | &bk_resources[j], 0); | 640 | &bk_resources[j], 0, NULL); |
| 641 | if (ret < 0) { | 641 | if (ret < 0) { |
| 642 | dev_err(chip->dev, "Failed to add " | 642 | dev_err(chip->dev, "Failed to add " |
| 643 | "backlight subdev\n"); | 643 | "backlight subdev\n"); |
| @@ -672,7 +672,7 @@ static void __devinit device_led_init(struct pm860x_chip *chip, | |||
| 672 | led_devs[i].resources = &led_resources[j], | 672 | led_devs[i].resources = &led_resources[j], |
| 673 | ret = mfd_add_devices(chip->dev, 0, | 673 | ret = mfd_add_devices(chip->dev, 0, |
| 674 | &led_devs[i], 1, | 674 | &led_devs[i], 1, |
| 675 | &led_resources[j], 0); | 675 | &led_resources[j], 0, NULL); |
| 676 | if (ret < 0) { | 676 | if (ret < 0) { |
| 677 | dev_err(chip->dev, "Failed to add " | 677 | dev_err(chip->dev, "Failed to add " |
| 678 | "led subdev\n"); | 678 | "led subdev\n"); |
| @@ -709,7 +709,7 @@ static void __devinit device_regulator_init(struct pm860x_chip *chip, | |||
| 709 | regulator_devs[i].resources = ®ulator_resources[seq]; | 709 | regulator_devs[i].resources = ®ulator_resources[seq]; |
| 710 | 710 | ||
| 711 | ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[i], 1, | 711 | ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[i], 1, |
| 712 | ®ulator_resources[seq], 0); | 712 | ®ulator_resources[seq], 0, NULL); |
| 713 | if (ret < 0) { | 713 | if (ret < 0) { |
| 714 | dev_err(chip->dev, "Failed to add regulator subdev\n"); | 714 | dev_err(chip->dev, "Failed to add regulator subdev\n"); |
| 715 | goto out; | 715 | goto out; |
| @@ -733,7 +733,7 @@ static void __devinit device_rtc_init(struct pm860x_chip *chip, | |||
| 733 | rtc_devs[0].resources = &rtc_resources[0]; | 733 | rtc_devs[0].resources = &rtc_resources[0]; |
| 734 | ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], | 734 | ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], |
| 735 | ARRAY_SIZE(rtc_devs), &rtc_resources[0], | 735 | ARRAY_SIZE(rtc_devs), &rtc_resources[0], |
| 736 | chip->irq_base); | 736 | chip->irq_base, NULL); |
| 737 | if (ret < 0) | 737 | if (ret < 0) |
| 738 | dev_err(chip->dev, "Failed to add rtc subdev\n"); | 738 | dev_err(chip->dev, "Failed to add rtc subdev\n"); |
| 739 | } | 739 | } |
| @@ -752,7 +752,7 @@ static void __devinit device_touch_init(struct pm860x_chip *chip, | |||
| 752 | touch_devs[0].resources = &touch_resources[0]; | 752 | touch_devs[0].resources = &touch_resources[0]; |
| 753 | ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], | 753 | ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], |
| 754 | ARRAY_SIZE(touch_devs), &touch_resources[0], | 754 | ARRAY_SIZE(touch_devs), &touch_resources[0], |
| 755 | chip->irq_base); | 755 | chip->irq_base, NULL); |
| 756 | if (ret < 0) | 756 | if (ret < 0) |
| 757 | dev_err(chip->dev, "Failed to add touch subdev\n"); | 757 | dev_err(chip->dev, "Failed to add touch subdev\n"); |
| 758 | } | 758 | } |
| @@ -770,7 +770,7 @@ static void __devinit device_power_init(struct pm860x_chip *chip, | |||
| 770 | power_devs[0].num_resources = ARRAY_SIZE(battery_resources); | 770 | power_devs[0].num_resources = ARRAY_SIZE(battery_resources); |
| 771 | power_devs[0].resources = &battery_resources[0], | 771 | power_devs[0].resources = &battery_resources[0], |
| 772 | ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1, | 772 | ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1, |
| 773 | &battery_resources[0], chip->irq_base); | 773 | &battery_resources[0], chip->irq_base, NULL); |
| 774 | if (ret < 0) | 774 | if (ret < 0) |
| 775 | dev_err(chip->dev, "Failed to add battery subdev\n"); | 775 | dev_err(chip->dev, "Failed to add battery subdev\n"); |
| 776 | 776 | ||
| @@ -779,7 +779,7 @@ static void __devinit device_power_init(struct pm860x_chip *chip, | |||
| 779 | power_devs[1].num_resources = ARRAY_SIZE(charger_resources); | 779 | power_devs[1].num_resources = ARRAY_SIZE(charger_resources); |
| 780 | power_devs[1].resources = &charger_resources[0], | 780 | power_devs[1].resources = &charger_resources[0], |
| 781 | ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1, | 781 | ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1, |
| 782 | &charger_resources[0], chip->irq_base); | 782 | &charger_resources[0], chip->irq_base, NULL); |
| 783 | if (ret < 0) | 783 | if (ret < 0) |
| 784 | dev_err(chip->dev, "Failed to add charger subdev\n"); | 784 | dev_err(chip->dev, "Failed to add charger subdev\n"); |
| 785 | 785 | ||
| @@ -788,7 +788,7 @@ static void __devinit device_power_init(struct pm860x_chip *chip, | |||
| 788 | power_devs[2].num_resources = ARRAY_SIZE(preg_resources); | 788 | power_devs[2].num_resources = ARRAY_SIZE(preg_resources); |
| 789 | power_devs[2].resources = &preg_resources[0], | 789 | power_devs[2].resources = &preg_resources[0], |
| 790 | ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1, | 790 | ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1, |
| 791 | &preg_resources[0], chip->irq_base); | 791 | &preg_resources[0], chip->irq_base, NULL); |
| 792 | if (ret < 0) | 792 | if (ret < 0) |
| 793 | dev_err(chip->dev, "Failed to add preg subdev\n"); | 793 | dev_err(chip->dev, "Failed to add preg subdev\n"); |
| 794 | } | 794 | } |
| @@ -802,7 +802,7 @@ static void __devinit device_onkey_init(struct pm860x_chip *chip, | |||
| 802 | onkey_devs[0].resources = &onkey_resources[0], | 802 | onkey_devs[0].resources = &onkey_resources[0], |
| 803 | ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], | 803 | ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], |
| 804 | ARRAY_SIZE(onkey_devs), &onkey_resources[0], | 804 | ARRAY_SIZE(onkey_devs), &onkey_resources[0], |
| 805 | chip->irq_base); | 805 | chip->irq_base, NULL); |
| 806 | if (ret < 0) | 806 | if (ret < 0) |
| 807 | dev_err(chip->dev, "Failed to add onkey subdev\n"); | 807 | dev_err(chip->dev, "Failed to add onkey subdev\n"); |
| 808 | } | 808 | } |
| @@ -815,7 +815,8 @@ static void __devinit device_codec_init(struct pm860x_chip *chip, | |||
| 815 | codec_devs[0].num_resources = ARRAY_SIZE(codec_resources); | 815 | codec_devs[0].num_resources = ARRAY_SIZE(codec_resources); |
| 816 | codec_devs[0].resources = &codec_resources[0], | 816 | codec_devs[0].resources = &codec_resources[0], |
| 817 | ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], | 817 | ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], |
| 818 | ARRAY_SIZE(codec_devs), &codec_resources[0], 0); | 818 | ARRAY_SIZE(codec_devs), &codec_resources[0], 0, |
| 819 | NULL); | ||
| 819 | if (ret < 0) | 820 | if (ret < 0) |
| 820 | dev_err(chip->dev, "Failed to add codec subdev\n"); | 821 | dev_err(chip->dev, "Failed to add codec subdev\n"); |
| 821 | } | 822 | } |
diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index 44a3fdbadef4..f1beb4971f87 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c | |||
| @@ -424,7 +424,7 @@ static int aat2870_i2c_probe(struct i2c_client *client, | |||
| 424 | } | 424 | } |
| 425 | 425 | ||
| 426 | ret = mfd_add_devices(aat2870->dev, 0, aat2870_devs, | 426 | ret = mfd_add_devices(aat2870->dev, 0, aat2870_devs, |
| 427 | ARRAY_SIZE(aat2870_devs), NULL, 0); | 427 | ARRAY_SIZE(aat2870_devs), NULL, 0, NULL); |
| 428 | if (ret != 0) { | 428 | if (ret != 0) { |
| 429 | dev_err(aat2870->dev, "Failed to add subdev: %d\n", ret); | 429 | dev_err(aat2870->dev, "Failed to add subdev: %d\n", ret); |
| 430 | goto out_disable; | 430 | goto out_disable; |
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 78fca2902c8d..01781ae5d0d7 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c | |||
| @@ -946,7 +946,7 @@ static int __devinit ab3100_probe(struct i2c_client *client, | |||
| 946 | } | 946 | } |
| 947 | 947 | ||
| 948 | err = mfd_add_devices(&client->dev, 0, ab3100_devs, | 948 | err = mfd_add_devices(&client->dev, 0, ab3100_devs, |
| 949 | ARRAY_SIZE(ab3100_devs), NULL, 0); | 949 | ARRAY_SIZE(ab3100_devs), NULL, 0, NULL); |
| 950 | 950 | ||
| 951 | ab3100_setup_debugfs(ab3100); | 951 | ab3100_setup_debugfs(ab3100); |
| 952 | 952 | ||
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 626b4ecaf647..47adf800024e 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
| @@ -1418,25 +1418,25 @@ static int __devinit ab8500_probe(struct platform_device *pdev) | |||
| 1418 | 1418 | ||
| 1419 | ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs, | 1419 | ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs, |
| 1420 | ARRAY_SIZE(abx500_common_devs), NULL, | 1420 | ARRAY_SIZE(abx500_common_devs), NULL, |
| 1421 | ab8500->irq_base); | 1421 | ab8500->irq_base, ab8500->domain); |
| 1422 | if (ret) | 1422 | if (ret) |
| 1423 | goto out_freeirq; | 1423 | goto out_freeirq; |
| 1424 | 1424 | ||
| 1425 | if (is_ab9540(ab8500)) | 1425 | if (is_ab9540(ab8500)) |
| 1426 | ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, | 1426 | ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, |
| 1427 | ARRAY_SIZE(ab9540_devs), NULL, | 1427 | ARRAY_SIZE(ab9540_devs), NULL, |
| 1428 | ab8500->irq_base); | 1428 | ab8500->irq_base, ab8500->domain); |
| 1429 | else | 1429 | else |
| 1430 | ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, | 1430 | ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, |
| 1431 | ARRAY_SIZE(ab8500_devs), NULL, | 1431 | ARRAY_SIZE(ab8500_devs), NULL, |
| 1432 | ab8500->irq_base); | 1432 | ab8500->irq_base, ab8500->domain); |
| 1433 | if (ret) | 1433 | if (ret) |
| 1434 | goto out_freeirq; | 1434 | goto out_freeirq; |
| 1435 | 1435 | ||
| 1436 | if (is_ab9540(ab8500) || is_ab8505(ab8500)) | 1436 | if (is_ab9540(ab8500) || is_ab8505(ab8500)) |
| 1437 | ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs, | 1437 | ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs, |
| 1438 | ARRAY_SIZE(ab9540_ab8505_devs), NULL, | 1438 | ARRAY_SIZE(ab9540_ab8505_devs), NULL, |
| 1439 | ab8500->irq_base); | 1439 | ab8500->irq_base, ab8500->domain); |
| 1440 | if (ret) | 1440 | if (ret) |
| 1441 | goto out_freeirq; | 1441 | goto out_freeirq; |
| 1442 | 1442 | ||
| @@ -1444,7 +1444,7 @@ static int __devinit ab8500_probe(struct platform_device *pdev) | |||
| 1444 | /* Add battery management devices */ | 1444 | /* Add battery management devices */ |
| 1445 | ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, | 1445 | ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, |
| 1446 | ARRAY_SIZE(ab8500_bm_devs), NULL, | 1446 | ARRAY_SIZE(ab8500_bm_devs), NULL, |
| 1447 | ab8500->irq_base); | 1447 | ab8500->irq_base, ab8500->domain); |
| 1448 | if (ret) | 1448 | if (ret) |
| 1449 | dev_err(ab8500->dev, "error adding bm devices\n"); | 1449 | dev_err(ab8500->dev, "error adding bm devices\n"); |
| 1450 | } | 1450 | } |
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 866f95960b4b..29d72a259c85 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c | |||
| @@ -342,7 +342,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel) | |||
| 342 | 342 | ||
| 343 | /* | 343 | /* |
| 344 | * Delay might be needed for ABB8500 cut 3.0, if not, remove | 344 | * Delay might be needed for ABB8500 cut 3.0, if not, remove |
| 345 | * when hardware will be availible | 345 | * when hardware will be available |
| 346 | */ | 346 | */ |
| 347 | msleep(1); | 347 | msleep(1); |
| 348 | break; | 348 | break; |
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index c7983e862549..1b48f2094806 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c | |||
| @@ -316,7 +316,7 @@ int __devinit arizona_dev_init(struct arizona *arizona) | |||
| 316 | } | 316 | } |
| 317 | 317 | ||
| 318 | ret = mfd_add_devices(arizona->dev, -1, early_devs, | 318 | ret = mfd_add_devices(arizona->dev, -1, early_devs, |
| 319 | ARRAY_SIZE(early_devs), NULL, 0); | 319 | ARRAY_SIZE(early_devs), NULL, 0, NULL); |
| 320 | if (ret != 0) { | 320 | if (ret != 0) { |
| 321 | dev_err(dev, "Failed to add early children: %d\n", ret); | 321 | dev_err(dev, "Failed to add early children: %d\n", ret); |
| 322 | return ret; | 322 | return ret; |
| @@ -516,11 +516,11 @@ int __devinit arizona_dev_init(struct arizona *arizona) | |||
| 516 | switch (arizona->type) { | 516 | switch (arizona->type) { |
| 517 | case WM5102: | 517 | case WM5102: |
| 518 | ret = mfd_add_devices(arizona->dev, -1, wm5102_devs, | 518 | ret = mfd_add_devices(arizona->dev, -1, wm5102_devs, |
| 519 | ARRAY_SIZE(wm5102_devs), NULL, 0); | 519 | ARRAY_SIZE(wm5102_devs), NULL, 0, NULL); |
| 520 | break; | 520 | break; |
| 521 | case WM5110: | 521 | case WM5110: |
| 522 | ret = mfd_add_devices(arizona->dev, -1, wm5110_devs, | 522 | ret = mfd_add_devices(arizona->dev, -1, wm5110_devs, |
| 523 | ARRAY_SIZE(wm5102_devs), NULL, 0); | 523 | ARRAY_SIZE(wm5102_devs), NULL, 0, NULL); |
| 524 | break; | 524 | break; |
| 525 | } | 525 | } |
| 526 | 526 | ||
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 683e18a23329..62f0883a7630 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c | |||
| @@ -913,14 +913,14 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, | |||
| 913 | if (pdata->clock_rate) { | 913 | if (pdata->clock_rate) { |
| 914 | ds1wm_pdata.clock_rate = pdata->clock_rate; | 914 | ds1wm_pdata.clock_rate = pdata->clock_rate; |
| 915 | ret = mfd_add_devices(&pdev->dev, pdev->id, | 915 | ret = mfd_add_devices(&pdev->dev, pdev->id, |
| 916 | &asic3_cell_ds1wm, 1, mem, asic->irq_base); | 916 | &asic3_cell_ds1wm, 1, mem, asic->irq_base, NULL); |
| 917 | if (ret < 0) | 917 | if (ret < 0) |
| 918 | goto out; | 918 | goto out; |
| 919 | } | 919 | } |
| 920 | 920 | ||
| 921 | if (mem_sdio && (irq >= 0)) { | 921 | if (mem_sdio && (irq >= 0)) { |
| 922 | ret = mfd_add_devices(&pdev->dev, pdev->id, | 922 | ret = mfd_add_devices(&pdev->dev, pdev->id, |
| 923 | &asic3_cell_mmc, 1, mem_sdio, irq); | 923 | &asic3_cell_mmc, 1, mem_sdio, irq, NULL); |
| 924 | if (ret < 0) | 924 | if (ret < 0) |
| 925 | goto out; | 925 | goto out; |
| 926 | } | 926 | } |
| @@ -934,7 +934,7 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, | |||
| 934 | asic3_cell_leds[i].pdata_size = sizeof(pdata->leds[i]); | 934 | asic3_cell_leds[i].pdata_size = sizeof(pdata->leds[i]); |
| 935 | } | 935 | } |
| 936 | ret = mfd_add_devices(&pdev->dev, 0, | 936 | ret = mfd_add_devices(&pdev->dev, 0, |
| 937 | asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0); | 937 | asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0, NULL); |
| 938 | } | 938 | } |
| 939 | 939 | ||
| 940 | out: | 940 | out: |
diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c index 3419e726de47..2b282133c725 100644 --- a/drivers/mfd/cs5535-mfd.c +++ b/drivers/mfd/cs5535-mfd.c | |||
| @@ -149,7 +149,7 @@ static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, | |||
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | err = mfd_add_devices(&pdev->dev, -1, cs5535_mfd_cells, | 151 | err = mfd_add_devices(&pdev->dev, -1, cs5535_mfd_cells, |
| 152 | ARRAY_SIZE(cs5535_mfd_cells), NULL, 0); | 152 | ARRAY_SIZE(cs5535_mfd_cells), NULL, 0, NULL); |
| 153 | if (err) { | 153 | if (err) { |
| 154 | dev_err(&pdev->dev, "MFD add devices failed: %d\n", err); | 154 | dev_err(&pdev->dev, "MFD add devices failed: %d\n", err); |
| 155 | goto err_disable; | 155 | goto err_disable; |
diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c index 2544910e1fd6..a0a62b24621b 100644 --- a/drivers/mfd/da9052-core.c +++ b/drivers/mfd/da9052-core.c | |||
| @@ -803,7 +803,7 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id) | |||
| 803 | dev_err(da9052->dev, "DA9052 ADC IRQ failed ret=%d\n", ret); | 803 | dev_err(da9052->dev, "DA9052 ADC IRQ failed ret=%d\n", ret); |
| 804 | 804 | ||
| 805 | ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info, | 805 | ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info, |
| 806 | ARRAY_SIZE(da9052_subdev_info), NULL, 0); | 806 | ARRAY_SIZE(da9052_subdev_info), NULL, 0, NULL); |
| 807 | if (ret) | 807 | if (ret) |
| 808 | goto err; | 808 | goto err; |
| 809 | 809 | ||
diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index 4e2af2cb2d26..45e83a68641b 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c | |||
| @@ -129,7 +129,7 @@ static int __init davinci_vc_probe(struct platform_device *pdev) | |||
| 129 | cell->pdata_size = sizeof(*davinci_vc); | 129 | cell->pdata_size = sizeof(*davinci_vc); |
| 130 | 130 | ||
| 131 | ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells, | 131 | ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells, |
| 132 | DAVINCI_VC_CELLS, NULL, 0); | 132 | DAVINCI_VC_CELLS, NULL, 0, NULL); |
| 133 | if (ret != 0) { | 133 | if (ret != 0) { |
| 134 | dev_err(&pdev->dev, "fail to register client devices\n"); | 134 | dev_err(&pdev->dev, "fail to register client devices\n"); |
| 135 | goto fail4; | 135 | goto fail4; |
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 7040a0081130..0e63cdd9b52a 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c | |||
| @@ -3010,7 +3010,7 @@ static int __devinit db8500_prcmu_probe(struct platform_device *pdev) | |||
| 3010 | prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); | 3010 | prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); |
| 3011 | 3011 | ||
| 3012 | err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs, | 3012 | err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs, |
| 3013 | ARRAY_SIZE(db8500_prcmu_devs), NULL, 0); | 3013 | ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, NULL); |
| 3014 | if (err) { | 3014 | if (err) { |
| 3015 | pr_err("prcmu: Failed to add subdevices\n"); | 3015 | pr_err("prcmu: Failed to add subdevices\n"); |
| 3016 | return err; | 3016 | return err; |
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 04c7093d6499..9e5453d21a68 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c | |||
| @@ -168,7 +168,7 @@ static int __init pasic3_probe(struct platform_device *pdev) | |||
| 168 | /* the first 5 PASIC3 registers control the DS1WM */ | 168 | /* the first 5 PASIC3 registers control the DS1WM */ |
| 169 | ds1wm_resources[0].end = (5 << asic->bus_shift) - 1; | 169 | ds1wm_resources[0].end = (5 << asic->bus_shift) - 1; |
| 170 | ret = mfd_add_devices(&pdev->dev, pdev->id, | 170 | ret = mfd_add_devices(&pdev->dev, pdev->id, |
| 171 | &ds1wm_cell, 1, r, irq); | 171 | &ds1wm_cell, 1, r, irq, NULL); |
| 172 | if (ret < 0) | 172 | if (ret < 0) |
| 173 | dev_warn(dev, "failed to register DS1WM\n"); | 173 | dev_warn(dev, "failed to register DS1WM\n"); |
| 174 | } | 174 | } |
| @@ -176,7 +176,8 @@ static int __init pasic3_probe(struct platform_device *pdev) | |||
| 176 | if (pdata && pdata->led_pdata) { | 176 | if (pdata && pdata->led_pdata) { |
| 177 | led_cell.platform_data = pdata->led_pdata; | 177 | led_cell.platform_data = pdata->led_pdata; |
| 178 | led_cell.pdata_size = sizeof(struct pasic3_leds_machinfo); | 178 | led_cell.pdata_size = sizeof(struct pasic3_leds_machinfo); |
| 179 | ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0); | 179 | ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, |
| 180 | 0, NULL); | ||
| 180 | if (ret < 0) | 181 | if (ret < 0) |
| 181 | dev_warn(dev, "failed to register LED device\n"); | 182 | dev_warn(dev, "failed to register LED device\n"); |
| 182 | } | 183 | } |
diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c index 59df5584cb58..266bdc5bd96d 100644 --- a/drivers/mfd/intel_msic.c +++ b/drivers/mfd/intel_msic.c | |||
| @@ -344,13 +344,13 @@ static int __devinit intel_msic_init_devices(struct intel_msic *msic) | |||
| 344 | continue; | 344 | continue; |
| 345 | 345 | ||
| 346 | ret = mfd_add_devices(&pdev->dev, -1, &msic_devs[i], 1, NULL, | 346 | ret = mfd_add_devices(&pdev->dev, -1, &msic_devs[i], 1, NULL, |
| 347 | pdata->irq[i]); | 347 | pdata->irq[i], NULL); |
| 348 | if (ret) | 348 | if (ret) |
| 349 | goto fail; | 349 | goto fail; |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | ret = mfd_add_devices(&pdev->dev, 0, msic_other_devs, | 352 | ret = mfd_add_devices(&pdev->dev, 0, msic_other_devs, |
| 353 | ARRAY_SIZE(msic_other_devs), NULL, 0); | 353 | ARRAY_SIZE(msic_other_devs), NULL, 0, NULL); |
| 354 | if (ret) | 354 | if (ret) |
| 355 | goto fail; | 355 | goto fail; |
| 356 | 356 | ||
diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c index 2ea99989551a..965c4801df8a 100644 --- a/drivers/mfd/janz-cmodio.c +++ b/drivers/mfd/janz-cmodio.c | |||
| @@ -147,7 +147,7 @@ static int __devinit cmodio_probe_submodules(struct cmodio_device *priv) | |||
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | return mfd_add_devices(&pdev->dev, 0, priv->cells, | 149 | return mfd_add_devices(&pdev->dev, 0, priv->cells, |
| 150 | num_probed, NULL, pdev->irq); | 150 | num_probed, NULL, pdev->irq, NULL); |
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | /* | 153 | /* |
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index 87662a17dec6..c6b6d7dda517 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c | |||
| @@ -287,7 +287,8 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev) | |||
| 287 | writeb(0xff, adc->base + JZ_REG_ADC_CTRL); | 287 | writeb(0xff, adc->base + JZ_REG_ADC_CTRL); |
| 288 | 288 | ||
| 289 | ret = mfd_add_devices(&pdev->dev, 0, jz4740_adc_cells, | 289 | ret = mfd_add_devices(&pdev->dev, 0, jz4740_adc_cells, |
| 290 | ARRAY_SIZE(jz4740_adc_cells), mem_base, irq_base); | 290 | ARRAY_SIZE(jz4740_adc_cells), mem_base, |
| 291 | irq_base, NULL); | ||
| 291 | if (ret < 0) | 292 | if (ret < 0) |
| 292 | goto err_clk_put; | 293 | goto err_clk_put; |
| 293 | 294 | ||
diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c index 0b2879b87fd9..24212f45b201 100644 --- a/drivers/mfd/lm3533-core.c +++ b/drivers/mfd/lm3533-core.c | |||
| @@ -393,7 +393,8 @@ static int __devinit lm3533_device_als_init(struct lm3533 *lm3533) | |||
| 393 | lm3533_als_devs[0].platform_data = pdata->als; | 393 | lm3533_als_devs[0].platform_data = pdata->als; |
| 394 | lm3533_als_devs[0].pdata_size = sizeof(*pdata->als); | 394 | lm3533_als_devs[0].pdata_size = sizeof(*pdata->als); |
| 395 | 395 | ||
| 396 | ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL, 0); | 396 | ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL, |
| 397 | 0, NULL); | ||
| 397 | if (ret) { | 398 | if (ret) { |
| 398 | dev_err(lm3533->dev, "failed to add ALS device\n"); | 399 | dev_err(lm3533->dev, "failed to add ALS device\n"); |
| 399 | return ret; | 400 | return ret; |
| @@ -422,7 +423,7 @@ static int __devinit lm3533_device_bl_init(struct lm3533 *lm3533) | |||
| 422 | } | 423 | } |
| 423 | 424 | ||
| 424 | ret = mfd_add_devices(lm3533->dev, 0, lm3533_bl_devs, | 425 | ret = mfd_add_devices(lm3533->dev, 0, lm3533_bl_devs, |
| 425 | pdata->num_backlights, NULL, 0); | 426 | pdata->num_backlights, NULL, 0, NULL); |
| 426 | if (ret) { | 427 | if (ret) { |
| 427 | dev_err(lm3533->dev, "failed to add backlight devices\n"); | 428 | dev_err(lm3533->dev, "failed to add backlight devices\n"); |
| 428 | return ret; | 429 | return ret; |
| @@ -451,7 +452,7 @@ static int __devinit lm3533_device_led_init(struct lm3533 *lm3533) | |||
| 451 | } | 452 | } |
| 452 | 453 | ||
| 453 | ret = mfd_add_devices(lm3533->dev, 0, lm3533_led_devs, | 454 | ret = mfd_add_devices(lm3533->dev, 0, lm3533_led_devs, |
| 454 | pdata->num_leds, NULL, 0); | 455 | pdata->num_leds, NULL, 0, NULL); |
| 455 | if (ret) { | 456 | if (ret) { |
| 456 | dev_err(lm3533->dev, "failed to add LED devices\n"); | 457 | dev_err(lm3533->dev, "failed to add LED devices\n"); |
| 457 | return ret; | 458 | return ret; |
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 027cc8f86132..092ad4b44b6d 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c | |||
| @@ -750,7 +750,7 @@ gpe0_done: | |||
| 750 | 750 | ||
| 751 | lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id); | 751 | lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id); |
| 752 | ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_GPIO], | 752 | ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_GPIO], |
| 753 | 1, NULL, 0); | 753 | 1, NULL, 0, NULL); |
| 754 | 754 | ||
| 755 | gpio_done: | 755 | gpio_done: |
| 756 | if (acpi_conflict) | 756 | if (acpi_conflict) |
| @@ -765,7 +765,6 @@ static int __devinit lpc_ich_init_wdt(struct pci_dev *dev, | |||
| 765 | u32 base_addr_cfg; | 765 | u32 base_addr_cfg; |
| 766 | u32 base_addr; | 766 | u32 base_addr; |
| 767 | int ret; | 767 | int ret; |
| 768 | bool acpi_conflict = false; | ||
| 769 | struct resource *res; | 768 | struct resource *res; |
| 770 | 769 | ||
| 771 | /* Setup power management base register */ | 770 | /* Setup power management base register */ |
| @@ -780,20 +779,11 @@ static int __devinit lpc_ich_init_wdt(struct pci_dev *dev, | |||
| 780 | res = wdt_io_res(ICH_RES_IO_TCO); | 779 | res = wdt_io_res(ICH_RES_IO_TCO); |
| 781 | res->start = base_addr + ACPIBASE_TCO_OFF; | 780 | res->start = base_addr + ACPIBASE_TCO_OFF; |
| 782 | res->end = base_addr + ACPIBASE_TCO_END; | 781 | res->end = base_addr + ACPIBASE_TCO_END; |
| 783 | ret = acpi_check_resource_conflict(res); | ||
| 784 | if (ret) { | ||
| 785 | acpi_conflict = true; | ||
| 786 | goto wdt_done; | ||
| 787 | } | ||
| 788 | 782 | ||
| 789 | res = wdt_io_res(ICH_RES_IO_SMI); | 783 | res = wdt_io_res(ICH_RES_IO_SMI); |
| 790 | res->start = base_addr + ACPIBASE_SMI_OFF; | 784 | res->start = base_addr + ACPIBASE_SMI_OFF; |
| 791 | res->end = base_addr + ACPIBASE_SMI_END; | 785 | res->end = base_addr + ACPIBASE_SMI_END; |
| 792 | ret = acpi_check_resource_conflict(res); | 786 | |
| 793 | if (ret) { | ||
| 794 | acpi_conflict = true; | ||
| 795 | goto wdt_done; | ||
| 796 | } | ||
| 797 | lpc_ich_enable_acpi_space(dev); | 787 | lpc_ich_enable_acpi_space(dev); |
| 798 | 788 | ||
| 799 | /* | 789 | /* |
| @@ -813,21 +803,13 @@ static int __devinit lpc_ich_init_wdt(struct pci_dev *dev, | |||
| 813 | res = wdt_mem_res(ICH_RES_MEM_GCS); | 803 | res = wdt_mem_res(ICH_RES_MEM_GCS); |
| 814 | res->start = base_addr + ACPIBASE_GCS_OFF; | 804 | res->start = base_addr + ACPIBASE_GCS_OFF; |
| 815 | res->end = base_addr + ACPIBASE_GCS_END; | 805 | res->end = base_addr + ACPIBASE_GCS_END; |
| 816 | ret = acpi_check_resource_conflict(res); | ||
| 817 | if (ret) { | ||
| 818 | acpi_conflict = true; | ||
| 819 | goto wdt_done; | ||
| 820 | } | ||
| 821 | } | 806 | } |
| 822 | 807 | ||
| 823 | lpc_ich_finalize_cell(&lpc_ich_cells[LPC_WDT], id); | 808 | lpc_ich_finalize_cell(&lpc_ich_cells[LPC_WDT], id); |
| 824 | ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_WDT], | 809 | ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_WDT], |
| 825 | 1, NULL, 0); | 810 | 1, NULL, 0, NULL); |
| 826 | 811 | ||
| 827 | wdt_done: | 812 | wdt_done: |
| 828 | if (acpi_conflict) | ||
| 829 | pr_warn("Resource conflict(s) found affecting %s\n", | ||
| 830 | lpc_ich_cells[LPC_WDT].name); | ||
| 831 | return ret; | 813 | return ret; |
| 832 | } | 814 | } |
| 833 | 815 | ||
diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c index 9f20abc5e393..f6b9c5c96b24 100644 --- a/drivers/mfd/lpc_sch.c +++ b/drivers/mfd/lpc_sch.c | |||
| @@ -127,7 +127,8 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev, | |||
| 127 | lpc_sch_cells[i].id = id->device; | 127 | lpc_sch_cells[i].id = id->device; |
| 128 | 128 | ||
| 129 | ret = mfd_add_devices(&dev->dev, 0, | 129 | ret = mfd_add_devices(&dev->dev, 0, |
| 130 | lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0); | 130 | lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, |
| 131 | 0, NULL); | ||
| 131 | if (ret) | 132 | if (ret) |
| 132 | goto out_dev; | 133 | goto out_dev; |
| 133 | 134 | ||
| @@ -153,7 +154,8 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev, | |||
| 153 | tunnelcreek_cells[i].id = id->device; | 154 | tunnelcreek_cells[i].id = id->device; |
| 154 | 155 | ||
| 155 | ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells, | 156 | ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells, |
| 156 | ARRAY_SIZE(tunnelcreek_cells), NULL, 0); | 157 | ARRAY_SIZE(tunnelcreek_cells), NULL, |
| 158 | 0, NULL); | ||
| 157 | } | 159 | } |
| 158 | 160 | ||
| 159 | return ret; | 161 | return ret; |
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index c03e12b51924..d9e24c849a00 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c | |||
| @@ -126,7 +126,7 @@ static int max77686_i2c_probe(struct i2c_client *i2c, | |||
| 126 | max77686_irq_init(max77686); | 126 | max77686_irq_init(max77686); |
| 127 | 127 | ||
| 128 | ret = mfd_add_devices(max77686->dev, -1, max77686_devs, | 128 | ret = mfd_add_devices(max77686->dev, -1, max77686_devs, |
| 129 | ARRAY_SIZE(max77686_devs), NULL, 0); | 129 | ARRAY_SIZE(max77686_devs), NULL, 0, NULL); |
| 130 | 130 | ||
| 131 | if (ret < 0) | 131 | if (ret < 0) |
| 132 | goto err_mfd; | 132 | goto err_mfd; |
diff --git a/drivers/mfd/max77693-irq.c b/drivers/mfd/max77693-irq.c index 2b403569e0a6..1029d018c739 100644 --- a/drivers/mfd/max77693-irq.c +++ b/drivers/mfd/max77693-irq.c | |||
| @@ -137,6 +137,9 @@ static void max77693_irq_mask(struct irq_data *data) | |||
| 137 | const struct max77693_irq_data *irq_data = | 137 | const struct max77693_irq_data *irq_data = |
| 138 | irq_to_max77693_irq(max77693, data->irq); | 138 | irq_to_max77693_irq(max77693, data->irq); |
| 139 | 139 | ||
| 140 | if (irq_data->group >= MAX77693_IRQ_GROUP_NR) | ||
| 141 | return; | ||
| 142 | |||
| 140 | if (irq_data->group >= MUIC_INT1 && irq_data->group <= MUIC_INT3) | 143 | if (irq_data->group >= MUIC_INT1 && irq_data->group <= MUIC_INT3) |
| 141 | max77693->irq_masks_cur[irq_data->group] &= ~irq_data->mask; | 144 | max77693->irq_masks_cur[irq_data->group] &= ~irq_data->mask; |
| 142 | else | 145 | else |
| @@ -149,6 +152,9 @@ static void max77693_irq_unmask(struct irq_data *data) | |||
| 149 | const struct max77693_irq_data *irq_data = | 152 | const struct max77693_irq_data *irq_data = |
| 150 | irq_to_max77693_irq(max77693, data->irq); | 153 | irq_to_max77693_irq(max77693, data->irq); |
| 151 | 154 | ||
| 155 | if (irq_data->group >= MAX77693_IRQ_GROUP_NR) | ||
| 156 | return; | ||
| 157 | |||
| 152 | if (irq_data->group >= MUIC_INT1 && irq_data->group <= MUIC_INT3) | 158 | if (irq_data->group >= MUIC_INT1 && irq_data->group <= MUIC_INT3) |
| 153 | max77693->irq_masks_cur[irq_data->group] |= irq_data->mask; | 159 | max77693->irq_masks_cur[irq_data->group] |= irq_data->mask; |
| 154 | else | 160 | else |
| @@ -200,7 +206,7 @@ static irqreturn_t max77693_irq_thread(int irq, void *data) | |||
| 200 | 206 | ||
| 201 | if (irq_src & MAX77693_IRQSRC_MUIC) | 207 | if (irq_src & MAX77693_IRQSRC_MUIC) |
| 202 | /* MUIC INT1 ~ INT3 */ | 208 | /* MUIC INT1 ~ INT3 */ |
| 203 | max77693_bulk_read(max77693->regmap, MAX77693_MUIC_REG_INT1, | 209 | max77693_bulk_read(max77693->regmap_muic, MAX77693_MUIC_REG_INT1, |
| 204 | MAX77693_NUM_IRQ_MUIC_REGS, &irq_reg[MUIC_INT1]); | 210 | MAX77693_NUM_IRQ_MUIC_REGS, &irq_reg[MUIC_INT1]); |
| 205 | 211 | ||
| 206 | /* Apply masking */ | 212 | /* Apply masking */ |
| @@ -255,7 +261,8 @@ int max77693_irq_init(struct max77693_dev *max77693) | |||
| 255 | { | 261 | { |
| 256 | struct irq_domain *domain; | 262 | struct irq_domain *domain; |
| 257 | int i; | 263 | int i; |
| 258 | int ret; | 264 | int ret = 0; |
| 265 | u8 intsrc_mask; | ||
| 259 | 266 | ||
| 260 | mutex_init(&max77693->irqlock); | 267 | mutex_init(&max77693->irqlock); |
| 261 | 268 | ||
| @@ -287,19 +294,38 @@ int max77693_irq_init(struct max77693_dev *max77693) | |||
| 287 | &max77693_irq_domain_ops, max77693); | 294 | &max77693_irq_domain_ops, max77693); |
| 288 | if (!domain) { | 295 | if (!domain) { |
| 289 | dev_err(max77693->dev, "could not create irq domain\n"); | 296 | dev_err(max77693->dev, "could not create irq domain\n"); |
| 290 | return -ENODEV; | 297 | ret = -ENODEV; |
| 298 | goto err_irq; | ||
| 291 | } | 299 | } |
| 292 | max77693->irq_domain = domain; | 300 | max77693->irq_domain = domain; |
| 293 | 301 | ||
| 302 | /* Unmask max77693 interrupt */ | ||
| 303 | ret = max77693_read_reg(max77693->regmap, | ||
| 304 | MAX77693_PMIC_REG_INTSRC_MASK, &intsrc_mask); | ||
| 305 | if (ret < 0) { | ||
| 306 | dev_err(max77693->dev, "fail to read PMIC register\n"); | ||
| 307 | goto err_irq; | ||
| 308 | } | ||
| 309 | |||
| 310 | intsrc_mask &= ~(MAX77693_IRQSRC_CHG); | ||
| 311 | intsrc_mask &= ~(MAX77693_IRQSRC_FLASH); | ||
| 312 | intsrc_mask &= ~(MAX77693_IRQSRC_MUIC); | ||
| 313 | ret = max77693_write_reg(max77693->regmap, | ||
| 314 | MAX77693_PMIC_REG_INTSRC_MASK, intsrc_mask); | ||
| 315 | if (ret < 0) { | ||
| 316 | dev_err(max77693->dev, "fail to write PMIC register\n"); | ||
| 317 | goto err_irq; | ||
| 318 | } | ||
| 319 | |||
| 294 | ret = request_threaded_irq(max77693->irq, NULL, max77693_irq_thread, | 320 | ret = request_threaded_irq(max77693->irq, NULL, max77693_irq_thread, |
| 295 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 321 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
| 296 | "max77693-irq", max77693); | 322 | "max77693-irq", max77693); |
| 297 | |||
| 298 | if (ret) | 323 | if (ret) |
| 299 | dev_err(max77693->dev, "Failed to request IRQ %d: %d\n", | 324 | dev_err(max77693->dev, "Failed to request IRQ %d: %d\n", |
| 300 | max77693->irq, ret); | 325 | max77693->irq, ret); |
| 301 | 326 | ||
| 302 | return 0; | 327 | err_irq: |
| 328 | return ret; | ||
| 303 | } | 329 | } |
| 304 | 330 | ||
| 305 | void max77693_irq_exit(struct max77693_dev *max77693) | 331 | void max77693_irq_exit(struct max77693_dev *max77693) |
diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index a1811cb50ec7..cc5155e20494 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c | |||
| @@ -152,6 +152,20 @@ static int max77693_i2c_probe(struct i2c_client *i2c, | |||
| 152 | max77693->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC); | 152 | max77693->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC); |
| 153 | i2c_set_clientdata(max77693->haptic, max77693); | 153 | i2c_set_clientdata(max77693->haptic, max77693); |
| 154 | 154 | ||
| 155 | /* | ||
| 156 | * Initialize register map for MUIC device because use regmap-muic | ||
| 157 | * instance of MUIC device when irq of max77693 is initialized | ||
| 158 | * before call max77693-muic probe() function. | ||
| 159 | */ | ||
| 160 | max77693->regmap_muic = devm_regmap_init_i2c(max77693->muic, | ||
| 161 | &max77693_regmap_config); | ||
| 162 | if (IS_ERR(max77693->regmap_muic)) { | ||
| 163 | ret = PTR_ERR(max77693->regmap_muic); | ||
| 164 | dev_err(max77693->dev, | ||
| 165 | "failed to allocate register map: %d\n", ret); | ||
| 166 | goto err_regmap; | ||
| 167 | } | ||
| 168 | |||
| 155 | ret = max77693_irq_init(max77693); | 169 | ret = max77693_irq_init(max77693); |
| 156 | if (ret < 0) | 170 | if (ret < 0) |
| 157 | goto err_irq; | 171 | goto err_irq; |
| @@ -159,7 +173,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c, | |||
| 159 | pm_runtime_set_active(max77693->dev); | 173 | pm_runtime_set_active(max77693->dev); |
| 160 | 174 | ||
| 161 | ret = mfd_add_devices(max77693->dev, -1, max77693_devs, | 175 | ret = mfd_add_devices(max77693->dev, -1, max77693_devs, |
| 162 | ARRAY_SIZE(max77693_devs), NULL, 0); | 176 | ARRAY_SIZE(max77693_devs), NULL, 0, NULL); |
| 163 | if (ret < 0) | 177 | if (ret < 0) |
| 164 | goto err_mfd; | 178 | goto err_mfd; |
| 165 | 179 | ||
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 825a7f06d9ba..ee53757beca7 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c | |||
| @@ -598,7 +598,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, | |||
| 598 | 598 | ||
| 599 | ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], | 599 | ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], |
| 600 | ARRAY_SIZE(rtc_devs), | 600 | ARRAY_SIZE(rtc_devs), |
| 601 | &rtc_resources[0], chip->irq_base); | 601 | &rtc_resources[0], chip->irq_base, NULL); |
| 602 | if (ret < 0) { | 602 | if (ret < 0) { |
| 603 | dev_err(chip->dev, "Failed to add rtc subdev\n"); | 603 | dev_err(chip->dev, "Failed to add rtc subdev\n"); |
| 604 | goto out; | 604 | goto out; |
| @@ -606,7 +606,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, | |||
| 606 | 606 | ||
| 607 | ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], | 607 | ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], |
| 608 | ARRAY_SIZE(onkey_devs), | 608 | ARRAY_SIZE(onkey_devs), |
| 609 | &onkey_resources[0], 0); | 609 | &onkey_resources[0], 0, NULL); |
| 610 | if (ret < 0) { | 610 | if (ret < 0) { |
| 611 | dev_err(chip->dev, "Failed to add onkey subdev\n"); | 611 | dev_err(chip->dev, "Failed to add onkey subdev\n"); |
| 612 | goto out_dev; | 612 | goto out_dev; |
| @@ -615,7 +615,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, | |||
| 615 | if (pdata) { | 615 | if (pdata) { |
| 616 | ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], | 616 | ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], |
| 617 | ARRAY_SIZE(regulator_devs), | 617 | ARRAY_SIZE(regulator_devs), |
| 618 | ®ulator_resources[0], 0); | 618 | ®ulator_resources[0], 0, NULL); |
| 619 | if (ret < 0) { | 619 | if (ret < 0) { |
| 620 | dev_err(chip->dev, "Failed to add regulator subdev\n"); | 620 | dev_err(chip->dev, "Failed to add regulator subdev\n"); |
| 621 | goto out_dev; | 621 | goto out_dev; |
| @@ -625,7 +625,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, | |||
| 625 | if (pdata && pdata->backlight) { | 625 | if (pdata && pdata->backlight) { |
| 626 | ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0], | 626 | ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0], |
| 627 | ARRAY_SIZE(backlight_devs), | 627 | ARRAY_SIZE(backlight_devs), |
| 628 | &backlight_resources[0], 0); | 628 | &backlight_resources[0], 0, NULL); |
| 629 | if (ret < 0) { | 629 | if (ret < 0) { |
| 630 | dev_err(chip->dev, "Failed to add backlight subdev\n"); | 630 | dev_err(chip->dev, "Failed to add backlight subdev\n"); |
| 631 | goto out_dev; | 631 | goto out_dev; |
| @@ -635,7 +635,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, | |||
| 635 | if (pdata && pdata->power) { | 635 | if (pdata && pdata->power) { |
| 636 | ret = mfd_add_devices(chip->dev, 0, &power_devs[0], | 636 | ret = mfd_add_devices(chip->dev, 0, &power_devs[0], |
| 637 | ARRAY_SIZE(power_devs), | 637 | ARRAY_SIZE(power_devs), |
| 638 | &power_supply_resources[0], 0); | 638 | &power_supply_resources[0], 0, NULL); |
| 639 | if (ret < 0) { | 639 | if (ret < 0) { |
| 640 | dev_err(chip->dev, "Failed to add power supply " | 640 | dev_err(chip->dev, "Failed to add power supply " |
| 641 | "subdev\n"); | 641 | "subdev\n"); |
| @@ -646,7 +646,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, | |||
| 646 | if (pdata && pdata->touch) { | 646 | if (pdata && pdata->touch) { |
| 647 | ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], | 647 | ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], |
| 648 | ARRAY_SIZE(touch_devs), | 648 | ARRAY_SIZE(touch_devs), |
| 649 | &touch_resources[0], 0); | 649 | &touch_resources[0], 0, NULL); |
| 650 | if (ret < 0) { | 650 | if (ret < 0) { |
| 651 | dev_err(chip->dev, "Failed to add touch subdev\n"); | 651 | dev_err(chip->dev, "Failed to add touch subdev\n"); |
| 652 | goto out_dev; | 652 | goto out_dev; |
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 10b629c245b6..f123517065ec 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c | |||
| @@ -160,7 +160,7 @@ static int max8997_i2c_probe(struct i2c_client *i2c, | |||
| 160 | 160 | ||
| 161 | mfd_add_devices(max8997->dev, -1, max8997_devs, | 161 | mfd_add_devices(max8997->dev, -1, max8997_devs, |
| 162 | ARRAY_SIZE(max8997_devs), | 162 | ARRAY_SIZE(max8997_devs), |
| 163 | NULL, 0); | 163 | NULL, 0, NULL); |
| 164 | 164 | ||
| 165 | /* | 165 | /* |
| 166 | * TODO: enable others (flash, muic, rtc, battery, ...) and | 166 | * TODO: enable others (flash, muic, rtc, battery, ...) and |
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 6ef56d28c056..d7218cc90945 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c | |||
| @@ -161,13 +161,13 @@ static int max8998_i2c_probe(struct i2c_client *i2c, | |||
| 161 | switch (id->driver_data) { | 161 | switch (id->driver_data) { |
| 162 | case TYPE_LP3974: | 162 | case TYPE_LP3974: |
| 163 | ret = mfd_add_devices(max8998->dev, -1, | 163 | ret = mfd_add_devices(max8998->dev, -1, |
| 164 | lp3974_devs, ARRAY_SIZE(lp3974_devs), | 164 | lp3974_devs, ARRAY_SIZE(lp3974_devs), |
| 165 | NULL, 0); | 165 | NULL, 0, NULL); |
| 166 | break; | 166 | break; |
| 167 | case TYPE_MAX8998: | 167 | case TYPE_MAX8998: |
| 168 | ret = mfd_add_devices(max8998->dev, -1, | 168 | ret = mfd_add_devices(max8998->dev, -1, |
| 169 | max8998_devs, ARRAY_SIZE(max8998_devs), | 169 | max8998_devs, ARRAY_SIZE(max8998_devs), |
| 170 | NULL, 0); | 170 | NULL, 0, NULL); |
| 171 | break; | 171 | break; |
| 172 | default: | 172 | default: |
| 173 | ret = -EINVAL; | 173 | ret = -EINVAL; |
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index b801dc72f041..1ec79b54bd2f 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c | |||
| @@ -612,7 +612,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, | |||
| 612 | if (!cell.name) | 612 | if (!cell.name) |
| 613 | return -ENOMEM; | 613 | return -ENOMEM; |
| 614 | 614 | ||
| 615 | return mfd_add_devices(mc13xxx->dev, -1, &cell, 1, NULL, 0); | 615 | return mfd_add_devices(mc13xxx->dev, -1, &cell, 1, NULL, 0, NULL); |
| 616 | } | 616 | } |
| 617 | 617 | ||
| 618 | static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) | 618 | static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) |
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 0c3a01cde2f7..f8b77711ad2d 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c | |||
| @@ -74,12 +74,11 @@ static int mfd_platform_add_cell(struct platform_device *pdev, | |||
| 74 | static int mfd_add_device(struct device *parent, int id, | 74 | static int mfd_add_device(struct device *parent, int id, |
| 75 | const struct mfd_cell *cell, | 75 | const struct mfd_cell *cell, |
| 76 | struct resource *mem_base, | 76 | struct resource *mem_base, |
| 77 | int irq_base) | 77 | int irq_base, struct irq_domain *domain) |
| 78 | { | 78 | { |
| 79 | struct resource *res; | 79 | struct resource *res; |
| 80 | struct platform_device *pdev; | 80 | struct platform_device *pdev; |
| 81 | struct device_node *np = NULL; | 81 | struct device_node *np = NULL; |
| 82 | struct irq_domain *domain = NULL; | ||
| 83 | int ret = -ENOMEM; | 82 | int ret = -ENOMEM; |
| 84 | int r; | 83 | int r; |
| 85 | 84 | ||
| @@ -97,7 +96,6 @@ static int mfd_add_device(struct device *parent, int id, | |||
| 97 | for_each_child_of_node(parent->of_node, np) { | 96 | for_each_child_of_node(parent->of_node, np) { |
| 98 | if (of_device_is_compatible(np, cell->of_compatible)) { | 97 | if (of_device_is_compatible(np, cell->of_compatible)) { |
| 99 | pdev->dev.of_node = np; | 98 | pdev->dev.of_node = np; |
| 100 | domain = irq_find_host(parent->of_node); | ||
| 101 | break; | 99 | break; |
| 102 | } | 100 | } |
| 103 | } | 101 | } |
| @@ -177,7 +175,7 @@ fail_alloc: | |||
| 177 | int mfd_add_devices(struct device *parent, int id, | 175 | int mfd_add_devices(struct device *parent, int id, |
| 178 | struct mfd_cell *cells, int n_devs, | 176 | struct mfd_cell *cells, int n_devs, |
| 179 | struct resource *mem_base, | 177 | struct resource *mem_base, |
| 180 | int irq_base) | 178 | int irq_base, struct irq_domain *domain) |
| 181 | { | 179 | { |
| 182 | int i; | 180 | int i; |
| 183 | int ret = 0; | 181 | int ret = 0; |
| @@ -191,7 +189,8 @@ int mfd_add_devices(struct device *parent, int id, | |||
| 191 | for (i = 0; i < n_devs; i++) { | 189 | for (i = 0; i < n_devs; i++) { |
| 192 | atomic_set(&cnts[i], 0); | 190 | atomic_set(&cnts[i], 0); |
| 193 | cells[i].usage_count = &cnts[i]; | 191 | cells[i].usage_count = &cnts[i]; |
| 194 | ret = mfd_add_device(parent, id, cells + i, mem_base, irq_base); | 192 | ret = mfd_add_device(parent, id, cells + i, mem_base, |
| 193 | irq_base, domain); | ||
| 195 | if (ret) | 194 | if (ret) |
| 196 | break; | 195 | break; |
| 197 | } | 196 | } |
| @@ -247,7 +246,8 @@ int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones) | |||
| 247 | for (i = 0; i < n_clones; i++) { | 246 | for (i = 0; i < n_clones; i++) { |
| 248 | cell_entry.name = clones[i]; | 247 | cell_entry.name = clones[i]; |
| 249 | /* don't give up if a single call fails; just report error */ | 248 | /* don't give up if a single call fails; just report error */ |
| 250 | if (mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0)) | 249 | if (mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0, |
| 250 | NULL)) | ||
| 251 | dev_err(dev, "failed to create platform device '%s'\n", | 251 | dev_err(dev, "failed to create platform device '%s'\n", |
| 252 | clones[i]); | 252 | clones[i]); |
| 253 | } | 253 | } |
diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index c4a69f193a1d..a345f9bb7b47 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c | |||
| @@ -453,7 +453,8 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, | |||
| 453 | 453 | ||
| 454 | ret = mfd_add_devices(palmas->dev, -1, | 454 | ret = mfd_add_devices(palmas->dev, -1, |
| 455 | children, ARRAY_SIZE(palmas_children), | 455 | children, ARRAY_SIZE(palmas_children), |
| 456 | NULL, regmap_irq_chip_get_base(palmas->irq_data)); | 456 | NULL, regmap_irq_chip_get_base(palmas->irq_data), |
| 457 | NULL); | ||
| 457 | kfree(children); | 458 | kfree(children); |
| 458 | 459 | ||
| 459 | if (ret < 0) | 460 | if (ret < 0) |
diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index cdc1df7fa0e9..ff61efc76ce2 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c | |||
| @@ -281,7 +281,7 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c, | |||
| 281 | 281 | ||
| 282 | if (i2c->irq) { | 282 | if (i2c->irq) { |
| 283 | ret = rc5t583_irq_init(rc5t583, i2c->irq, pdata->irq_base); | 283 | ret = rc5t583_irq_init(rc5t583, i2c->irq, pdata->irq_base); |
| 284 | /* Still continue with waring if irq init fails */ | 284 | /* Still continue with warning, if irq init fails */ |
| 285 | if (ret) | 285 | if (ret) |
| 286 | dev_warn(&i2c->dev, "IRQ init failed: %d\n", ret); | 286 | dev_warn(&i2c->dev, "IRQ init failed: %d\n", ret); |
| 287 | else | 287 | else |
| @@ -289,7 +289,7 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c, | |||
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | ret = mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs, | 291 | ret = mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs, |
| 292 | ARRAY_SIZE(rc5t583_subdevs), NULL, 0); | 292 | ARRAY_SIZE(rc5t583_subdevs), NULL, 0, NULL); |
| 293 | if (ret) { | 293 | if (ret) { |
| 294 | dev_err(&i2c->dev, "add mfd devices failed: %d\n", ret); | 294 | dev_err(&i2c->dev, "add mfd devices failed: %d\n", ret); |
| 295 | goto err_add_devs; | 295 | goto err_add_devs; |
diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c index 685d61e431ad..fbabc3cbe350 100644 --- a/drivers/mfd/rdc321x-southbridge.c +++ b/drivers/mfd/rdc321x-southbridge.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * RDC321x MFD southbrige driver | 2 | * RDC321x MFD southbridge driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2007-2010 Florian Fainelli <florian@openwrt.org> | 4 | * Copyright (C) 2007-2010 Florian Fainelli <florian@openwrt.org> |
| 5 | * Copyright (C) 2010 Bernhard Loos <bernhardloos@googlemail.com> | 5 | * Copyright (C) 2010 Bernhard Loos <bernhardloos@googlemail.com> |
| @@ -87,7 +87,8 @@ static int __devinit rdc321x_sb_probe(struct pci_dev *pdev, | |||
| 87 | rdc321x_wdt_pdata.sb_pdev = pdev; | 87 | rdc321x_wdt_pdata.sb_pdev = pdev; |
| 88 | 88 | ||
| 89 | return mfd_add_devices(&pdev->dev, -1, | 89 | return mfd_add_devices(&pdev->dev, -1, |
| 90 | rdc321x_sb_cells, ARRAY_SIZE(rdc321x_sb_cells), NULL, 0); | 90 | rdc321x_sb_cells, ARRAY_SIZE(rdc321x_sb_cells), |
| 91 | NULL, 0, NULL); | ||
| 91 | } | 92 | } |
| 92 | 93 | ||
| 93 | static void __devexit rdc321x_sb_remove(struct pci_dev *pdev) | 94 | static void __devexit rdc321x_sb_remove(struct pci_dev *pdev) |
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 2988efde11eb..49d361a618d0 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c | |||
| @@ -141,19 +141,19 @@ static int sec_pmic_probe(struct i2c_client *i2c, | |||
| 141 | switch (sec_pmic->device_type) { | 141 | switch (sec_pmic->device_type) { |
| 142 | case S5M8751X: | 142 | case S5M8751X: |
| 143 | ret = mfd_add_devices(sec_pmic->dev, -1, s5m8751_devs, | 143 | ret = mfd_add_devices(sec_pmic->dev, -1, s5m8751_devs, |
| 144 | ARRAY_SIZE(s5m8751_devs), NULL, 0); | 144 | ARRAY_SIZE(s5m8751_devs), NULL, 0, NULL); |
| 145 | break; | 145 | break; |
| 146 | case S5M8763X: | 146 | case S5M8763X: |
| 147 | ret = mfd_add_devices(sec_pmic->dev, -1, s5m8763_devs, | 147 | ret = mfd_add_devices(sec_pmic->dev, -1, s5m8763_devs, |
| 148 | ARRAY_SIZE(s5m8763_devs), NULL, 0); | 148 | ARRAY_SIZE(s5m8763_devs), NULL, 0, NULL); |
| 149 | break; | 149 | break; |
| 150 | case S5M8767X: | 150 | case S5M8767X: |
| 151 | ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs, | 151 | ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs, |
| 152 | ARRAY_SIZE(s5m8767_devs), NULL, 0); | 152 | ARRAY_SIZE(s5m8767_devs), NULL, 0, NULL); |
| 153 | break; | 153 | break; |
| 154 | case S2MPS11X: | 154 | case S2MPS11X: |
| 155 | ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs, | 155 | ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs, |
| 156 | ARRAY_SIZE(s2mps11_devs), NULL, 0); | 156 | ARRAY_SIZE(s2mps11_devs), NULL, 0, NULL); |
| 157 | break; | 157 | break; |
| 158 | default: | 158 | default: |
| 159 | /* If this happens the probe function is problem */ | 159 | /* If this happens the probe function is problem */ |
diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c index d31fed07aefb..d35da6820bea 100644 --- a/drivers/mfd/sta2x11-mfd.c +++ b/drivers/mfd/sta2x11-mfd.c | |||
| @@ -407,7 +407,7 @@ static int __devinit sta2x11_mfd_probe(struct pci_dev *pdev, | |||
| 407 | sta2x11_mfd_bar0, | 407 | sta2x11_mfd_bar0, |
| 408 | ARRAY_SIZE(sta2x11_mfd_bar0), | 408 | ARRAY_SIZE(sta2x11_mfd_bar0), |
| 409 | &pdev->resource[0], | 409 | &pdev->resource[0], |
| 410 | 0); | 410 | 0, NULL); |
| 411 | if (err) { | 411 | if (err) { |
| 412 | dev_err(&pdev->dev, "mfd_add_devices[0] failed: %d\n", err); | 412 | dev_err(&pdev->dev, "mfd_add_devices[0] failed: %d\n", err); |
| 413 | goto err_disable; | 413 | goto err_disable; |
| @@ -417,7 +417,7 @@ static int __devinit sta2x11_mfd_probe(struct pci_dev *pdev, | |||
| 417 | sta2x11_mfd_bar1, | 417 | sta2x11_mfd_bar1, |
| 418 | ARRAY_SIZE(sta2x11_mfd_bar1), | 418 | ARRAY_SIZE(sta2x11_mfd_bar1), |
| 419 | &pdev->resource[1], | 419 | &pdev->resource[1], |
| 420 | 0); | 420 | 0, NULL); |
| 421 | if (err) { | 421 | if (err) { |
| 422 | dev_err(&pdev->dev, "mfd_add_devices[1] failed: %d\n", err); | 422 | dev_err(&pdev->dev, "mfd_add_devices[1] failed: %d\n", err); |
| 423 | goto err_disable; | 423 | goto err_disable; |
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 2dd8d49cb30b..c94f521f392c 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c | |||
| @@ -962,7 +962,7 @@ static int __devinit stmpe_add_device(struct stmpe *stmpe, | |||
| 962 | struct mfd_cell *cell, int irq) | 962 | struct mfd_cell *cell, int irq) |
| 963 | { | 963 | { |
| 964 | return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1, | 964 | return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1, |
| 965 | NULL, stmpe->irq_base + irq); | 965 | NULL, stmpe->irq_base + irq, NULL); |
| 966 | } | 966 | } |
| 967 | 967 | ||
| 968 | static int __devinit stmpe_devices_init(struct stmpe *stmpe) | 968 | static int __devinit stmpe_devices_init(struct stmpe *stmpe) |
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 2d9e8799e733..b32940ec9034 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c | |||
| @@ -388,7 +388,7 @@ static int t7l66xb_probe(struct platform_device *dev) | |||
| 388 | 388 | ||
| 389 | ret = mfd_add_devices(&dev->dev, dev->id, | 389 | ret = mfd_add_devices(&dev->dev, dev->id, |
| 390 | t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), | 390 | t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), |
| 391 | iomem, t7l66xb->irq_base); | 391 | iomem, t7l66xb->irq_base, NULL); |
| 392 | 392 | ||
| 393 | if (!ret) | 393 | if (!ret) |
| 394 | return 0; | 394 | return 0; |
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 048bf0532a09..b56ba6b43294 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c | |||
| @@ -262,8 +262,8 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) | |||
| 262 | 262 | ||
| 263 | if (blocks & TC3589x_BLOCK_GPIO) { | 263 | if (blocks & TC3589x_BLOCK_GPIO) { |
| 264 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio, | 264 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio, |
| 265 | ARRAY_SIZE(tc3589x_dev_gpio), NULL, | 265 | ARRAY_SIZE(tc3589x_dev_gpio), NULL, |
| 266 | tc3589x->irq_base); | 266 | tc3589x->irq_base, NULL); |
| 267 | if (ret) { | 267 | if (ret) { |
| 268 | dev_err(tc3589x->dev, "failed to add gpio child\n"); | 268 | dev_err(tc3589x->dev, "failed to add gpio child\n"); |
| 269 | return ret; | 269 | return ret; |
| @@ -273,8 +273,8 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) | |||
| 273 | 273 | ||
| 274 | if (blocks & TC3589x_BLOCK_KEYPAD) { | 274 | if (blocks & TC3589x_BLOCK_KEYPAD) { |
| 275 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad, | 275 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad, |
| 276 | ARRAY_SIZE(tc3589x_dev_keypad), NULL, | 276 | ARRAY_SIZE(tc3589x_dev_keypad), NULL, |
| 277 | tc3589x->irq_base); | 277 | tc3589x->irq_base, NULL); |
| 278 | if (ret) { | 278 | if (ret) { |
| 279 | dev_err(tc3589x->dev, "failed to keypad child\n"); | 279 | dev_err(tc3589x->dev, "failed to keypad child\n"); |
| 280 | return ret; | 280 | return ret; |
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index d20a284ad4ba..413c891102f8 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c | |||
| @@ -192,7 +192,7 @@ static int __devinit tc6387xb_probe(struct platform_device *dev) | |||
| 192 | printk(KERN_INFO "Toshiba tc6387xb initialised\n"); | 192 | printk(KERN_INFO "Toshiba tc6387xb initialised\n"); |
| 193 | 193 | ||
| 194 | ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells, | 194 | ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells, |
| 195 | ARRAY_SIZE(tc6387xb_cells), iomem, irq); | 195 | ARRAY_SIZE(tc6387xb_cells), iomem, irq, NULL); |
| 196 | 196 | ||
| 197 | if (!ret) | 197 | if (!ret) |
| 198 | return 0; | 198 | return 0; |
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 9612264f0e6d..dcab026fcbb2 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c | |||
| @@ -700,8 +700,8 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) | |||
| 700 | tc6393xb_cells[TC6393XB_CELL_FB].pdata_size = sizeof(*tcpd->fb_data); | 700 | tc6393xb_cells[TC6393XB_CELL_FB].pdata_size = sizeof(*tcpd->fb_data); |
| 701 | 701 | ||
| 702 | ret = mfd_add_devices(&dev->dev, dev->id, | 702 | ret = mfd_add_devices(&dev->dev, dev->id, |
| 703 | tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), | 703 | tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), |
| 704 | iomem, tcpd->irq_base); | 704 | iomem, tcpd->irq_base, NULL); |
| 705 | 705 | ||
| 706 | if (!ret) | 706 | if (!ret) |
| 707 | return 0; | 707 | return 0; |
diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c index 4fb0e6c8e8fe..7c3675a74f93 100644 --- a/drivers/mfd/ti-ssp.c +++ b/drivers/mfd/ti-ssp.c | |||
| @@ -412,7 +412,7 @@ static int __devinit ti_ssp_probe(struct platform_device *pdev) | |||
| 412 | cells[id].data_size = data->pdata_size; | 412 | cells[id].data_size = data->pdata_size; |
| 413 | } | 413 | } |
| 414 | 414 | ||
| 415 | error = mfd_add_devices(dev, 0, cells, 2, NULL, 0); | 415 | error = mfd_add_devices(dev, 0, cells, 2, NULL, 0, NULL); |
| 416 | if (error < 0) { | 416 | if (error < 0) { |
| 417 | dev_err(dev, "cannot add mfd cells\n"); | 417 | dev_err(dev, "cannot add mfd cells\n"); |
| 418 | goto error_enable; | 418 | goto error_enable; |
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index a447f4ec11fb..cccc626c83c8 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c | |||
| @@ -757,25 +757,25 @@ static int __devinit timb_probe(struct pci_dev *dev, | |||
| 757 | err = mfd_add_devices(&dev->dev, -1, | 757 | err = mfd_add_devices(&dev->dev, -1, |
| 758 | timberdale_cells_bar0_cfg0, | 758 | timberdale_cells_bar0_cfg0, |
| 759 | ARRAY_SIZE(timberdale_cells_bar0_cfg0), | 759 | ARRAY_SIZE(timberdale_cells_bar0_cfg0), |
| 760 | &dev->resource[0], msix_entries[0].vector); | 760 | &dev->resource[0], msix_entries[0].vector, NULL); |
| 761 | break; | 761 | break; |
| 762 | case TIMB_HW_VER1: | 762 | case TIMB_HW_VER1: |
| 763 | err = mfd_add_devices(&dev->dev, -1, | 763 | err = mfd_add_devices(&dev->dev, -1, |
| 764 | timberdale_cells_bar0_cfg1, | 764 | timberdale_cells_bar0_cfg1, |
| 765 | ARRAY_SIZE(timberdale_cells_bar0_cfg1), | 765 | ARRAY_SIZE(timberdale_cells_bar0_cfg1), |
| 766 | &dev->resource[0], msix_entries[0].vector); | 766 | &dev->resource[0], msix_entries[0].vector, NULL); |
| 767 | break; | 767 | break; |
| 768 | case TIMB_HW_VER2: | 768 | case TIMB_HW_VER2: |
| 769 | err = mfd_add_devices(&dev->dev, -1, | 769 | err = mfd_add_devices(&dev->dev, -1, |
| 770 | timberdale_cells_bar0_cfg2, | 770 | timberdale_cells_bar0_cfg2, |
| 771 | ARRAY_SIZE(timberdale_cells_bar0_cfg2), | 771 | ARRAY_SIZE(timberdale_cells_bar0_cfg2), |
| 772 | &dev->resource[0], msix_entries[0].vector); | 772 | &dev->resource[0], msix_entries[0].vector, NULL); |
| 773 | break; | 773 | break; |
| 774 | case TIMB_HW_VER3: | 774 | case TIMB_HW_VER3: |
| 775 | err = mfd_add_devices(&dev->dev, -1, | 775 | err = mfd_add_devices(&dev->dev, -1, |
| 776 | timberdale_cells_bar0_cfg3, | 776 | timberdale_cells_bar0_cfg3, |
| 777 | ARRAY_SIZE(timberdale_cells_bar0_cfg3), | 777 | ARRAY_SIZE(timberdale_cells_bar0_cfg3), |
| 778 | &dev->resource[0], msix_entries[0].vector); | 778 | &dev->resource[0], msix_entries[0].vector, NULL); |
| 779 | break; | 779 | break; |
| 780 | default: | 780 | default: |
| 781 | dev_err(&dev->dev, "Uknown IP setup: %d.%d.%d\n", | 781 | dev_err(&dev->dev, "Uknown IP setup: %d.%d.%d\n", |
| @@ -792,7 +792,7 @@ static int __devinit timb_probe(struct pci_dev *dev, | |||
| 792 | 792 | ||
| 793 | err = mfd_add_devices(&dev->dev, 0, | 793 | err = mfd_add_devices(&dev->dev, 0, |
| 794 | timberdale_cells_bar1, ARRAY_SIZE(timberdale_cells_bar1), | 794 | timberdale_cells_bar1, ARRAY_SIZE(timberdale_cells_bar1), |
| 795 | &dev->resource[1], msix_entries[0].vector); | 795 | &dev->resource[1], msix_entries[0].vector, NULL); |
| 796 | if (err) { | 796 | if (err) { |
| 797 | dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err); | 797 | dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err); |
| 798 | goto err_mfd2; | 798 | goto err_mfd2; |
| @@ -803,7 +803,7 @@ static int __devinit timb_probe(struct pci_dev *dev, | |||
| 803 | ((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER3)) { | 803 | ((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER3)) { |
| 804 | err = mfd_add_devices(&dev->dev, 1, timberdale_cells_bar2, | 804 | err = mfd_add_devices(&dev->dev, 1, timberdale_cells_bar2, |
| 805 | ARRAY_SIZE(timberdale_cells_bar2), | 805 | ARRAY_SIZE(timberdale_cells_bar2), |
| 806 | &dev->resource[2], msix_entries[0].vector); | 806 | &dev->resource[2], msix_entries[0].vector, NULL); |
| 807 | if (err) { | 807 | if (err) { |
| 808 | dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err); | 808 | dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err); |
| 809 | goto err_mfd2; | 809 | goto err_mfd2; |
diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c index a293b978e27c..14051bdc714b 100644 --- a/drivers/mfd/tps6105x.c +++ b/drivers/mfd/tps6105x.c | |||
| @@ -188,7 +188,7 @@ static int __devinit tps6105x_probe(struct i2c_client *client, | |||
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | ret = mfd_add_devices(&client->dev, 0, tps6105x_cells, | 190 | ret = mfd_add_devices(&client->dev, 0, tps6105x_cells, |
| 191 | ARRAY_SIZE(tps6105x_cells), NULL, 0); | 191 | ARRAY_SIZE(tps6105x_cells), NULL, 0, NULL); |
| 192 | if (ret) | 192 | if (ret) |
| 193 | goto fail; | 193 | goto fail; |
| 194 | 194 | ||
diff --git a/drivers/mfd/tps6507x.c b/drivers/mfd/tps6507x.c index 33ba7723c967..1b203499c744 100644 --- a/drivers/mfd/tps6507x.c +++ b/drivers/mfd/tps6507x.c | |||
| @@ -100,7 +100,7 @@ static int tps6507x_i2c_probe(struct i2c_client *i2c, | |||
| 100 | 100 | ||
| 101 | ret = mfd_add_devices(tps6507x->dev, -1, | 101 | ret = mfd_add_devices(tps6507x->dev, -1, |
| 102 | tps6507x_devs, ARRAY_SIZE(tps6507x_devs), | 102 | tps6507x_devs, ARRAY_SIZE(tps6507x_devs), |
| 103 | NULL, 0); | 103 | NULL, 0, NULL); |
| 104 | 104 | ||
| 105 | if (ret < 0) | 105 | if (ret < 0) |
| 106 | goto err; | 106 | goto err; |
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index 80e24f4b47bf..50fd87c87a1c 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c | |||
| @@ -292,7 +292,7 @@ static int __devinit tps65090_i2c_probe(struct i2c_client *client, | |||
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | ret = mfd_add_devices(tps65090->dev, -1, tps65090s, | 294 | ret = mfd_add_devices(tps65090->dev, -1, tps65090s, |
| 295 | ARRAY_SIZE(tps65090s), NULL, 0); | 295 | ARRAY_SIZE(tps65090s), NULL, 0, NULL); |
| 296 | if (ret) { | 296 | if (ret) { |
| 297 | dev_err(&client->dev, "add mfd devices failed with err: %d\n", | 297 | dev_err(&client->dev, "add mfd devices failed with err: %d\n", |
| 298 | ret); | 298 | ret); |
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 61c097a98f5d..a95e9421b735 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c | |||
| @@ -24,11 +24,18 @@ | |||
| 24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
| 25 | #include <linux/regmap.h> | 25 | #include <linux/regmap.h> |
| 26 | #include <linux/err.h> | 26 | #include <linux/err.h> |
| 27 | #include <linux/regulator/of_regulator.h> | 27 | #include <linux/of.h> |
| 28 | #include <linux/of_device.h> | ||
| 28 | 29 | ||
| 29 | #include <linux/mfd/core.h> | 30 | #include <linux/mfd/core.h> |
| 30 | #include <linux/mfd/tps65217.h> | 31 | #include <linux/mfd/tps65217.h> |
| 31 | 32 | ||
| 33 | static struct mfd_cell tps65217s[] = { | ||
| 34 | { | ||
| 35 | .name = "tps65217-pmic", | ||
| 36 | }, | ||
| 37 | }; | ||
| 38 | |||
| 32 | /** | 39 | /** |
| 33 | * tps65217_reg_read: Read a single tps65217 register. | 40 | * tps65217_reg_read: Read a single tps65217 register. |
| 34 | * | 41 | * |
| @@ -133,83 +140,48 @@ int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg, | |||
| 133 | } | 140 | } |
| 134 | EXPORT_SYMBOL_GPL(tps65217_clear_bits); | 141 | EXPORT_SYMBOL_GPL(tps65217_clear_bits); |
| 135 | 142 | ||
| 136 | #ifdef CONFIG_OF | ||
| 137 | static struct of_regulator_match reg_matches[] = { | ||
| 138 | { .name = "dcdc1", .driver_data = (void *)TPS65217_DCDC_1 }, | ||
| 139 | { .name = "dcdc2", .driver_data = (void *)TPS65217_DCDC_2 }, | ||
| 140 | { .name = "dcdc3", .driver_data = (void *)TPS65217_DCDC_3 }, | ||
| 141 | { .name = "ldo1", .driver_data = (void *)TPS65217_LDO_1 }, | ||
| 142 | { .name = "ldo2", .driver_data = (void *)TPS65217_LDO_2 }, | ||
| 143 | { .name = "ldo3", .driver_data = (void *)TPS65217_LDO_3 }, | ||
| 144 | { .name = "ldo4", .driver_data = (void *)TPS65217_LDO_4 }, | ||
| 145 | }; | ||
| 146 | |||
| 147 | static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client) | ||
| 148 | { | ||
| 149 | struct device_node *node = client->dev.of_node; | ||
| 150 | struct tps65217_board *pdata; | ||
| 151 | struct device_node *regs; | ||
| 152 | int count = ARRAY_SIZE(reg_matches); | ||
| 153 | int ret, i; | ||
| 154 | |||
| 155 | regs = of_find_node_by_name(node, "regulators"); | ||
| 156 | if (!regs) | ||
| 157 | return NULL; | ||
| 158 | |||
| 159 | ret = of_regulator_match(&client->dev, regs, reg_matches, count); | ||
| 160 | of_node_put(regs); | ||
| 161 | if ((ret < 0) || (ret > count)) | ||
| 162 | return NULL; | ||
| 163 | |||
| 164 | count = ret; | ||
| 165 | pdata = devm_kzalloc(&client->dev, count * sizeof(*pdata), GFP_KERNEL); | ||
| 166 | if (!pdata) | ||
| 167 | return NULL; | ||
| 168 | |||
| 169 | for (i = 0; i < count; i++) { | ||
| 170 | if (!reg_matches[i].init_data || !reg_matches[i].of_node) | ||
| 171 | continue; | ||
| 172 | |||
| 173 | pdata->tps65217_init_data[i] = reg_matches[i].init_data; | ||
| 174 | pdata->of_node[i] = reg_matches[i].of_node; | ||
| 175 | } | ||
| 176 | |||
| 177 | return pdata; | ||
| 178 | } | ||
| 179 | |||
| 180 | static struct of_device_id tps65217_of_match[] = { | ||
| 181 | { .compatible = "ti,tps65217", }, | ||
| 182 | { }, | ||
| 183 | }; | ||
| 184 | #else | ||
| 185 | static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client) | ||
| 186 | { | ||
| 187 | return NULL; | ||
| 188 | } | ||
| 189 | #endif | ||
| 190 | |||
| 191 | static struct regmap_config tps65217_regmap_config = { | 143 | static struct regmap_config tps65217_regmap_config = { |
| 192 | .reg_bits = 8, | 144 | .reg_bits = 8, |
| 193 | .val_bits = 8, | 145 | .val_bits = 8, |
| 194 | }; | 146 | }; |
| 195 | 147 | ||
| 148 | static const struct of_device_id tps65217_of_match[] = { | ||
| 149 | { .compatible = "ti,tps65217", .data = (void *)TPS65217 }, | ||
| 150 | { /* sentinel */ }, | ||
| 151 | }; | ||
| 152 | |||
| 196 | static int __devinit tps65217_probe(struct i2c_client *client, | 153 | static int __devinit tps65217_probe(struct i2c_client *client, |
| 197 | const struct i2c_device_id *ids) | 154 | const struct i2c_device_id *ids) |
| 198 | { | 155 | { |
| 199 | struct tps65217 *tps; | 156 | struct tps65217 *tps; |
| 200 | struct regulator_init_data *reg_data; | ||
| 201 | struct tps65217_board *pdata = client->dev.platform_data; | ||
| 202 | int i, ret; | ||
| 203 | unsigned int version; | 157 | unsigned int version; |
| 158 | unsigned int chip_id = ids->driver_data; | ||
| 159 | const struct of_device_id *match; | ||
| 160 | int ret; | ||
| 204 | 161 | ||
| 205 | if (!pdata && client->dev.of_node) | 162 | if (client->dev.of_node) { |
| 206 | pdata = tps65217_parse_dt(client); | 163 | match = of_match_device(tps65217_of_match, &client->dev); |
| 164 | if (!match) { | ||
| 165 | dev_err(&client->dev, | ||
| 166 | "Failed to find matching dt id\n"); | ||
| 167 | return -EINVAL; | ||
| 168 | } | ||
| 169 | chip_id = (unsigned int)match->data; | ||
| 170 | } | ||
| 171 | |||
| 172 | if (!chip_id) { | ||
| 173 | dev_err(&client->dev, "id is null.\n"); | ||
| 174 | return -ENODEV; | ||
| 175 | } | ||
| 207 | 176 | ||
| 208 | tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); | 177 | tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); |
| 209 | if (!tps) | 178 | if (!tps) |
| 210 | return -ENOMEM; | 179 | return -ENOMEM; |
| 211 | 180 | ||
| 212 | tps->pdata = pdata; | 181 | i2c_set_clientdata(client, tps); |
| 182 | tps->dev = &client->dev; | ||
| 183 | tps->id = chip_id; | ||
| 184 | |||
| 213 | tps->regmap = devm_regmap_init_i2c(client, &tps65217_regmap_config); | 185 | tps->regmap = devm_regmap_init_i2c(client, &tps65217_regmap_config); |
| 214 | if (IS_ERR(tps->regmap)) { | 186 | if (IS_ERR(tps->regmap)) { |
| 215 | ret = PTR_ERR(tps->regmap); | 187 | ret = PTR_ERR(tps->regmap); |
| @@ -218,8 +190,12 @@ static int __devinit tps65217_probe(struct i2c_client *client, | |||
| 218 | return ret; | 190 | return ret; |
| 219 | } | 191 | } |
| 220 | 192 | ||
| 221 | i2c_set_clientdata(client, tps); | 193 | ret = mfd_add_devices(tps->dev, -1, tps65217s, |
| 222 | tps->dev = &client->dev; | 194 | ARRAY_SIZE(tps65217s), NULL, 0, NULL); |
| 195 | if (ret < 0) { | ||
| 196 | dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret); | ||
| 197 | return ret; | ||
| 198 | } | ||
| 223 | 199 | ||
| 224 | ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version); | 200 | ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version); |
| 225 | if (ret < 0) { | 201 | if (ret < 0) { |
| @@ -232,41 +208,21 @@ static int __devinit tps65217_probe(struct i2c_client *client, | |||
| 232 | (version & TPS65217_CHIPID_CHIP_MASK) >> 4, | 208 | (version & TPS65217_CHIPID_CHIP_MASK) >> 4, |
| 233 | version & TPS65217_CHIPID_REV_MASK); | 209 | version & TPS65217_CHIPID_REV_MASK); |
| 234 | 210 | ||
| 235 | for (i = 0; i < TPS65217_NUM_REGULATOR; i++) { | ||
| 236 | struct platform_device *pdev; | ||
| 237 | |||
| 238 | pdev = platform_device_alloc("tps65217-pmic", i); | ||
| 239 | if (!pdev) { | ||
| 240 | dev_err(tps->dev, "Cannot create regulator %d\n", i); | ||
| 241 | continue; | ||
| 242 | } | ||
| 243 | |||
| 244 | pdev->dev.parent = tps->dev; | ||
| 245 | pdev->dev.of_node = pdata->of_node[i]; | ||
| 246 | reg_data = pdata->tps65217_init_data[i]; | ||
| 247 | platform_device_add_data(pdev, reg_data, sizeof(*reg_data)); | ||
| 248 | tps->regulator_pdev[i] = pdev; | ||
| 249 | |||
| 250 | platform_device_add(pdev); | ||
| 251 | } | ||
| 252 | |||
| 253 | return 0; | 211 | return 0; |
| 254 | } | 212 | } |
| 255 | 213 | ||
| 256 | static int __devexit tps65217_remove(struct i2c_client *client) | 214 | static int __devexit tps65217_remove(struct i2c_client *client) |
| 257 | { | 215 | { |
| 258 | struct tps65217 *tps = i2c_get_clientdata(client); | 216 | struct tps65217 *tps = i2c_get_clientdata(client); |
| 259 | int i; | ||
| 260 | 217 | ||
| 261 | for (i = 0; i < TPS65217_NUM_REGULATOR; i++) | 218 | mfd_remove_devices(tps->dev); |
| 262 | platform_device_unregister(tps->regulator_pdev[i]); | ||
| 263 | 219 | ||
| 264 | return 0; | 220 | return 0; |
| 265 | } | 221 | } |
| 266 | 222 | ||
| 267 | static const struct i2c_device_id tps65217_id_table[] = { | 223 | static const struct i2c_device_id tps65217_id_table[] = { |
| 268 | {"tps65217", 0xF0}, | 224 | {"tps65217", TPS65217}, |
| 269 | {/* end of list */} | 225 | { /* sentinel */ } |
| 270 | }; | 226 | }; |
| 271 | MODULE_DEVICE_TABLE(i2c, tps65217_id_table); | 227 | MODULE_DEVICE_TABLE(i2c, tps65217_id_table); |
| 272 | 228 | ||
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 353c34812120..345960ca2fd8 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/i2c.h> | 25 | #include <linux/i2c.h> |
| 26 | #include <linux/regmap.h> | 26 | #include <linux/regmap.h> |
| 27 | #include <linux/regulator/of_regulator.h> | 27 | #include <linux/regulator/of_regulator.h> |
| 28 | #include <linux/regulator/machine.h> | ||
| 28 | 29 | ||
| 29 | #include <linux/mfd/core.h> | 30 | #include <linux/mfd/core.h> |
| 30 | #include <linux/mfd/tps6586x.h> | 31 | #include <linux/mfd/tps6586x.h> |
| @@ -346,6 +347,7 @@ failed: | |||
| 346 | 347 | ||
| 347 | #ifdef CONFIG_OF | 348 | #ifdef CONFIG_OF |
| 348 | static struct of_regulator_match tps6586x_matches[] = { | 349 | static struct of_regulator_match tps6586x_matches[] = { |
| 350 | { .name = "sys", .driver_data = (void *)TPS6586X_ID_SYS }, | ||
| 349 | { .name = "sm0", .driver_data = (void *)TPS6586X_ID_SM_0 }, | 351 | { .name = "sm0", .driver_data = (void *)TPS6586X_ID_SM_0 }, |
| 350 | { .name = "sm1", .driver_data = (void *)TPS6586X_ID_SM_1 }, | 352 | { .name = "sm1", .driver_data = (void *)TPS6586X_ID_SM_1 }, |
| 351 | { .name = "sm2", .driver_data = (void *)TPS6586X_ID_SM_2 }, | 353 | { .name = "sm2", .driver_data = (void *)TPS6586X_ID_SM_2 }, |
| @@ -369,6 +371,7 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien | |||
| 369 | struct tps6586x_platform_data *pdata; | 371 | struct tps6586x_platform_data *pdata; |
| 370 | struct tps6586x_subdev_info *devs; | 372 | struct tps6586x_subdev_info *devs; |
| 371 | struct device_node *regs; | 373 | struct device_node *regs; |
| 374 | const char *sys_rail_name = NULL; | ||
| 372 | unsigned int count; | 375 | unsigned int count; |
| 373 | unsigned int i, j; | 376 | unsigned int i, j; |
| 374 | int err; | 377 | int err; |
| @@ -391,12 +394,22 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien | |||
| 391 | return NULL; | 394 | return NULL; |
| 392 | 395 | ||
| 393 | for (i = 0, j = 0; i < num && j < count; i++) { | 396 | for (i = 0, j = 0; i < num && j < count; i++) { |
| 397 | struct regulator_init_data *reg_idata; | ||
| 398 | |||
| 394 | if (!tps6586x_matches[i].init_data) | 399 | if (!tps6586x_matches[i].init_data) |
| 395 | continue; | 400 | continue; |
| 396 | 401 | ||
| 402 | reg_idata = tps6586x_matches[i].init_data; | ||
| 397 | devs[j].name = "tps6586x-regulator"; | 403 | devs[j].name = "tps6586x-regulator"; |
| 398 | devs[j].platform_data = tps6586x_matches[i].init_data; | 404 | devs[j].platform_data = tps6586x_matches[i].init_data; |
| 399 | devs[j].id = (int)tps6586x_matches[i].driver_data; | 405 | devs[j].id = (int)tps6586x_matches[i].driver_data; |
| 406 | if (devs[j].id == TPS6586X_ID_SYS) | ||
| 407 | sys_rail_name = reg_idata->constraints.name; | ||
| 408 | |||
| 409 | if ((devs[j].id == TPS6586X_ID_LDO_5) || | ||
| 410 | (devs[j].id == TPS6586X_ID_LDO_RTC)) | ||
| 411 | reg_idata->supply_regulator = sys_rail_name; | ||
| 412 | |||
| 400 | devs[j].of_node = tps6586x_matches[i].of_node; | 413 | devs[j].of_node = tps6586x_matches[i].of_node; |
| 401 | j++; | 414 | j++; |
| 402 | } | 415 | } |
| @@ -493,7 +506,8 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, | |||
| 493 | } | 506 | } |
| 494 | 507 | ||
| 495 | ret = mfd_add_devices(tps6586x->dev, -1, | 508 | ret = mfd_add_devices(tps6586x->dev, -1, |
| 496 | tps6586x_cell, ARRAY_SIZE(tps6586x_cell), NULL, 0); | 509 | tps6586x_cell, ARRAY_SIZE(tps6586x_cell), |
| 510 | NULL, 0, NULL); | ||
| 497 | if (ret < 0) { | 511 | if (ret < 0) { |
| 498 | dev_err(&client->dev, "mfd_add_devices failed: %d\n", ret); | 512 | dev_err(&client->dev, "mfd_add_devices failed: %d\n", ret); |
| 499 | goto err_mfd_add; | 513 | goto err_mfd_add; |
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 1c563792c777..d3ce4d569deb 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c | |||
| @@ -254,7 +254,7 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, | |||
| 254 | 254 | ||
| 255 | ret = mfd_add_devices(tps65910->dev, -1, | 255 | ret = mfd_add_devices(tps65910->dev, -1, |
| 256 | tps65910s, ARRAY_SIZE(tps65910s), | 256 | tps65910s, ARRAY_SIZE(tps65910s), |
| 257 | NULL, 0); | 257 | NULL, 0, NULL); |
| 258 | if (ret < 0) { | 258 | if (ret < 0) { |
| 259 | dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret); | 259 | dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret); |
| 260 | return ret; | 260 | return ret; |
diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c index 5a62e6bf89ae..0b6e361432c4 100644 --- a/drivers/mfd/tps65911-comparator.c +++ b/drivers/mfd/tps65911-comparator.c | |||
| @@ -136,7 +136,7 @@ static __devinit int tps65911_comparator_probe(struct platform_device *pdev) | |||
| 136 | 136 | ||
| 137 | ret = comp_threshold_set(tps65910, COMP2, pdata->vmbch2_threshold); | 137 | ret = comp_threshold_set(tps65910, COMP2, pdata->vmbch2_threshold); |
| 138 | if (ret < 0) { | 138 | if (ret < 0) { |
| 139 | dev_err(&pdev->dev, "cannot set COMP2 theshold\n"); | 139 | dev_err(&pdev->dev, "cannot set COMP2 threshold\n"); |
| 140 | return ret; | 140 | return ret; |
| 141 | } | 141 | } |
| 142 | 142 | ||
diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c index 74fd8cb5f372..4658b5bdcd84 100644 --- a/drivers/mfd/tps65912-core.c +++ b/drivers/mfd/tps65912-core.c | |||
| @@ -146,7 +146,7 @@ int tps65912_device_init(struct tps65912 *tps65912) | |||
| 146 | 146 | ||
| 147 | ret = mfd_add_devices(tps65912->dev, -1, | 147 | ret = mfd_add_devices(tps65912->dev, -1, |
| 148 | tps65912s, ARRAY_SIZE(tps65912s), | 148 | tps65912s, ARRAY_SIZE(tps65912s), |
| 149 | NULL, 0); | 149 | NULL, 0, NULL); |
| 150 | if (ret < 0) | 150 | if (ret < 0) |
| 151 | goto err; | 151 | goto err; |
| 152 | 152 | ||
diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 838ce4eb444e..77c9acb14583 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c | |||
| @@ -223,7 +223,7 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev) | |||
| 223 | 223 | ||
| 224 | if (childs) | 224 | if (childs) |
| 225 | ret = mfd_add_devices(&pdev->dev, pdev->id, audio->cells, | 225 | ret = mfd_add_devices(&pdev->dev, pdev->id, audio->cells, |
| 226 | childs, NULL, 0); | 226 | childs, NULL, 0, NULL); |
| 227 | else { | 227 | else { |
| 228 | dev_err(&pdev->dev, "No platform data found for childs\n"); | 228 | dev_err(&pdev->dev, "No platform data found for childs\n"); |
| 229 | ret = -ENODEV; | 229 | ret = -ENODEV; |
diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c index b0fad0ffca56..3dca5c195a20 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040-core.c | |||
| @@ -632,7 +632,7 @@ static int __devinit twl6040_probe(struct i2c_client *client, | |||
| 632 | } | 632 | } |
| 633 | 633 | ||
| 634 | ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children, | 634 | ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children, |
| 635 | NULL, 0); | 635 | NULL, 0, NULL); |
| 636 | if (ret) | 636 | if (ret) |
| 637 | goto mfd_err; | 637 | goto mfd_err; |
| 638 | 638 | ||
diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c index 872aff21e4be..b9a636d44c7f 100644 --- a/drivers/mfd/vx855.c +++ b/drivers/mfd/vx855.c | |||
| @@ -102,7 +102,7 @@ static __devinit int vx855_probe(struct pci_dev *pdev, | |||
| 102 | vx855_gpio_resources[1].end = vx855_gpio_resources[1].start + 3; | 102 | vx855_gpio_resources[1].end = vx855_gpio_resources[1].start + 3; |
| 103 | 103 | ||
| 104 | ret = mfd_add_devices(&pdev->dev, -1, vx855_cells, ARRAY_SIZE(vx855_cells), | 104 | ret = mfd_add_devices(&pdev->dev, -1, vx855_cells, ARRAY_SIZE(vx855_cells), |
| 105 | NULL, 0); | 105 | NULL, 0, NULL); |
| 106 | 106 | ||
| 107 | /* we always return -ENODEV here in order to enable other | 107 | /* we always return -ENODEV here in order to enable other |
| 108 | * drivers like old, not-yet-platform_device ported i2c-viapro */ | 108 | * drivers like old, not-yet-platform_device ported i2c-viapro */ |
diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index f39b756df561..86e0e4309fc2 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c | |||
| @@ -241,7 +241,7 @@ static int __devinit wl1273_core_probe(struct i2c_client *client, | |||
| 241 | __func__, children); | 241 | __func__, children); |
| 242 | 242 | ||
| 243 | r = mfd_add_devices(&client->dev, -1, core->cells, | 243 | r = mfd_add_devices(&client->dev, -1, core->cells, |
| 244 | children, NULL, 0); | 244 | children, NULL, 0, NULL); |
| 245 | if (r) | 245 | if (r) |
| 246 | goto err; | 246 | goto err; |
| 247 | 247 | ||
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 946698fd2dc6..301731035940 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c | |||
| @@ -1813,27 +1813,27 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
| 1813 | case WM8310: | 1813 | case WM8310: |
| 1814 | ret = mfd_add_devices(wm831x->dev, wm831x_num, | 1814 | ret = mfd_add_devices(wm831x->dev, wm831x_num, |
| 1815 | wm8310_devs, ARRAY_SIZE(wm8310_devs), | 1815 | wm8310_devs, ARRAY_SIZE(wm8310_devs), |
| 1816 | NULL, 0); | 1816 | NULL, 0, NULL); |
| 1817 | break; | 1817 | break; |
| 1818 | 1818 | ||
| 1819 | case WM8311: | 1819 | case WM8311: |
| 1820 | ret = mfd_add_devices(wm831x->dev, wm831x_num, | 1820 | ret = mfd_add_devices(wm831x->dev, wm831x_num, |
| 1821 | wm8311_devs, ARRAY_SIZE(wm8311_devs), | 1821 | wm8311_devs, ARRAY_SIZE(wm8311_devs), |
| 1822 | NULL, 0); | 1822 | NULL, 0, NULL); |
| 1823 | if (!pdata || !pdata->disable_touch) | 1823 | if (!pdata || !pdata->disable_touch) |
| 1824 | mfd_add_devices(wm831x->dev, wm831x_num, | 1824 | mfd_add_devices(wm831x->dev, wm831x_num, |
| 1825 | touch_devs, ARRAY_SIZE(touch_devs), | 1825 | touch_devs, ARRAY_SIZE(touch_devs), |
| 1826 | NULL, 0); | 1826 | NULL, 0, NULL); |
| 1827 | break; | 1827 | break; |
| 1828 | 1828 | ||
| 1829 | case WM8312: | 1829 | case WM8312: |
| 1830 | ret = mfd_add_devices(wm831x->dev, wm831x_num, | 1830 | ret = mfd_add_devices(wm831x->dev, wm831x_num, |
| 1831 | wm8312_devs, ARRAY_SIZE(wm8312_devs), | 1831 | wm8312_devs, ARRAY_SIZE(wm8312_devs), |
| 1832 | NULL, 0); | 1832 | NULL, 0, NULL); |
| 1833 | if (!pdata || !pdata->disable_touch) | 1833 | if (!pdata || !pdata->disable_touch) |
| 1834 | mfd_add_devices(wm831x->dev, wm831x_num, | 1834 | mfd_add_devices(wm831x->dev, wm831x_num, |
| 1835 | touch_devs, ARRAY_SIZE(touch_devs), | 1835 | touch_devs, ARRAY_SIZE(touch_devs), |
| 1836 | NULL, 0); | 1836 | NULL, 0, NULL); |
| 1837 | break; | 1837 | break; |
| 1838 | 1838 | ||
| 1839 | case WM8320: | 1839 | case WM8320: |
| @@ -1842,7 +1842,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
| 1842 | case WM8326: | 1842 | case WM8326: |
| 1843 | ret = mfd_add_devices(wm831x->dev, wm831x_num, | 1843 | ret = mfd_add_devices(wm831x->dev, wm831x_num, |
| 1844 | wm8320_devs, ARRAY_SIZE(wm8320_devs), | 1844 | wm8320_devs, ARRAY_SIZE(wm8320_devs), |
| 1845 | NULL, 0); | 1845 | NULL, 0, NULL); |
| 1846 | break; | 1846 | break; |
| 1847 | 1847 | ||
| 1848 | default: | 1848 | default: |
| @@ -1867,7 +1867,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
| 1867 | if (ret & WM831X_XTAL_ENA) { | 1867 | if (ret & WM831X_XTAL_ENA) { |
| 1868 | ret = mfd_add_devices(wm831x->dev, wm831x_num, | 1868 | ret = mfd_add_devices(wm831x->dev, wm831x_num, |
| 1869 | rtc_devs, ARRAY_SIZE(rtc_devs), | 1869 | rtc_devs, ARRAY_SIZE(rtc_devs), |
| 1870 | NULL, 0); | 1870 | NULL, 0, NULL); |
| 1871 | if (ret != 0) { | 1871 | if (ret != 0) { |
| 1872 | dev_err(wm831x->dev, "Failed to add RTC: %d\n", ret); | 1872 | dev_err(wm831x->dev, "Failed to add RTC: %d\n", ret); |
| 1873 | goto err_irq; | 1873 | goto err_irq; |
| @@ -1880,7 +1880,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
| 1880 | /* Treat errors as non-critical */ | 1880 | /* Treat errors as non-critical */ |
| 1881 | ret = mfd_add_devices(wm831x->dev, wm831x_num, backlight_devs, | 1881 | ret = mfd_add_devices(wm831x->dev, wm831x_num, backlight_devs, |
| 1882 | ARRAY_SIZE(backlight_devs), NULL, | 1882 | ARRAY_SIZE(backlight_devs), NULL, |
| 1883 | 0); | 1883 | 0, NULL); |
| 1884 | if (ret < 0) | 1884 | if (ret < 0) |
| 1885 | dev_err(wm831x->dev, "Failed to add backlight: %d\n", | 1885 | dev_err(wm831x->dev, "Failed to add backlight: %d\n", |
| 1886 | ret); | 1886 | ret); |
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 4b7d378551d5..639ca359242f 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c | |||
| @@ -70,7 +70,7 @@ static int wm8400_register_codec(struct wm8400 *wm8400) | |||
| 70 | .pdata_size = sizeof(*wm8400), | 70 | .pdata_size = sizeof(*wm8400), |
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0); | 73 | return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0, NULL); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | /* | 76 | /* |
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index eec74aa55fdf..2febf88cfce8 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c | |||
| @@ -414,7 +414,7 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
| 414 | ret = mfd_add_devices(wm8994->dev, -1, | 414 | ret = mfd_add_devices(wm8994->dev, -1, |
| 415 | wm8994_regulator_devs, | 415 | wm8994_regulator_devs, |
| 416 | ARRAY_SIZE(wm8994_regulator_devs), | 416 | ARRAY_SIZE(wm8994_regulator_devs), |
| 417 | NULL, 0); | 417 | NULL, 0, NULL); |
| 418 | if (ret != 0) { | 418 | if (ret != 0) { |
| 419 | dev_err(wm8994->dev, "Failed to add children: %d\n", ret); | 419 | dev_err(wm8994->dev, "Failed to add children: %d\n", ret); |
| 420 | goto err; | 420 | goto err; |
| @@ -648,7 +648,7 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
| 648 | 648 | ||
| 649 | ret = mfd_add_devices(wm8994->dev, -1, | 649 | ret = mfd_add_devices(wm8994->dev, -1, |
| 650 | wm8994_devs, ARRAY_SIZE(wm8994_devs), | 650 | wm8994_devs, ARRAY_SIZE(wm8994_devs), |
| 651 | NULL, 0); | 651 | NULL, 0, NULL); |
| 652 | if (ret != 0) { | 652 | if (ret != 0) { |
| 653 | dev_err(wm8994->dev, "Failed to add children: %d\n", ret); | 653 | dev_err(wm8994->dev, "Failed to add children: %d\n", ret); |
| 654 | goto err_irq; | 654 | goto err_irq; |
diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index 0aac4aff17a5..a050e56a9bbd 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c | |||
| @@ -135,6 +135,7 @@ static struct regmap_irq_chip wm8994_irq_chip = { | |||
| 135 | .status_base = WM8994_INTERRUPT_STATUS_1, | 135 | .status_base = WM8994_INTERRUPT_STATUS_1, |
| 136 | .mask_base = WM8994_INTERRUPT_STATUS_1_MASK, | 136 | .mask_base = WM8994_INTERRUPT_STATUS_1_MASK, |
| 137 | .ack_base = WM8994_INTERRUPT_STATUS_1, | 137 | .ack_base = WM8994_INTERRUPT_STATUS_1, |
| 138 | .runtime_pm = true, | ||
| 138 | }; | 139 | }; |
| 139 | 140 | ||
| 140 | int wm8994_irq_init(struct wm8994 *wm8994) | 141 | int wm8994_irq_init(struct wm8994 *wm8994) |
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index d4619e2ec030..2273ce6b6c1a 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c | |||
| @@ -641,7 +641,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, | |||
| 641 | /* | 641 | /* |
| 642 | * If the host and card support UHS-I mode request the card | 642 | * If the host and card support UHS-I mode request the card |
| 643 | * to switch to 1.8V signaling level. No 1.8v signalling if | 643 | * to switch to 1.8V signaling level. No 1.8v signalling if |
| 644 | * UHS mode is not enabled to maintain compatibilty and some | 644 | * UHS mode is not enabled to maintain compatibility and some |
| 645 | * systems that claim 1.8v signalling in fact do not support | 645 | * systems that claim 1.8v signalling in fact do not support |
| 646 | * it. | 646 | * it. |
| 647 | */ | 647 | */ |
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index efdb81d21c44..74bed0fc23e7 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c | |||
| @@ -356,7 +356,7 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host) | |||
| 356 | } | 356 | } |
| 357 | 357 | ||
| 358 | /* | 358 | /* |
| 359 | * Update bytes tranfered count during a write operation | 359 | * Update bytes transfered count during a write operation |
| 360 | */ | 360 | */ |
| 361 | static void at91_mci_update_bytes_xfered(struct at91mci_host *host) | 361 | static void at91_mci_update_bytes_xfered(struct at91mci_host *host) |
| 362 | { | 362 | { |
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index a53c7c478e05..852d5fbda630 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c | |||
| @@ -1022,7 +1022,7 @@ static void atmci_stop_transfer(struct atmel_mci *host) | |||
| 1022 | } | 1022 | } |
| 1023 | 1023 | ||
| 1024 | /* | 1024 | /* |
| 1025 | * Stop data transfer because error(s) occured. | 1025 | * Stop data transfer because error(s) occurred. |
| 1026 | */ | 1026 | */ |
| 1027 | static void atmci_stop_transfer_pdc(struct atmel_mci *host) | 1027 | static void atmci_stop_transfer_pdc(struct atmel_mci *host) |
| 1028 | { | 1028 | { |
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 3a09f93cc3b6..686e256764c8 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c | |||
| @@ -447,7 +447,7 @@ static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host) | |||
| 447 | OMAP_HSMMC_WRITE(host->base, SYSCTL, | 447 | OMAP_HSMMC_WRITE(host->base, SYSCTL, |
| 448 | OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN); | 448 | OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN); |
| 449 | if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0) | 449 | if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0) |
| 450 | dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n"); | 450 | dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stopped\n"); |
| 451 | } | 451 | } |
| 452 | 452 | ||
| 453 | static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host, | 453 | static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host, |
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index e23f8134591c..32f4a070551f 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c | |||
| @@ -315,7 +315,7 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) | |||
| 315 | new_val = val & (SDHCI_CTRL_LED | \ | 315 | new_val = val & (SDHCI_CTRL_LED | \ |
| 316 | SDHCI_CTRL_4BITBUS | \ | 316 | SDHCI_CTRL_4BITBUS | \ |
| 317 | SDHCI_CTRL_D3CD); | 317 | SDHCI_CTRL_D3CD); |
| 318 | /* ensure the endianess */ | 318 | /* ensure the endianness */ |
| 319 | new_val |= ESDHC_HOST_CONTROL_LE; | 319 | new_val |= ESDHC_HOST_CONTROL_LE; |
| 320 | /* bits 8&9 are reserved on mx25 */ | 320 | /* bits 8&9 are reserved on mx25 */ |
| 321 | if (!is_imx25_esdhc(imx_data)) { | 321 | if (!is_imx25_esdhc(imx_data)) { |
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index 3135a1a5d75d..58eab9ac1d01 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c | |||
| @@ -806,7 +806,7 @@ static void command_res_completed(struct urb *urb) | |||
| 806 | * we suspect a buggy USB host controller | 806 | * we suspect a buggy USB host controller |
| 807 | */ | 807 | */ |
| 808 | } else if (!vub300->data) { | 808 | } else if (!vub300->data) { |
| 809 | /* this means that the command (typically CMD52) suceeded */ | 809 | /* this means that the command (typically CMD52) succeeded */ |
| 810 | } else if (vub300->resp.common.header_type != 0x02) { | 810 | } else if (vub300->resp.common.header_type != 0x02) { |
| 811 | /* | 811 | /* |
| 812 | * this is an error response from the VUB300 chip | 812 | * this is an error response from the VUB300 chip |
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index f2f482bec573..a6e74514e662 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
| @@ -1123,6 +1123,33 @@ static unsigned long mtdchar_get_unmapped_area(struct file *file, | |||
| 1123 | } | 1123 | } |
| 1124 | #endif | 1124 | #endif |
| 1125 | 1125 | ||
| 1126 | static inline unsigned long get_vm_size(struct vm_area_struct *vma) | ||
| 1127 | { | ||
| 1128 | return vma->vm_end - vma->vm_start; | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | static inline resource_size_t get_vm_offset(struct vm_area_struct *vma) | ||
| 1132 | { | ||
| 1133 | return (resource_size_t) vma->vm_pgoff << PAGE_SHIFT; | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | /* | ||
| 1137 | * Set a new vm offset. | ||
| 1138 | * | ||
| 1139 | * Verify that the incoming offset really works as a page offset, | ||
| 1140 | * and that the offset and size fit in a resource_size_t. | ||
| 1141 | */ | ||
| 1142 | static inline int set_vm_offset(struct vm_area_struct *vma, resource_size_t off) | ||
| 1143 | { | ||
| 1144 | pgoff_t pgoff = off >> PAGE_SHIFT; | ||
| 1145 | if (off != (resource_size_t) pgoff << PAGE_SHIFT) | ||
| 1146 | return -EINVAL; | ||
| 1147 | if (off + get_vm_size(vma) - 1 < off) | ||
| 1148 | return -EINVAL; | ||
| 1149 | vma->vm_pgoff = pgoff; | ||
| 1150 | return 0; | ||
| 1151 | } | ||
| 1152 | |||
| 1126 | /* | 1153 | /* |
| 1127 | * set up a mapping for shared memory segments | 1154 | * set up a mapping for shared memory segments |
| 1128 | */ | 1155 | */ |
| @@ -1132,20 +1159,29 @@ static int mtdchar_mmap(struct file *file, struct vm_area_struct *vma) | |||
| 1132 | struct mtd_file_info *mfi = file->private_data; | 1159 | struct mtd_file_info *mfi = file->private_data; |
| 1133 | struct mtd_info *mtd = mfi->mtd; | 1160 | struct mtd_info *mtd = mfi->mtd; |
| 1134 | struct map_info *map = mtd->priv; | 1161 | struct map_info *map = mtd->priv; |
| 1135 | unsigned long start; | 1162 | resource_size_t start, off; |
| 1136 | unsigned long off; | 1163 | unsigned long len, vma_len; |
| 1137 | u32 len; | ||
| 1138 | 1164 | ||
| 1139 | if (mtd->type == MTD_RAM || mtd->type == MTD_ROM) { | 1165 | if (mtd->type == MTD_RAM || mtd->type == MTD_ROM) { |
| 1140 | off = vma->vm_pgoff << PAGE_SHIFT; | 1166 | off = get_vm_offset(vma); |
| 1141 | start = map->phys; | 1167 | start = map->phys; |
| 1142 | len = PAGE_ALIGN((start & ~PAGE_MASK) + map->size); | 1168 | len = PAGE_ALIGN((start & ~PAGE_MASK) + map->size); |
| 1143 | start &= PAGE_MASK; | 1169 | start &= PAGE_MASK; |
| 1144 | if ((vma->vm_end - vma->vm_start + off) > len) | 1170 | vma_len = get_vm_size(vma); |
| 1171 | |||
| 1172 | /* Overflow in off+len? */ | ||
| 1173 | if (vma_len + off < off) | ||
| 1174 | return -EINVAL; | ||
| 1175 | /* Does it fit in the mapping? */ | ||
| 1176 | if (vma_len + off > len) | ||
| 1145 | return -EINVAL; | 1177 | return -EINVAL; |
| 1146 | 1178 | ||
| 1147 | off += start; | 1179 | off += start; |
| 1148 | vma->vm_pgoff = off >> PAGE_SHIFT; | 1180 | /* Did that overflow? */ |
| 1181 | if (off < start) | ||
| 1182 | return -EINVAL; | ||
| 1183 | if (set_vm_offset(vma, off) < 0) | ||
| 1184 | return -EINVAL; | ||
| 1149 | vma->vm_flags |= VM_IO | VM_RESERVED; | 1185 | vma->vm_flags |= VM_IO | VM_RESERVED; |
| 1150 | 1186 | ||
| 1151 | #ifdef pgprot_noncached | 1187 | #ifdef pgprot_noncached |
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 98ee43819911..7edadee487ba 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c | |||
| @@ -1391,7 +1391,6 @@ static irqreturn_t ican3_irq(int irq, void *dev_id) | |||
| 1391 | */ | 1391 | */ |
| 1392 | static int ican3_reset_module(struct ican3_dev *mod) | 1392 | static int ican3_reset_module(struct ican3_dev *mod) |
| 1393 | { | 1393 | { |
| 1394 | u8 val = 1 << mod->num; | ||
| 1395 | unsigned long start; | 1394 | unsigned long start; |
| 1396 | u8 runold, runnew; | 1395 | u8 runold, runnew; |
| 1397 | 1396 | ||
| @@ -1405,8 +1404,7 @@ static int ican3_reset_module(struct ican3_dev *mod) | |||
| 1405 | runold = ioread8(mod->dpm + TARGET_RUNNING); | 1404 | runold = ioread8(mod->dpm + TARGET_RUNNING); |
| 1406 | 1405 | ||
| 1407 | /* reset the module */ | 1406 | /* reset the module */ |
| 1408 | iowrite8(val, &mod->ctrl->reset_assert); | 1407 | iowrite8(0x00, &mod->dpmctrl->hwreset); |
| 1409 | iowrite8(val, &mod->ctrl->reset_deassert); | ||
| 1410 | 1408 | ||
| 1411 | /* wait until the module has finished resetting and is running */ | 1409 | /* wait until the module has finished resetting and is running */ |
| 1412 | start = jiffies; | 1410 | start = jiffies; |
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index a580db29e503..26e7129332ab 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c | |||
| @@ -83,6 +83,11 @@ | |||
| 83 | #define INSTRUCTION_LOAD_TXB(n) (0x40 + 2 * (n)) | 83 | #define INSTRUCTION_LOAD_TXB(n) (0x40 + 2 * (n)) |
| 84 | #define INSTRUCTION_READ_RXB(n) (((n) == 0) ? 0x90 : 0x94) | 84 | #define INSTRUCTION_READ_RXB(n) (((n) == 0) ? 0x90 : 0x94) |
| 85 | #define INSTRUCTION_RESET 0xC0 | 85 | #define INSTRUCTION_RESET 0xC0 |
| 86 | #define RTS_TXB0 0x01 | ||
| 87 | #define RTS_TXB1 0x02 | ||
| 88 | #define RTS_TXB2 0x04 | ||
| 89 | #define INSTRUCTION_RTS(n) (0x80 | ((n) & 0x07)) | ||
| 90 | |||
| 86 | 91 | ||
| 87 | /* MPC251x registers */ | 92 | /* MPC251x registers */ |
| 88 | #define CANSTAT 0x0e | 93 | #define CANSTAT 0x0e |
| @@ -397,6 +402,7 @@ static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf, | |||
| 397 | static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame, | 402 | static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame, |
| 398 | int tx_buf_idx) | 403 | int tx_buf_idx) |
| 399 | { | 404 | { |
| 405 | struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); | ||
| 400 | u32 sid, eid, exide, rtr; | 406 | u32 sid, eid, exide, rtr; |
| 401 | u8 buf[SPI_TRANSFER_BUF_LEN]; | 407 | u8 buf[SPI_TRANSFER_BUF_LEN]; |
| 402 | 408 | ||
| @@ -418,7 +424,10 @@ static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame, | |||
| 418 | buf[TXBDLC_OFF] = (rtr << DLC_RTR_SHIFT) | frame->can_dlc; | 424 | buf[TXBDLC_OFF] = (rtr << DLC_RTR_SHIFT) | frame->can_dlc; |
| 419 | memcpy(buf + TXBDAT_OFF, frame->data, frame->can_dlc); | 425 | memcpy(buf + TXBDAT_OFF, frame->data, frame->can_dlc); |
| 420 | mcp251x_hw_tx_frame(spi, buf, frame->can_dlc, tx_buf_idx); | 426 | mcp251x_hw_tx_frame(spi, buf, frame->can_dlc, tx_buf_idx); |
| 421 | mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ); | 427 | |
| 428 | /* use INSTRUCTION_RTS, to avoid "repeated frame problem" */ | ||
| 429 | priv->spi_tx_buf[0] = INSTRUCTION_RTS(1 << tx_buf_idx); | ||
| 430 | mcp251x_spi_trans(priv->spi, 1); | ||
| 422 | } | 431 | } |
| 423 | 432 | ||
| 424 | static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf, | 433 | static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf, |
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 527dbcf95335..9ded21e79db5 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c | |||
| @@ -984,12 +984,12 @@ static int __devexit ti_hecc_remove(struct platform_device *pdev) | |||
| 984 | struct net_device *ndev = platform_get_drvdata(pdev); | 984 | struct net_device *ndev = platform_get_drvdata(pdev); |
| 985 | struct ti_hecc_priv *priv = netdev_priv(ndev); | 985 | struct ti_hecc_priv *priv = netdev_priv(ndev); |
| 986 | 986 | ||
| 987 | unregister_candev(ndev); | ||
| 987 | clk_disable(priv->clk); | 988 | clk_disable(priv->clk); |
| 988 | clk_put(priv->clk); | 989 | clk_put(priv->clk); |
| 989 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 990 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 990 | iounmap(priv->base); | 991 | iounmap(priv->base); |
| 991 | release_mem_region(res->start, resource_size(res)); | 992 | release_mem_region(res->start, resource_size(res)); |
| 992 | unregister_candev(ndev); | ||
| 993 | free_candev(ndev); | 993 | free_candev(ndev); |
| 994 | platform_set_drvdata(pdev, NULL); | 994 | platform_set_drvdata(pdev, NULL); |
| 995 | 995 | ||
diff --git a/drivers/net/ethernet/3com/typhoon.c b/drivers/net/ethernet/3com/typhoon.c index b15366635147..bb9670f29b59 100644 --- a/drivers/net/ethernet/3com/typhoon.c +++ b/drivers/net/ethernet/3com/typhoon.c | |||
| @@ -364,7 +364,7 @@ typhoon_inc_rxfree_index(u32 *index, const int count) | |||
| 364 | static inline void | 364 | static inline void |
| 365 | typhoon_inc_tx_index(u32 *index, const int count) | 365 | typhoon_inc_tx_index(u32 *index, const int count) |
| 366 | { | 366 | { |
| 367 | /* if we start using the Hi Tx ring, this needs updateing */ | 367 | /* if we start using the Hi Tx ring, this needs updating */ |
| 368 | typhoon_inc_index(index, count, TXLO_ENTRIES); | 368 | typhoon_inc_index(index, count, TXLO_ENTRIES); |
| 369 | } | 369 | } |
| 370 | 370 | ||
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index a0e8399793b6..d4310700c7a7 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c | |||
| @@ -8564,7 +8564,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 8564 | return 0; | 8564 | return 0; |
| 8565 | 8565 | ||
| 8566 | error: | 8566 | error: |
| 8567 | iounmap(bp->regview); | 8567 | pci_iounmap(pdev, bp->regview); |
| 8568 | pci_release_regions(pdev); | 8568 | pci_release_regions(pdev); |
| 8569 | pci_disable_device(pdev); | 8569 | pci_disable_device(pdev); |
| 8570 | pci_set_drvdata(pdev, NULL); | 8570 | pci_set_drvdata(pdev, NULL); |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 6d1a24acb77e..eac25236856c 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | |||
| @@ -1458,7 +1458,7 @@ struct bnx2x { | |||
| 1458 | int fw_stats_req_sz; | 1458 | int fw_stats_req_sz; |
| 1459 | 1459 | ||
| 1460 | /* | 1460 | /* |
| 1461 | * FW statistics data shortcut (points at the begining of | 1461 | * FW statistics data shortcut (points at the beginning of |
| 1462 | * fw_stats buffer + fw_stats_req_sz). | 1462 | * fw_stats buffer + fw_stats_req_sz). |
| 1463 | */ | 1463 | */ |
| 1464 | struct bnx2x_fw_stats_data *fw_stats_data; | 1464 | struct bnx2x_fw_stats_data *fw_stats_data; |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index af20c6ee2cd9..e8e97a7d1d06 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | |||
| @@ -662,14 +662,16 @@ void bnx2x_csum_validate(struct sk_buff *skb, union eth_rx_cqe *cqe, | |||
| 662 | struct bnx2x_fastpath *fp, | 662 | struct bnx2x_fastpath *fp, |
| 663 | struct bnx2x_eth_q_stats *qstats) | 663 | struct bnx2x_eth_q_stats *qstats) |
| 664 | { | 664 | { |
| 665 | /* Do nothing if no IP/L4 csum validation was done */ | 665 | /* Do nothing if no L4 csum validation was done. |
| 666 | 666 | * We do not check whether IP csum was validated. For IPv4 we assume | |
| 667 | * that if the card got as far as validating the L4 csum, it also | ||
| 668 | * validated the IP csum. IPv6 has no IP csum. | ||
| 669 | */ | ||
| 667 | if (cqe->fast_path_cqe.status_flags & | 670 | if (cqe->fast_path_cqe.status_flags & |
| 668 | (ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG | | 671 | ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG) |
| 669 | ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG)) | ||
| 670 | return; | 672 | return; |
| 671 | 673 | ||
| 672 | /* If both IP/L4 validation were done, check if an error was found. */ | 674 | /* If L4 validation was done, check if an error was found. */ |
| 673 | 675 | ||
| 674 | if (cqe->fast_path_cqe.type_error_flags & | 676 | if (cqe->fast_path_cqe.type_error_flags & |
| 675 | (ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG | | 677 | (ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG | |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 21b553229ea4..dfd86a55f1dc 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | |||
| @@ -710,17 +710,15 @@ static inline u16 bnx2x_tx_avail(struct bnx2x *bp, | |||
| 710 | prod = txdata->tx_bd_prod; | 710 | prod = txdata->tx_bd_prod; |
| 711 | cons = txdata->tx_bd_cons; | 711 | cons = txdata->tx_bd_cons; |
| 712 | 712 | ||
| 713 | /* NUM_TX_RINGS = number of "next-page" entries | 713 | used = SUB_S16(prod, cons); |
| 714 | It will be used as a threshold */ | ||
| 715 | used = SUB_S16(prod, cons) + (s16)NUM_TX_RINGS; | ||
| 716 | 714 | ||
| 717 | #ifdef BNX2X_STOP_ON_ERROR | 715 | #ifdef BNX2X_STOP_ON_ERROR |
| 718 | WARN_ON(used < 0); | 716 | WARN_ON(used < 0); |
| 719 | WARN_ON(used > bp->tx_ring_size); | 717 | WARN_ON(used > txdata->tx_ring_size); |
| 720 | WARN_ON((bp->tx_ring_size - used) > MAX_TX_AVAIL); | 718 | WARN_ON((txdata->tx_ring_size - used) > MAX_TX_AVAIL); |
| 721 | #endif | 719 | #endif |
| 722 | 720 | ||
| 723 | return (s16)(bp->tx_ring_size) - used; | 721 | return (s16)(txdata->tx_ring_size) - used; |
| 724 | } | 722 | } |
| 725 | 723 | ||
| 726 | static inline int bnx2x_tx_queue_has_work(struct bnx2x_fp_txdata *txdata) | 724 | static inline int bnx2x_tx_queue_has_work(struct bnx2x_fp_txdata *txdata) |
| @@ -1088,6 +1086,7 @@ static inline void bnx2x_init_txdata(struct bnx2x *bp, | |||
| 1088 | txdata->txq_index = txq_index; | 1086 | txdata->txq_index = txq_index; |
| 1089 | txdata->tx_cons_sb = tx_cons_sb; | 1087 | txdata->tx_cons_sb = tx_cons_sb; |
| 1090 | txdata->parent_fp = fp; | 1088 | txdata->parent_fp = fp; |
| 1089 | txdata->tx_ring_size = IS_FCOE_FP(fp) ? MAX_TX_AVAIL : bp->tx_ring_size; | ||
| 1091 | 1090 | ||
| 1092 | DP(NETIF_MSG_IFUP, "created tx data cid %d, txq %d\n", | 1091 | DP(NETIF_MSG_IFUP, "created tx data cid %d, txq %d\n", |
| 1093 | txdata->cid, txdata->txq_index); | 1092 | txdata->cid, txdata->txq_index); |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h index 3e4cff9b1ebe..b926f58e983b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h | |||
| @@ -401,11 +401,11 @@ static const struct reg_addr reg_addrs[] = { | |||
| 401 | { 0x70000, 8, RI_ALL_ONLINE }, | 401 | { 0x70000, 8, RI_ALL_ONLINE }, |
| 402 | { 0x70020, 8184, RI_ALL_OFFLINE }, | 402 | { 0x70020, 8184, RI_ALL_OFFLINE }, |
| 403 | { 0x78000, 8192, RI_E3E3B0_OFFLINE }, | 403 | { 0x78000, 8192, RI_E3E3B0_OFFLINE }, |
| 404 | { 0x85000, 3, RI_ALL_ONLINE }, | 404 | { 0x85000, 3, RI_ALL_OFFLINE }, |
| 405 | { 0x8501c, 7, RI_ALL_ONLINE }, | 405 | { 0x8501c, 7, RI_ALL_OFFLINE }, |
| 406 | { 0x85048, 1, RI_ALL_ONLINE }, | 406 | { 0x85048, 1, RI_ALL_OFFLINE }, |
| 407 | { 0x85200, 32, RI_ALL_ONLINE }, | 407 | { 0x85200, 32, RI_ALL_OFFLINE }, |
| 408 | { 0xb0000, 16384, RI_E1H_ONLINE }, | 408 | { 0xb0000, 16384, RI_E1H_OFFLINE }, |
| 409 | { 0xc1000, 7, RI_ALL_ONLINE }, | 409 | { 0xc1000, 7, RI_ALL_ONLINE }, |
| 410 | { 0xc103c, 2, RI_E2E3E3B0_ONLINE }, | 410 | { 0xc103c, 2, RI_E2E3E3B0_ONLINE }, |
| 411 | { 0xc1800, 2, RI_ALL_ONLINE }, | 411 | { 0xc1800, 2, RI_ALL_ONLINE }, |
| @@ -581,17 +581,12 @@ static const struct reg_addr reg_addrs[] = { | |||
| 581 | { 0x140188, 3, RI_E1E1HE2E3_ONLINE }, | 581 | { 0x140188, 3, RI_E1E1HE2E3_ONLINE }, |
| 582 | { 0x140194, 13, RI_ALL_ONLINE }, | 582 | { 0x140194, 13, RI_ALL_ONLINE }, |
| 583 | { 0x140200, 6, RI_E1E1HE2E3_ONLINE }, | 583 | { 0x140200, 6, RI_E1E1HE2E3_ONLINE }, |
| 584 | { 0x140220, 4, RI_E2E3_ONLINE }, | ||
| 585 | { 0x140240, 4, RI_E2E3_ONLINE }, | ||
| 586 | { 0x140260, 4, RI_E2E3_ONLINE }, | 584 | { 0x140260, 4, RI_E2E3_ONLINE }, |
| 587 | { 0x140280, 4, RI_E2E3_ONLINE }, | 585 | { 0x140280, 4, RI_E2E3_ONLINE }, |
| 588 | { 0x1402a0, 4, RI_E2E3_ONLINE }, | ||
| 589 | { 0x1402c0, 4, RI_E2E3_ONLINE }, | ||
| 590 | { 0x1402e0, 2, RI_E2E3_ONLINE }, | 586 | { 0x1402e0, 2, RI_E2E3_ONLINE }, |
| 591 | { 0x1402e8, 2, RI_E2E3E3B0_ONLINE }, | 587 | { 0x1402e8, 2, RI_E2E3E3B0_ONLINE }, |
| 592 | { 0x1402f0, 9, RI_E2E3_ONLINE }, | 588 | { 0x1402f0, 9, RI_E2E3_ONLINE }, |
| 593 | { 0x140314, 44, RI_E3B0_ONLINE }, | 589 | { 0x140314, 44, RI_E3B0_ONLINE }, |
| 594 | { 0x1403d0, 70, RI_E3B0_ONLINE }, | ||
| 595 | { 0x144000, 4, RI_E1E1H_ONLINE }, | 590 | { 0x144000, 4, RI_E1E1H_ONLINE }, |
| 596 | { 0x148000, 4, RI_E1E1H_ONLINE }, | 591 | { 0x148000, 4, RI_E1E1H_ONLINE }, |
| 597 | { 0x14c000, 4, RI_E1E1H_ONLINE }, | 592 | { 0x14c000, 4, RI_E1E1H_ONLINE }, |
| @@ -704,7 +699,6 @@ static const struct reg_addr reg_addrs[] = { | |||
| 704 | { 0x180398, 1, RI_E2E3E3B0_ONLINE }, | 699 | { 0x180398, 1, RI_E2E3E3B0_ONLINE }, |
| 705 | { 0x1803a0, 5, RI_E2E3E3B0_ONLINE }, | 700 | { 0x1803a0, 5, RI_E2E3E3B0_ONLINE }, |
| 706 | { 0x1803b4, 2, RI_E3E3B0_ONLINE }, | 701 | { 0x1803b4, 2, RI_E3E3B0_ONLINE }, |
| 707 | { 0x180400, 1, RI_ALL_ONLINE }, | ||
| 708 | { 0x180404, 255, RI_E1E1H_OFFLINE }, | 702 | { 0x180404, 255, RI_E1E1H_OFFLINE }, |
| 709 | { 0x181000, 4, RI_ALL_ONLINE }, | 703 | { 0x181000, 4, RI_ALL_ONLINE }, |
| 710 | { 0x181010, 1020, RI_ALL_OFFLINE }, | 704 | { 0x181010, 1020, RI_ALL_OFFLINE }, |
| @@ -800,9 +794,9 @@ static const struct reg_addr reg_addrs[] = { | |||
| 800 | { 0x1b905c, 1, RI_E3E3B0_ONLINE }, | 794 | { 0x1b905c, 1, RI_E3E3B0_ONLINE }, |
| 801 | { 0x1b9064, 1, RI_E3B0_ONLINE }, | 795 | { 0x1b9064, 1, RI_E3B0_ONLINE }, |
| 802 | { 0x1b9080, 10, RI_E3B0_ONLINE }, | 796 | { 0x1b9080, 10, RI_E3B0_ONLINE }, |
| 803 | { 0x1b9400, 14, RI_E2E3E3B0_ONLINE }, | 797 | { 0x1b9400, 14, RI_E2E3E3B0_OFFLINE }, |
| 804 | { 0x1b943c, 19, RI_E2E3E3B0_ONLINE }, | 798 | { 0x1b943c, 19, RI_E2E3E3B0_OFFLINE }, |
| 805 | { 0x1b9490, 10, RI_E2E3E3B0_ONLINE }, | 799 | { 0x1b9490, 10, RI_E2E3E3B0_OFFLINE }, |
| 806 | { 0x1c0000, 2, RI_ALL_ONLINE }, | 800 | { 0x1c0000, 2, RI_ALL_ONLINE }, |
| 807 | { 0x200000, 65, RI_ALL_ONLINE }, | 801 | { 0x200000, 65, RI_ALL_ONLINE }, |
| 808 | { 0x20014c, 2, RI_E1HE2E3E3B0_ONLINE }, | 802 | { 0x20014c, 2, RI_E1HE2E3E3B0_ONLINE }, |
| @@ -814,7 +808,6 @@ static const struct reg_addr reg_addrs[] = { | |||
| 814 | { 0x200398, 1, RI_E2E3E3B0_ONLINE }, | 808 | { 0x200398, 1, RI_E2E3E3B0_ONLINE }, |
| 815 | { 0x2003a0, 1, RI_E2E3E3B0_ONLINE }, | 809 | { 0x2003a0, 1, RI_E2E3E3B0_ONLINE }, |
| 816 | { 0x2003a8, 2, RI_E2E3E3B0_ONLINE }, | 810 | { 0x2003a8, 2, RI_E2E3E3B0_ONLINE }, |
| 817 | { 0x200400, 1, RI_ALL_ONLINE }, | ||
| 818 | { 0x200404, 255, RI_E1E1H_OFFLINE }, | 811 | { 0x200404, 255, RI_E1E1H_OFFLINE }, |
| 819 | { 0x202000, 4, RI_ALL_ONLINE }, | 812 | { 0x202000, 4, RI_ALL_ONLINE }, |
| 820 | { 0x202010, 2044, RI_ALL_OFFLINE }, | 813 | { 0x202010, 2044, RI_ALL_OFFLINE }, |
| @@ -921,7 +914,6 @@ static const struct reg_addr reg_addrs[] = { | |||
| 921 | { 0x280398, 1, RI_E2E3E3B0_ONLINE }, | 914 | { 0x280398, 1, RI_E2E3E3B0_ONLINE }, |
| 922 | { 0x2803a0, 1, RI_E2E3E3B0_ONLINE }, | 915 | { 0x2803a0, 1, RI_E2E3E3B0_ONLINE }, |
| 923 | { 0x2803a8, 2, RI_E2E3E3B0_ONLINE }, | 916 | { 0x2803a8, 2, RI_E2E3E3B0_ONLINE }, |
| 924 | { 0x280400, 1, RI_ALL_ONLINE }, | ||
| 925 | { 0x280404, 255, RI_E1E1H_OFFLINE }, | 917 | { 0x280404, 255, RI_E1E1H_OFFLINE }, |
| 926 | { 0x282000, 4, RI_ALL_ONLINE }, | 918 | { 0x282000, 4, RI_ALL_ONLINE }, |
| 927 | { 0x282010, 2044, RI_ALL_OFFLINE }, | 919 | { 0x282010, 2044, RI_ALL_OFFLINE }, |
| @@ -1031,7 +1023,6 @@ static const struct reg_addr reg_addrs[] = { | |||
| 1031 | { 0x300398, 1, RI_E2E3E3B0_ONLINE }, | 1023 | { 0x300398, 1, RI_E2E3E3B0_ONLINE }, |
| 1032 | { 0x3003a0, 1, RI_E2E3E3B0_ONLINE }, | 1024 | { 0x3003a0, 1, RI_E2E3E3B0_ONLINE }, |
| 1033 | { 0x3003a8, 2, RI_E2E3E3B0_ONLINE }, | 1025 | { 0x3003a8, 2, RI_E2E3E3B0_ONLINE }, |
| 1034 | { 0x300400, 1, RI_ALL_ONLINE }, | ||
| 1035 | { 0x300404, 255, RI_E1E1H_OFFLINE }, | 1026 | { 0x300404, 255, RI_E1E1H_OFFLINE }, |
| 1036 | { 0x302000, 4, RI_ALL_ONLINE }, | 1027 | { 0x302000, 4, RI_ALL_ONLINE }, |
| 1037 | { 0x302010, 2044, RI_ALL_OFFLINE }, | 1028 | { 0x302010, 2044, RI_ALL_OFFLINE }, |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index c37a68d68090..ebf40cd7aa10 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | |||
| @@ -775,7 +775,7 @@ static void bnx2x_get_regs(struct net_device *dev, | |||
| 775 | struct bnx2x *bp = netdev_priv(dev); | 775 | struct bnx2x *bp = netdev_priv(dev); |
| 776 | struct dump_hdr dump_hdr = {0}; | 776 | struct dump_hdr dump_hdr = {0}; |
| 777 | 777 | ||
| 778 | regs->version = 0; | 778 | regs->version = 1; |
| 779 | memset(p, 0, regs->len); | 779 | memset(p, 0, regs->len); |
| 780 | 780 | ||
| 781 | if (!netif_running(bp->dev)) | 781 | if (!netif_running(bp->dev)) |
| @@ -1587,6 +1587,12 @@ static int bnx2x_set_pauseparam(struct net_device *dev, | |||
| 1587 | bp->link_params.req_flow_ctrl[cfg_idx] = | 1587 | bp->link_params.req_flow_ctrl[cfg_idx] = |
| 1588 | BNX2X_FLOW_CTRL_AUTO; | 1588 | BNX2X_FLOW_CTRL_AUTO; |
| 1589 | } | 1589 | } |
| 1590 | bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_NONE; | ||
| 1591 | if (epause->rx_pause) | ||
| 1592 | bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_RX; | ||
| 1593 | |||
| 1594 | if (epause->tx_pause) | ||
| 1595 | bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_TX; | ||
| 1590 | } | 1596 | } |
| 1591 | 1597 | ||
| 1592 | DP(BNX2X_MSG_ETHTOOL, | 1598 | DP(BNX2X_MSG_ETHTOOL, |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index f4beb46c4709..b046beb435b2 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | |||
| @@ -2667,9 +2667,11 @@ int bnx2x_update_pfc(struct link_params *params, | |||
| 2667 | return bnx2x_status; | 2667 | return bnx2x_status; |
| 2668 | 2668 | ||
| 2669 | DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n"); | 2669 | DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n"); |
| 2670 | if (CHIP_IS_E3(bp)) | 2670 | |
| 2671 | bnx2x_update_pfc_xmac(params, vars, 0); | 2671 | if (CHIP_IS_E3(bp)) { |
| 2672 | else { | 2672 | if (vars->mac_type == MAC_TYPE_XMAC) |
| 2673 | bnx2x_update_pfc_xmac(params, vars, 0); | ||
| 2674 | } else { | ||
| 2673 | val = REG_RD(bp, MISC_REG_RESET_REG_2); | 2675 | val = REG_RD(bp, MISC_REG_RESET_REG_2); |
| 2674 | if ((val & | 2676 | if ((val & |
| 2675 | (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port)) | 2677 | (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port)) |
| @@ -5432,7 +5434,7 @@ static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy, | |||
| 5432 | switch (speed_mask) { | 5434 | switch (speed_mask) { |
| 5433 | case GP_STATUS_10M: | 5435 | case GP_STATUS_10M: |
| 5434 | vars->line_speed = SPEED_10; | 5436 | vars->line_speed = SPEED_10; |
| 5435 | if (vars->duplex == DUPLEX_FULL) | 5437 | if (is_duplex == DUPLEX_FULL) |
| 5436 | vars->link_status |= LINK_10TFD; | 5438 | vars->link_status |= LINK_10TFD; |
| 5437 | else | 5439 | else |
| 5438 | vars->link_status |= LINK_10THD; | 5440 | vars->link_status |= LINK_10THD; |
| @@ -5440,7 +5442,7 @@ static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy, | |||
| 5440 | 5442 | ||
| 5441 | case GP_STATUS_100M: | 5443 | case GP_STATUS_100M: |
| 5442 | vars->line_speed = SPEED_100; | 5444 | vars->line_speed = SPEED_100; |
| 5443 | if (vars->duplex == DUPLEX_FULL) | 5445 | if (is_duplex == DUPLEX_FULL) |
| 5444 | vars->link_status |= LINK_100TXFD; | 5446 | vars->link_status |= LINK_100TXFD; |
| 5445 | else | 5447 | else |
| 5446 | vars->link_status |= LINK_100TXHD; | 5448 | vars->link_status |= LINK_100TXHD; |
| @@ -5449,7 +5451,7 @@ static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy, | |||
| 5449 | case GP_STATUS_1G: | 5451 | case GP_STATUS_1G: |
| 5450 | case GP_STATUS_1G_KX: | 5452 | case GP_STATUS_1G_KX: |
| 5451 | vars->line_speed = SPEED_1000; | 5453 | vars->line_speed = SPEED_1000; |
| 5452 | if (vars->duplex == DUPLEX_FULL) | 5454 | if (is_duplex == DUPLEX_FULL) |
| 5453 | vars->link_status |= LINK_1000TFD; | 5455 | vars->link_status |= LINK_1000TFD; |
| 5454 | else | 5456 | else |
| 5455 | vars->link_status |= LINK_1000THD; | 5457 | vars->link_status |= LINK_1000THD; |
| @@ -5457,7 +5459,7 @@ static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy, | |||
| 5457 | 5459 | ||
| 5458 | case GP_STATUS_2_5G: | 5460 | case GP_STATUS_2_5G: |
| 5459 | vars->line_speed = SPEED_2500; | 5461 | vars->line_speed = SPEED_2500; |
| 5460 | if (vars->duplex == DUPLEX_FULL) | 5462 | if (is_duplex == DUPLEX_FULL) |
| 5461 | vars->link_status |= LINK_2500TFD; | 5463 | vars->link_status |= LINK_2500TFD; |
| 5462 | else | 5464 | else |
| 5463 | vars->link_status |= LINK_2500THD; | 5465 | vars->link_status |= LINK_2500THD; |
| @@ -5531,6 +5533,7 @@ static int bnx2x_link_settings_status(struct bnx2x_phy *phy, | |||
| 5531 | 5533 | ||
| 5532 | if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) { | 5534 | if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) { |
| 5533 | if (SINGLE_MEDIA_DIRECT(params)) { | 5535 | if (SINGLE_MEDIA_DIRECT(params)) { |
| 5536 | vars->duplex = duplex; | ||
| 5534 | bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status); | 5537 | bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status); |
| 5535 | if (phy->req_line_speed == SPEED_AUTO_NEG) | 5538 | if (phy->req_line_speed == SPEED_AUTO_NEG) |
| 5536 | bnx2x_xgxs_an_resolve(phy, params, vars, | 5539 | bnx2x_xgxs_an_resolve(phy, params, vars, |
| @@ -5625,6 +5628,7 @@ static int bnx2x_warpcore_read_status(struct bnx2x_phy *phy, | |||
| 5625 | LINK_STATUS_PARALLEL_DETECTION_USED; | 5628 | LINK_STATUS_PARALLEL_DETECTION_USED; |
| 5626 | } | 5629 | } |
| 5627 | bnx2x_ext_phy_resolve_fc(phy, params, vars); | 5630 | bnx2x_ext_phy_resolve_fc(phy, params, vars); |
| 5631 | vars->duplex = duplex; | ||
| 5628 | } | 5632 | } |
| 5629 | } | 5633 | } |
| 5630 | 5634 | ||
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 88b4a5439263..e11485ca037d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | |||
| @@ -7555,8 +7555,14 @@ int bnx2x_set_mac_one(struct bnx2x *bp, u8 *mac, | |||
| 7555 | } | 7555 | } |
| 7556 | 7556 | ||
| 7557 | rc = bnx2x_config_vlan_mac(bp, &ramrod_param); | 7557 | rc = bnx2x_config_vlan_mac(bp, &ramrod_param); |
| 7558 | if (rc < 0) | 7558 | |
| 7559 | if (rc == -EEXIST) { | ||
| 7560 | DP(BNX2X_MSG_SP, "Failed to schedule ADD operations: %d\n", rc); | ||
| 7561 | /* do not treat adding same MAC as error */ | ||
| 7562 | rc = 0; | ||
| 7563 | } else if (rc < 0) | ||
| 7559 | BNX2X_ERR("%s MAC failed\n", (set ? "Set" : "Del")); | 7564 | BNX2X_ERR("%s MAC failed\n", (set ? "Set" : "Del")); |
| 7565 | |||
| 7560 | return rc; | 7566 | return rc; |
| 7561 | } | 7567 | } |
| 7562 | 7568 | ||
| @@ -9815,12 +9821,13 @@ static void __devinit bnx2x_get_igu_cam_info(struct bnx2x *bp) | |||
| 9815 | } | 9821 | } |
| 9816 | 9822 | ||
| 9817 | #ifdef CONFIG_PCI_MSI | 9823 | #ifdef CONFIG_PCI_MSI |
| 9818 | /* | 9824 | /* Due to new PF resource allocation by MFW T7.4 and above, it's |
| 9819 | * It's expected that number of CAM entries for this functions is equal | 9825 | * optional that number of CAM entries will not be equal to the value |
| 9820 | * to the number evaluated based on the MSI-X table size. We want a | 9826 | * advertised in PCI. |
| 9821 | * harsh warning if these values are different! | 9827 | * Driver should use the minimal value of both as the actual status |
| 9828 | * block count | ||
| 9822 | */ | 9829 | */ |
| 9823 | WARN_ON(bp->igu_sb_cnt != igu_sb_cnt); | 9830 | bp->igu_sb_cnt = min_t(int, bp->igu_sb_cnt, igu_sb_cnt); |
| 9824 | #endif | 9831 | #endif |
| 9825 | 9832 | ||
| 9826 | if (igu_sb_cnt == 0) | 9833 | if (igu_sb_cnt == 0) |
| @@ -10284,13 +10291,11 @@ static void __devinit bnx2x_get_fcoe_info(struct bnx2x *bp) | |||
| 10284 | dev_info.port_hw_config[port]. | 10291 | dev_info.port_hw_config[port]. |
| 10285 | fcoe_wwn_node_name_lower); | 10292 | fcoe_wwn_node_name_lower); |
| 10286 | } else if (!IS_MF_SD(bp)) { | 10293 | } else if (!IS_MF_SD(bp)) { |
| 10287 | u32 cfg = MF_CFG_RD(bp, func_ext_config[func].func_cfg); | ||
| 10288 | |||
| 10289 | /* | 10294 | /* |
| 10290 | * Read the WWN info only if the FCoE feature is enabled for | 10295 | * Read the WWN info only if the FCoE feature is enabled for |
| 10291 | * this function. | 10296 | * this function. |
| 10292 | */ | 10297 | */ |
| 10293 | if (cfg & MACP_FUNC_CFG_FLAGS_FCOE_OFFLOAD) | 10298 | if (BNX2X_MF_EXT_PROTOCOL_FCOE(bp) && !CHIP_IS_E1x(bp)) |
| 10294 | bnx2x_get_ext_wwn_info(bp, func); | 10299 | bnx2x_get_ext_wwn_info(bp, func); |
| 10295 | 10300 | ||
| 10296 | } else if (IS_MF_FCOE_SD(bp)) | 10301 | } else if (IS_MF_FCOE_SD(bp)) |
| @@ -11063,7 +11068,14 @@ static int bnx2x_set_uc_list(struct bnx2x *bp) | |||
| 11063 | netdev_for_each_uc_addr(ha, dev) { | 11068 | netdev_for_each_uc_addr(ha, dev) { |
| 11064 | rc = bnx2x_set_mac_one(bp, bnx2x_uc_addr(ha), mac_obj, true, | 11069 | rc = bnx2x_set_mac_one(bp, bnx2x_uc_addr(ha), mac_obj, true, |
| 11065 | BNX2X_UC_LIST_MAC, &ramrod_flags); | 11070 | BNX2X_UC_LIST_MAC, &ramrod_flags); |
| 11066 | if (rc < 0) { | 11071 | if (rc == -EEXIST) { |
| 11072 | DP(BNX2X_MSG_SP, | ||
| 11073 | "Failed to schedule ADD operations: %d\n", rc); | ||
| 11074 | /* do not treat adding same MAC as error */ | ||
| 11075 | rc = 0; | ||
| 11076 | |||
| 11077 | } else if (rc < 0) { | ||
| 11078 | |||
| 11067 | BNX2X_ERR("Failed to schedule ADD operations: %d\n", | 11079 | BNX2X_ERR("Failed to schedule ADD operations: %d\n", |
| 11068 | rc); | 11080 | rc); |
| 11069 | return rc; | 11081 | return rc; |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h index f83e033da6da..acf2fe4ca608 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h | |||
| @@ -1321,7 +1321,7 @@ void bnx2x_init_mcast_obj(struct bnx2x *bp, | |||
| 1321 | * the current command will be enqueued to the tail of the | 1321 | * the current command will be enqueued to the tail of the |
| 1322 | * pending commands list. | 1322 | * pending commands list. |
| 1323 | * | 1323 | * |
| 1324 | * Return: 0 is operation was sucessfull and there are no pending completions, | 1324 | * Return: 0 is operation was successfull and there are no pending completions, |
| 1325 | * negative if there were errors, positive if there are pending | 1325 | * negative if there were errors, positive if there are pending |
| 1326 | * completions. | 1326 | * completions. |
| 1327 | */ | 1327 | */ |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c index 332db64dd5be..a1d0446b39b3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c | |||
| @@ -101,6 +101,11 @@ static void bnx2x_hw_stats_post(struct bnx2x *bp) | |||
| 101 | if (CHIP_REV_IS_SLOW(bp)) | 101 | if (CHIP_REV_IS_SLOW(bp)) |
| 102 | return; | 102 | return; |
| 103 | 103 | ||
| 104 | /* Update MCP's statistics if possible */ | ||
| 105 | if (bp->func_stx) | ||
| 106 | memcpy(bnx2x_sp(bp, func_stats), &bp->func_stats, | ||
| 107 | sizeof(bp->func_stats)); | ||
| 108 | |||
| 104 | /* loader */ | 109 | /* loader */ |
| 105 | if (bp->executer_idx) { | 110 | if (bp->executer_idx) { |
| 106 | int loader_idx = PMF_DMAE_C(bp); | 111 | int loader_idx = PMF_DMAE_C(bp); |
| @@ -128,8 +133,6 @@ static void bnx2x_hw_stats_post(struct bnx2x *bp) | |||
| 128 | 133 | ||
| 129 | } else if (bp->func_stx) { | 134 | } else if (bp->func_stx) { |
| 130 | *stats_comp = 0; | 135 | *stats_comp = 0; |
| 131 | memcpy(bnx2x_sp(bp, func_stats), &bp->func_stats, | ||
| 132 | sizeof(bp->func_stats)); | ||
| 133 | bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp)); | 136 | bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp)); |
| 134 | } | 137 | } |
| 135 | } | 138 | } |
| @@ -1151,9 +1154,11 @@ static void bnx2x_stats_update(struct bnx2x *bp) | |||
| 1151 | if (bp->port.pmf) | 1154 | if (bp->port.pmf) |
| 1152 | bnx2x_hw_stats_update(bp); | 1155 | bnx2x_hw_stats_update(bp); |
| 1153 | 1156 | ||
| 1154 | if (bnx2x_storm_stats_update(bp) && (bp->stats_pending++ == 3)) { | 1157 | if (bnx2x_storm_stats_update(bp)) { |
| 1155 | BNX2X_ERR("storm stats were not updated for 3 times\n"); | 1158 | if (bp->stats_pending++ == 3) { |
| 1156 | bnx2x_panic(); | 1159 | BNX2X_ERR("storm stats were not updated for 3 times\n"); |
| 1160 | bnx2x_panic(); | ||
| 1161 | } | ||
| 1157 | return; | 1162 | return; |
| 1158 | } | 1163 | } |
| 1159 | 1164 | ||
diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c index 77884191a8c6..4e980a7886fb 100644 --- a/drivers/net/ethernet/cadence/at91_ether.c +++ b/drivers/net/ethernet/cadence/at91_ether.c | |||
| @@ -1086,7 +1086,7 @@ static int __init at91ether_probe(struct platform_device *pdev) | |||
| 1086 | /* Clock */ | 1086 | /* Clock */ |
| 1087 | lp->ether_clk = clk_get(&pdev->dev, "ether_clk"); | 1087 | lp->ether_clk = clk_get(&pdev->dev, "ether_clk"); |
| 1088 | if (IS_ERR(lp->ether_clk)) { | 1088 | if (IS_ERR(lp->ether_clk)) { |
| 1089 | res = -ENODEV; | 1089 | res = PTR_ERR(lp->ether_clk); |
| 1090 | goto err_ioumap; | 1090 | goto err_ioumap; |
| 1091 | } | 1091 | } |
| 1092 | clk_enable(lp->ether_clk); | 1092 | clk_enable(lp->ether_clk); |
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index 8971921cc1c8..ab6762caa957 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c | |||
| @@ -1773,6 +1773,7 @@ static int gfar_get_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd, | |||
| 1773 | } | 1773 | } |
| 1774 | 1774 | ||
| 1775 | int gfar_phc_index = -1; | 1775 | int gfar_phc_index = -1; |
| 1776 | EXPORT_SYMBOL(gfar_phc_index); | ||
| 1776 | 1777 | ||
| 1777 | static int gfar_get_ts_info(struct net_device *dev, | 1778 | static int gfar_get_ts_info(struct net_device *dev, |
| 1778 | struct ethtool_ts_info *info) | 1779 | struct ethtool_ts_info *info) |
diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c index c08e5d40fecb..0daa66b8eca0 100644 --- a/drivers/net/ethernet/freescale/gianfar_ptp.c +++ b/drivers/net/ethernet/freescale/gianfar_ptp.c | |||
| @@ -515,7 +515,7 @@ static int gianfar_ptp_probe(struct platform_device *dev) | |||
| 515 | err = PTR_ERR(etsects->clock); | 515 | err = PTR_ERR(etsects->clock); |
| 516 | goto no_clock; | 516 | goto no_clock; |
| 517 | } | 517 | } |
| 518 | gfar_phc_clock = ptp_clock_index(etsects->clock); | 518 | gfar_phc_index = ptp_clock_index(etsects->clock); |
| 519 | 519 | ||
| 520 | dev_set_drvdata(&dev->dev, etsects); | 520 | dev_set_drvdata(&dev->dev, etsects); |
| 521 | 521 | ||
| @@ -539,7 +539,7 @@ static int gianfar_ptp_remove(struct platform_device *dev) | |||
| 539 | gfar_write(&etsects->regs->tmr_temask, 0); | 539 | gfar_write(&etsects->regs->tmr_temask, 0); |
| 540 | gfar_write(&etsects->regs->tmr_ctrl, 0); | 540 | gfar_write(&etsects->regs->tmr_ctrl, 0); |
| 541 | 541 | ||
| 542 | gfar_phc_clock = -1; | 542 | gfar_phc_index = -1; |
| 543 | ptp_clock_unregister(etsects->clock); | 543 | ptp_clock_unregister(etsects->clock); |
| 544 | iounmap(etsects->regs); | 544 | iounmap(etsects->regs); |
| 545 | release_resource(etsects->rsrc); | 545 | release_resource(etsects->rsrc); |
diff --git a/drivers/net/ethernet/i825xx/znet.c b/drivers/net/ethernet/i825xx/znet.c index bd1f1ef91e19..ba4e0cea3506 100644 --- a/drivers/net/ethernet/i825xx/znet.c +++ b/drivers/net/ethernet/i825xx/znet.c | |||
| @@ -139,8 +139,11 @@ struct znet_private { | |||
| 139 | /* Only one can be built-in;-> */ | 139 | /* Only one can be built-in;-> */ |
| 140 | static struct net_device *znet_dev; | 140 | static struct net_device *znet_dev; |
| 141 | 141 | ||
| 142 | #define NETIDBLK_MAGIC "NETIDBLK" | ||
| 143 | #define NETIDBLK_MAGIC_SIZE 8 | ||
| 144 | |||
| 142 | struct netidblk { | 145 | struct netidblk { |
| 143 | char magic[8]; /* The magic number (string) "NETIDBLK" */ | 146 | char magic[NETIDBLK_MAGIC_SIZE]; /* The magic number (string) "NETIDBLK" */ |
| 144 | unsigned char netid[8]; /* The physical station address */ | 147 | unsigned char netid[8]; /* The physical station address */ |
| 145 | char nettype, globalopt; | 148 | char nettype, globalopt; |
| 146 | char vendor[8]; /* The machine vendor and product name. */ | 149 | char vendor[8]; /* The machine vendor and product name. */ |
| @@ -373,14 +376,16 @@ static int __init znet_probe (void) | |||
| 373 | struct znet_private *znet; | 376 | struct znet_private *znet; |
| 374 | struct net_device *dev; | 377 | struct net_device *dev; |
| 375 | char *p; | 378 | char *p; |
| 379 | char *plast = phys_to_virt(0x100000 - NETIDBLK_MAGIC_SIZE); | ||
| 376 | int err = -ENOMEM; | 380 | int err = -ENOMEM; |
| 377 | 381 | ||
| 378 | /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */ | 382 | /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */ |
| 379 | for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++) | 383 | for(p = (char *)phys_to_virt(0xf0000); p <= plast; p++) |
| 380 | if (*p == 'N' && strncmp(p, "NETIDBLK", 8) == 0) | 384 | if (*p == 'N' && |
| 385 | strncmp(p, NETIDBLK_MAGIC, NETIDBLK_MAGIC_SIZE) == 0) | ||
| 381 | break; | 386 | break; |
| 382 | 387 | ||
| 383 | if (p >= (char *)phys_to_virt(0x100000)) { | 388 | if (p > plast) { |
| 384 | if (znet_debug > 1) | 389 | if (znet_debug > 1) |
| 385 | printk(KERN_INFO "No Z-Note ethernet adaptor found.\n"); | 390 | printk(KERN_INFO "No Z-Note ethernet adaptor found.\n"); |
| 386 | return -ENODEV; | 391 | return -ENODEV; |
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 9010cea68bc3..b68d28a130e6 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c | |||
| @@ -472,14 +472,9 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) | |||
| 472 | } | 472 | } |
| 473 | 473 | ||
| 474 | if (adapter->rx_queue.queue_addr != NULL) { | 474 | if (adapter->rx_queue.queue_addr != NULL) { |
| 475 | if (!dma_mapping_error(dev, adapter->rx_queue.queue_dma)) { | 475 | dma_free_coherent(dev, adapter->rx_queue.queue_len, |
| 476 | dma_unmap_single(dev, | 476 | adapter->rx_queue.queue_addr, |
| 477 | adapter->rx_queue.queue_dma, | 477 | adapter->rx_queue.queue_dma); |
| 478 | adapter->rx_queue.queue_len, | ||
| 479 | DMA_BIDIRECTIONAL); | ||
| 480 | adapter->rx_queue.queue_dma = DMA_ERROR_CODE; | ||
| 481 | } | ||
| 482 | kfree(adapter->rx_queue.queue_addr); | ||
| 483 | adapter->rx_queue.queue_addr = NULL; | 478 | adapter->rx_queue.queue_addr = NULL; |
| 484 | } | 479 | } |
| 485 | 480 | ||
| @@ -556,10 +551,13 @@ static int ibmveth_open(struct net_device *netdev) | |||
| 556 | goto err_out; | 551 | goto err_out; |
| 557 | } | 552 | } |
| 558 | 553 | ||
| 554 | dev = &adapter->vdev->dev; | ||
| 555 | |||
| 559 | adapter->rx_queue.queue_len = sizeof(struct ibmveth_rx_q_entry) * | 556 | adapter->rx_queue.queue_len = sizeof(struct ibmveth_rx_q_entry) * |
| 560 | rxq_entries; | 557 | rxq_entries; |
| 561 | adapter->rx_queue.queue_addr = kmalloc(adapter->rx_queue.queue_len, | 558 | adapter->rx_queue.queue_addr = |
| 562 | GFP_KERNEL); | 559 | dma_alloc_coherent(dev, adapter->rx_queue.queue_len, |
| 560 | &adapter->rx_queue.queue_dma, GFP_KERNEL); | ||
| 563 | 561 | ||
| 564 | if (!adapter->rx_queue.queue_addr) { | 562 | if (!adapter->rx_queue.queue_addr) { |
| 565 | netdev_err(netdev, "unable to allocate rx queue pages\n"); | 563 | netdev_err(netdev, "unable to allocate rx queue pages\n"); |
| @@ -567,19 +565,13 @@ static int ibmveth_open(struct net_device *netdev) | |||
| 567 | goto err_out; | 565 | goto err_out; |
| 568 | } | 566 | } |
| 569 | 567 | ||
| 570 | dev = &adapter->vdev->dev; | ||
| 571 | |||
| 572 | adapter->buffer_list_dma = dma_map_single(dev, | 568 | adapter->buffer_list_dma = dma_map_single(dev, |
| 573 | adapter->buffer_list_addr, 4096, DMA_BIDIRECTIONAL); | 569 | adapter->buffer_list_addr, 4096, DMA_BIDIRECTIONAL); |
| 574 | adapter->filter_list_dma = dma_map_single(dev, | 570 | adapter->filter_list_dma = dma_map_single(dev, |
| 575 | adapter->filter_list_addr, 4096, DMA_BIDIRECTIONAL); | 571 | adapter->filter_list_addr, 4096, DMA_BIDIRECTIONAL); |
| 576 | adapter->rx_queue.queue_dma = dma_map_single(dev, | ||
| 577 | adapter->rx_queue.queue_addr, | ||
| 578 | adapter->rx_queue.queue_len, DMA_BIDIRECTIONAL); | ||
| 579 | 572 | ||
| 580 | if ((dma_mapping_error(dev, adapter->buffer_list_dma)) || | 573 | if ((dma_mapping_error(dev, adapter->buffer_list_dma)) || |
| 581 | (dma_mapping_error(dev, adapter->filter_list_dma)) || | 574 | (dma_mapping_error(dev, adapter->filter_list_dma))) { |
| 582 | (dma_mapping_error(dev, adapter->rx_queue.queue_dma))) { | ||
| 583 | netdev_err(netdev, "unable to map filter or buffer list " | 575 | netdev_err(netdev, "unable to map filter or buffer list " |
| 584 | "pages\n"); | 576 | "pages\n"); |
| 585 | rc = -ENOMEM; | 577 | rc = -ENOMEM; |
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 524cfb4cac61..f3f9aeb7d1e1 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c | |||
| @@ -3149,6 +3149,17 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, | |||
| 3149 | return NETDEV_TX_OK; | 3149 | return NETDEV_TX_OK; |
| 3150 | } | 3150 | } |
| 3151 | 3151 | ||
| 3152 | /* On PCI/PCI-X HW, if packet size is less than ETH_ZLEN, | ||
| 3153 | * packets may get corrupted during padding by HW. | ||
| 3154 | * To WA this issue, pad all small packets manually. | ||
| 3155 | */ | ||
| 3156 | if (skb->len < ETH_ZLEN) { | ||
| 3157 | if (skb_pad(skb, ETH_ZLEN - skb->len)) | ||
| 3158 | return NETDEV_TX_OK; | ||
| 3159 | skb->len = ETH_ZLEN; | ||
| 3160 | skb_set_tail_pointer(skb, ETH_ZLEN); | ||
| 3161 | } | ||
| 3162 | |||
| 3152 | mss = skb_shinfo(skb)->gso_size; | 3163 | mss = skb_shinfo(skb)->gso_size; |
| 3153 | /* The controller does a simple calculation to | 3164 | /* The controller does a simple calculation to |
| 3154 | * make sure there is enough room in the FIFO before | 3165 | * make sure there is enough room in the FIFO before |
diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c index daf417923661..31d02649be41 100644 --- a/drivers/net/ethernet/mellanox/mlx4/icm.c +++ b/drivers/net/ethernet/mellanox/mlx4/icm.c | |||
| @@ -227,9 +227,10 @@ int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev) | |||
| 227 | MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); | 227 | MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); |
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) | 230 | int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj) |
| 231 | { | 231 | { |
| 232 | int i = (obj & (table->num_obj - 1)) / (MLX4_TABLE_CHUNK_SIZE / table->obj_size); | 232 | u32 i = (obj & (table->num_obj - 1)) / |
| 233 | (MLX4_TABLE_CHUNK_SIZE / table->obj_size); | ||
| 233 | int ret = 0; | 234 | int ret = 0; |
| 234 | 235 | ||
| 235 | mutex_lock(&table->mutex); | 236 | mutex_lock(&table->mutex); |
| @@ -262,16 +263,18 @@ out: | |||
| 262 | return ret; | 263 | return ret; |
| 263 | } | 264 | } |
| 264 | 265 | ||
| 265 | void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) | 266 | void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj) |
| 266 | { | 267 | { |
| 267 | int i; | 268 | u32 i; |
| 269 | u64 offset; | ||
| 268 | 270 | ||
| 269 | i = (obj & (table->num_obj - 1)) / (MLX4_TABLE_CHUNK_SIZE / table->obj_size); | 271 | i = (obj & (table->num_obj - 1)) / (MLX4_TABLE_CHUNK_SIZE / table->obj_size); |
| 270 | 272 | ||
| 271 | mutex_lock(&table->mutex); | 273 | mutex_lock(&table->mutex); |
| 272 | 274 | ||
| 273 | if (--table->icm[i]->refcount == 0) { | 275 | if (--table->icm[i]->refcount == 0) { |
| 274 | mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE, | 276 | offset = (u64) i * MLX4_TABLE_CHUNK_SIZE; |
| 277 | mlx4_UNMAP_ICM(dev, table->virt + offset, | ||
| 275 | MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); | 278 | MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); |
| 276 | mlx4_free_icm(dev, table->icm[i], table->coherent); | 279 | mlx4_free_icm(dev, table->icm[i], table->coherent); |
| 277 | table->icm[i] = NULL; | 280 | table->icm[i] = NULL; |
| @@ -280,9 +283,11 @@ void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) | |||
| 280 | mutex_unlock(&table->mutex); | 283 | mutex_unlock(&table->mutex); |
| 281 | } | 284 | } |
| 282 | 285 | ||
| 283 | void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle) | 286 | void *mlx4_table_find(struct mlx4_icm_table *table, u32 obj, |
| 287 | dma_addr_t *dma_handle) | ||
| 284 | { | 288 | { |
| 285 | int idx, offset, dma_offset, i; | 289 | int offset, dma_offset, i; |
| 290 | u64 idx; | ||
| 286 | struct mlx4_icm_chunk *chunk; | 291 | struct mlx4_icm_chunk *chunk; |
| 287 | struct mlx4_icm *icm; | 292 | struct mlx4_icm *icm; |
| 288 | struct page *page = NULL; | 293 | struct page *page = NULL; |
| @@ -292,7 +297,7 @@ void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_han | |||
| 292 | 297 | ||
| 293 | mutex_lock(&table->mutex); | 298 | mutex_lock(&table->mutex); |
| 294 | 299 | ||
| 295 | idx = (obj & (table->num_obj - 1)) * table->obj_size; | 300 | idx = (u64) (obj & (table->num_obj - 1)) * table->obj_size; |
| 296 | icm = table->icm[idx / MLX4_TABLE_CHUNK_SIZE]; | 301 | icm = table->icm[idx / MLX4_TABLE_CHUNK_SIZE]; |
| 297 | dma_offset = offset = idx % MLX4_TABLE_CHUNK_SIZE; | 302 | dma_offset = offset = idx % MLX4_TABLE_CHUNK_SIZE; |
| 298 | 303 | ||
| @@ -326,10 +331,11 @@ out: | |||
| 326 | } | 331 | } |
| 327 | 332 | ||
| 328 | int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, | 333 | int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, |
| 329 | int start, int end) | 334 | u32 start, u32 end) |
| 330 | { | 335 | { |
| 331 | int inc = MLX4_TABLE_CHUNK_SIZE / table->obj_size; | 336 | int inc = MLX4_TABLE_CHUNK_SIZE / table->obj_size; |
| 332 | int i, err; | 337 | int err; |
| 338 | u32 i; | ||
| 333 | 339 | ||
| 334 | for (i = start; i <= end; i += inc) { | 340 | for (i = start; i <= end; i += inc) { |
| 335 | err = mlx4_table_get(dev, table, i); | 341 | err = mlx4_table_get(dev, table, i); |
| @@ -349,9 +355,9 @@ fail: | |||
| 349 | } | 355 | } |
| 350 | 356 | ||
| 351 | void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, | 357 | void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, |
| 352 | int start, int end) | 358 | u32 start, u32 end) |
| 353 | { | 359 | { |
| 354 | int i; | 360 | u32 i; |
| 355 | 361 | ||
| 356 | for (i = start; i <= end; i += MLX4_TABLE_CHUNK_SIZE / table->obj_size) | 362 | for (i = start; i <= end; i += MLX4_TABLE_CHUNK_SIZE / table->obj_size) |
| 357 | mlx4_table_put(dev, table, i); | 363 | mlx4_table_put(dev, table, i); |
diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.h b/drivers/net/ethernet/mellanox/mlx4/icm.h index a67744f53506..dee67fa39107 100644 --- a/drivers/net/ethernet/mellanox/mlx4/icm.h +++ b/drivers/net/ethernet/mellanox/mlx4/icm.h | |||
| @@ -71,17 +71,17 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, | |||
| 71 | gfp_t gfp_mask, int coherent); | 71 | gfp_t gfp_mask, int coherent); |
| 72 | void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent); | 72 | void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent); |
| 73 | 73 | ||
| 74 | int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); | 74 | int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj); |
| 75 | void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); | 75 | void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, u32 obj); |
| 76 | int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, | 76 | int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, |
| 77 | int start, int end); | 77 | u32 start, u32 end); |
| 78 | void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, | 78 | void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, |
| 79 | int start, int end); | 79 | u32 start, u32 end); |
| 80 | int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, | 80 | int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, |
| 81 | u64 virt, int obj_size, u32 nobj, int reserved, | 81 | u64 virt, int obj_size, u32 nobj, int reserved, |
| 82 | int use_lowmem, int use_coherent); | 82 | int use_lowmem, int use_coherent); |
| 83 | void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table); | 83 | void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table); |
| 84 | void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle); | 84 | void *mlx4_table_find(struct mlx4_icm_table *table, u32 obj, dma_addr_t *dma_handle); |
| 85 | 85 | ||
| 86 | static inline void mlx4_icm_first(struct mlx4_icm *icm, | 86 | static inline void mlx4_icm_first(struct mlx4_icm *icm, |
| 87 | struct mlx4_icm_iter *iter) | 87 | struct mlx4_icm_iter *iter) |
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 3d65097e0a89..dd6ea942625c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c | |||
| @@ -1234,13 +1234,13 @@ static int mlx4_init_hca(struct mlx4_dev *dev) | |||
| 1234 | mlx4_info(dev, "non-primary physical function, skipping.\n"); | 1234 | mlx4_info(dev, "non-primary physical function, skipping.\n"); |
| 1235 | else | 1235 | else |
| 1236 | mlx4_err(dev, "QUERY_FW command failed, aborting.\n"); | 1236 | mlx4_err(dev, "QUERY_FW command failed, aborting.\n"); |
| 1237 | goto unmap_bf; | 1237 | return err; |
| 1238 | } | 1238 | } |
| 1239 | 1239 | ||
| 1240 | err = mlx4_load_fw(dev); | 1240 | err = mlx4_load_fw(dev); |
| 1241 | if (err) { | 1241 | if (err) { |
| 1242 | mlx4_err(dev, "Failed to start FW, aborting.\n"); | 1242 | mlx4_err(dev, "Failed to start FW, aborting.\n"); |
| 1243 | goto unmap_bf; | 1243 | return err; |
| 1244 | } | 1244 | } |
| 1245 | 1245 | ||
| 1246 | mlx4_cfg.log_pg_sz_m = 1; | 1246 | mlx4_cfg.log_pg_sz_m = 1; |
| @@ -1304,7 +1304,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev) | |||
| 1304 | err = mlx4_init_slave(dev); | 1304 | err = mlx4_init_slave(dev); |
| 1305 | if (err) { | 1305 | if (err) { |
| 1306 | mlx4_err(dev, "Failed to initialize slave\n"); | 1306 | mlx4_err(dev, "Failed to initialize slave\n"); |
| 1307 | goto unmap_bf; | 1307 | return err; |
| 1308 | } | 1308 | } |
| 1309 | 1309 | ||
| 1310 | err = mlx4_slave_cap(dev); | 1310 | err = mlx4_slave_cap(dev); |
| @@ -1324,7 +1324,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev) | |||
| 1324 | err = mlx4_QUERY_ADAPTER(dev, &adapter); | 1324 | err = mlx4_QUERY_ADAPTER(dev, &adapter); |
| 1325 | if (err) { | 1325 | if (err) { |
| 1326 | mlx4_err(dev, "QUERY_ADAPTER command failed, aborting.\n"); | 1326 | mlx4_err(dev, "QUERY_ADAPTER command failed, aborting.\n"); |
| 1327 | goto err_close; | 1327 | goto unmap_bf; |
| 1328 | } | 1328 | } |
| 1329 | 1329 | ||
| 1330 | priv->eq_table.inta_pin = adapter.inta_pin; | 1330 | priv->eq_table.inta_pin = adapter.inta_pin; |
| @@ -1332,6 +1332,9 @@ static int mlx4_init_hca(struct mlx4_dev *dev) | |||
| 1332 | 1332 | ||
| 1333 | return 0; | 1333 | return 0; |
| 1334 | 1334 | ||
| 1335 | unmap_bf: | ||
| 1336 | unmap_bf_area(dev); | ||
| 1337 | |||
| 1335 | err_close: | 1338 | err_close: |
| 1336 | mlx4_close_hca(dev); | 1339 | mlx4_close_hca(dev); |
| 1337 | 1340 | ||
| @@ -1344,8 +1347,6 @@ err_stop_fw: | |||
| 1344 | mlx4_UNMAP_FA(dev); | 1347 | mlx4_UNMAP_FA(dev); |
| 1345 | mlx4_free_icm(dev, priv->fw.fw_icm, 0); | 1348 | mlx4_free_icm(dev, priv->fw.fw_icm, 0); |
| 1346 | } | 1349 | } |
| 1347 | unmap_bf: | ||
| 1348 | unmap_bf_area(dev); | ||
| 1349 | return err; | 1350 | return err; |
| 1350 | } | 1351 | } |
| 1351 | 1352 | ||
| @@ -1996,7 +1997,8 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1996 | } | 1997 | } |
| 1997 | 1998 | ||
| 1998 | slave_start: | 1999 | slave_start: |
| 1999 | if (mlx4_cmd_init(dev)) { | 2000 | err = mlx4_cmd_init(dev); |
| 2001 | if (err) { | ||
| 2000 | mlx4_err(dev, "Failed to init command interface, aborting.\n"); | 2002 | mlx4_err(dev, "Failed to init command interface, aborting.\n"); |
| 2001 | goto err_sriov; | 2003 | goto err_sriov; |
| 2002 | } | 2004 | } |
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index a018ea2a43de..e151c21baf2b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c | |||
| @@ -137,11 +137,11 @@ static int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, | |||
| 137 | return err; | 137 | return err; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | static struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 pf_num, | 140 | static struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 port, |
| 141 | enum mlx4_steer_type steer, | 141 | enum mlx4_steer_type steer, |
| 142 | u32 qpn) | 142 | u32 qpn) |
| 143 | { | 143 | { |
| 144 | struct mlx4_steer *s_steer = &mlx4_priv(dev)->steer[pf_num]; | 144 | struct mlx4_steer *s_steer = &mlx4_priv(dev)->steer[port - 1]; |
| 145 | struct mlx4_promisc_qp *pqp; | 145 | struct mlx4_promisc_qp *pqp; |
| 146 | 146 | ||
| 147 | list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { | 147 | list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { |
| @@ -182,7 +182,7 @@ static int new_steering_entry(struct mlx4_dev *dev, u8 port, | |||
| 182 | /* If the given qpn is also a promisc qp, | 182 | /* If the given qpn is also a promisc qp, |
| 183 | * it should be inserted to duplicates list | 183 | * it should be inserted to duplicates list |
| 184 | */ | 184 | */ |
| 185 | pqp = get_promisc_qp(dev, 0, steer, qpn); | 185 | pqp = get_promisc_qp(dev, port, steer, qpn); |
| 186 | if (pqp) { | 186 | if (pqp) { |
| 187 | dqp = kmalloc(sizeof *dqp, GFP_KERNEL); | 187 | dqp = kmalloc(sizeof *dqp, GFP_KERNEL); |
| 188 | if (!dqp) { | 188 | if (!dqp) { |
| @@ -256,7 +256,7 @@ static int existing_steering_entry(struct mlx4_dev *dev, u8 port, | |||
| 256 | 256 | ||
| 257 | s_steer = &mlx4_priv(dev)->steer[port - 1]; | 257 | s_steer = &mlx4_priv(dev)->steer[port - 1]; |
| 258 | 258 | ||
| 259 | pqp = get_promisc_qp(dev, 0, steer, qpn); | 259 | pqp = get_promisc_qp(dev, port, steer, qpn); |
| 260 | if (!pqp) | 260 | if (!pqp) |
| 261 | return 0; /* nothing to do */ | 261 | return 0; /* nothing to do */ |
| 262 | 262 | ||
| @@ -302,7 +302,7 @@ static bool check_duplicate_entry(struct mlx4_dev *dev, u8 port, | |||
| 302 | s_steer = &mlx4_priv(dev)->steer[port - 1]; | 302 | s_steer = &mlx4_priv(dev)->steer[port - 1]; |
| 303 | 303 | ||
| 304 | /* if qp is not promisc, it cannot be duplicated */ | 304 | /* if qp is not promisc, it cannot be duplicated */ |
| 305 | if (!get_promisc_qp(dev, 0, steer, qpn)) | 305 | if (!get_promisc_qp(dev, port, steer, qpn)) |
| 306 | return false; | 306 | return false; |
| 307 | 307 | ||
| 308 | /* The qp is promisc qp so it is a duplicate on this index | 308 | /* The qp is promisc qp so it is a duplicate on this index |
| @@ -352,7 +352,7 @@ static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port, | |||
| 352 | members_count = be32_to_cpu(mgm->members_count) & 0xffffff; | 352 | members_count = be32_to_cpu(mgm->members_count) & 0xffffff; |
| 353 | for (i = 0; i < members_count; i++) { | 353 | for (i = 0; i < members_count; i++) { |
| 354 | qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK; | 354 | qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK; |
| 355 | if (!get_promisc_qp(dev, 0, steer, qpn) && qpn != tqpn) { | 355 | if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) { |
| 356 | /* the qp is not promisc, the entry can't be removed */ | 356 | /* the qp is not promisc, the entry can't be removed */ |
| 357 | goto out; | 357 | goto out; |
| 358 | } | 358 | } |
| @@ -398,7 +398,7 @@ static int add_promisc_qp(struct mlx4_dev *dev, u8 port, | |||
| 398 | 398 | ||
| 399 | mutex_lock(&priv->mcg_table.mutex); | 399 | mutex_lock(&priv->mcg_table.mutex); |
| 400 | 400 | ||
| 401 | if (get_promisc_qp(dev, 0, steer, qpn)) { | 401 | if (get_promisc_qp(dev, port, steer, qpn)) { |
| 402 | err = 0; /* Noting to do, already exists */ | 402 | err = 0; /* Noting to do, already exists */ |
| 403 | goto out_mutex; | 403 | goto out_mutex; |
| 404 | } | 404 | } |
| @@ -503,7 +503,7 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 port, | |||
| 503 | s_steer = &mlx4_priv(dev)->steer[port - 1]; | 503 | s_steer = &mlx4_priv(dev)->steer[port - 1]; |
| 504 | mutex_lock(&priv->mcg_table.mutex); | 504 | mutex_lock(&priv->mcg_table.mutex); |
| 505 | 505 | ||
| 506 | pqp = get_promisc_qp(dev, 0, steer, qpn); | 506 | pqp = get_promisc_qp(dev, port, steer, qpn); |
| 507 | if (unlikely(!pqp)) { | 507 | if (unlikely(!pqp)) { |
| 508 | mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn); | 508 | mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn); |
| 509 | /* nothing to do */ | 509 | /* nothing to do */ |
| @@ -650,13 +650,6 @@ static int find_entry(struct mlx4_dev *dev, u8 port, | |||
| 650 | return err; | 650 | return err; |
| 651 | } | 651 | } |
| 652 | 652 | ||
| 653 | struct mlx4_net_trans_rule_hw_ctrl { | ||
| 654 | __be32 ctrl; | ||
| 655 | __be32 vf_vep_port; | ||
| 656 | __be32 qpn; | ||
| 657 | __be32 reserved; | ||
| 658 | }; | ||
| 659 | |||
| 660 | static void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl, | 653 | static void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl, |
| 661 | struct mlx4_net_trans_rule_hw_ctrl *hw) | 654 | struct mlx4_net_trans_rule_hw_ctrl *hw) |
| 662 | { | 655 | { |
| @@ -680,87 +673,18 @@ static void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl, | |||
| 680 | hw->qpn = cpu_to_be32(ctrl->qpn); | 673 | hw->qpn = cpu_to_be32(ctrl->qpn); |
| 681 | } | 674 | } |
| 682 | 675 | ||
| 683 | struct mlx4_net_trans_rule_hw_ib { | 676 | const u16 __sw_id_hw[] = { |
| 684 | u8 size; | 677 | [MLX4_NET_TRANS_RULE_ID_ETH] = 0xE001, |
| 685 | u8 rsvd1; | 678 | [MLX4_NET_TRANS_RULE_ID_IB] = 0xE005, |
| 686 | __be16 id; | 679 | [MLX4_NET_TRANS_RULE_ID_IPV6] = 0xE003, |
| 687 | u32 rsvd2; | 680 | [MLX4_NET_TRANS_RULE_ID_IPV4] = 0xE002, |
| 688 | __be32 qpn; | 681 | [MLX4_NET_TRANS_RULE_ID_TCP] = 0xE004, |
| 689 | __be32 qpn_mask; | 682 | [MLX4_NET_TRANS_RULE_ID_UDP] = 0xE006 |
| 690 | u8 dst_gid[16]; | ||
| 691 | u8 dst_gid_msk[16]; | ||
| 692 | } __packed; | ||
| 693 | |||
| 694 | struct mlx4_net_trans_rule_hw_eth { | ||
| 695 | u8 size; | ||
| 696 | u8 rsvd; | ||
| 697 | __be16 id; | ||
| 698 | u8 rsvd1[6]; | ||
| 699 | u8 dst_mac[6]; | ||
| 700 | u16 rsvd2; | ||
| 701 | u8 dst_mac_msk[6]; | ||
| 702 | u16 rsvd3; | ||
| 703 | u8 src_mac[6]; | ||
| 704 | u16 rsvd4; | ||
| 705 | u8 src_mac_msk[6]; | ||
| 706 | u8 rsvd5; | ||
| 707 | u8 ether_type_enable; | ||
| 708 | __be16 ether_type; | ||
| 709 | __be16 vlan_id_msk; | ||
| 710 | __be16 vlan_id; | ||
| 711 | } __packed; | ||
| 712 | |||
| 713 | struct mlx4_net_trans_rule_hw_tcp_udp { | ||
| 714 | u8 size; | ||
| 715 | u8 rsvd; | ||
| 716 | __be16 id; | ||
| 717 | __be16 rsvd1[3]; | ||
| 718 | __be16 dst_port; | ||
| 719 | __be16 rsvd2; | ||
| 720 | __be16 dst_port_msk; | ||
| 721 | __be16 rsvd3; | ||
| 722 | __be16 src_port; | ||
| 723 | __be16 rsvd4; | ||
| 724 | __be16 src_port_msk; | ||
| 725 | } __packed; | ||
| 726 | |||
| 727 | struct mlx4_net_trans_rule_hw_ipv4 { | ||
| 728 | u8 size; | ||
| 729 | u8 rsvd; | ||
| 730 | __be16 id; | ||
| 731 | __be32 rsvd1; | ||
| 732 | __be32 dst_ip; | ||
| 733 | __be32 dst_ip_msk; | ||
| 734 | __be32 src_ip; | ||
| 735 | __be32 src_ip_msk; | ||
| 736 | } __packed; | ||
| 737 | |||
| 738 | struct _rule_hw { | ||
| 739 | union { | ||
| 740 | struct { | ||
| 741 | u8 size; | ||
| 742 | u8 rsvd; | ||
| 743 | __be16 id; | ||
| 744 | }; | ||
| 745 | struct mlx4_net_trans_rule_hw_eth eth; | ||
| 746 | struct mlx4_net_trans_rule_hw_ib ib; | ||
| 747 | struct mlx4_net_trans_rule_hw_ipv4 ipv4; | ||
| 748 | struct mlx4_net_trans_rule_hw_tcp_udp tcp_udp; | ||
| 749 | }; | ||
| 750 | }; | 683 | }; |
| 751 | 684 | ||
| 752 | static int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec, | 685 | static int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec, |
| 753 | struct _rule_hw *rule_hw) | 686 | struct _rule_hw *rule_hw) |
| 754 | { | 687 | { |
| 755 | static const u16 __sw_id_hw[] = { | ||
| 756 | [MLX4_NET_TRANS_RULE_ID_ETH] = 0xE001, | ||
| 757 | [MLX4_NET_TRANS_RULE_ID_IB] = 0xE005, | ||
| 758 | [MLX4_NET_TRANS_RULE_ID_IPV6] = 0xE003, | ||
| 759 | [MLX4_NET_TRANS_RULE_ID_IPV4] = 0xE002, | ||
| 760 | [MLX4_NET_TRANS_RULE_ID_TCP] = 0xE004, | ||
| 761 | [MLX4_NET_TRANS_RULE_ID_UDP] = 0xE006 | ||
| 762 | }; | ||
| 763 | |||
| 764 | static const size_t __rule_hw_sz[] = { | 688 | static const size_t __rule_hw_sz[] = { |
| 765 | [MLX4_NET_TRANS_RULE_ID_ETH] = | 689 | [MLX4_NET_TRANS_RULE_ID_ETH] = |
| 766 | sizeof(struct mlx4_net_trans_rule_hw_eth), | 690 | sizeof(struct mlx4_net_trans_rule_hw_eth), |
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 4d9df8f2a126..dba69d98734a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h | |||
| @@ -690,6 +690,82 @@ struct mlx4_steer { | |||
| 690 | struct list_head steer_entries[MLX4_NUM_STEERS]; | 690 | struct list_head steer_entries[MLX4_NUM_STEERS]; |
| 691 | }; | 691 | }; |
| 692 | 692 | ||
| 693 | struct mlx4_net_trans_rule_hw_ctrl { | ||
| 694 | __be32 ctrl; | ||
| 695 | __be32 vf_vep_port; | ||
| 696 | __be32 qpn; | ||
| 697 | __be32 reserved; | ||
| 698 | }; | ||
| 699 | |||
| 700 | struct mlx4_net_trans_rule_hw_ib { | ||
| 701 | u8 size; | ||
| 702 | u8 rsvd1; | ||
| 703 | __be16 id; | ||
| 704 | u32 rsvd2; | ||
| 705 | __be32 qpn; | ||
| 706 | __be32 qpn_mask; | ||
| 707 | u8 dst_gid[16]; | ||
| 708 | u8 dst_gid_msk[16]; | ||
| 709 | } __packed; | ||
| 710 | |||
| 711 | struct mlx4_net_trans_rule_hw_eth { | ||
| 712 | u8 size; | ||
| 713 | u8 rsvd; | ||
| 714 | __be16 id; | ||
| 715 | u8 rsvd1[6]; | ||
| 716 | u8 dst_mac[6]; | ||
| 717 | u16 rsvd2; | ||
| 718 | u8 dst_mac_msk[6]; | ||
| 719 | u16 rsvd3; | ||
| 720 | u8 src_mac[6]; | ||
| 721 | u16 rsvd4; | ||
| 722 | u8 src_mac_msk[6]; | ||
| 723 | u8 rsvd5; | ||
| 724 | u8 ether_type_enable; | ||
| 725 | __be16 ether_type; | ||
| 726 | __be16 vlan_id_msk; | ||
| 727 | __be16 vlan_id; | ||
| 728 | } __packed; | ||
| 729 | |||
| 730 | struct mlx4_net_trans_rule_hw_tcp_udp { | ||
| 731 | u8 size; | ||
| 732 | u8 rsvd; | ||
| 733 | __be16 id; | ||
| 734 | __be16 rsvd1[3]; | ||
| 735 | __be16 dst_port; | ||
| 736 | __be16 rsvd2; | ||
| 737 | __be16 dst_port_msk; | ||
| 738 | __be16 rsvd3; | ||
| 739 | __be16 src_port; | ||
| 740 | __be16 rsvd4; | ||
| 741 | __be16 src_port_msk; | ||
| 742 | } __packed; | ||
| 743 | |||
| 744 | struct mlx4_net_trans_rule_hw_ipv4 { | ||
| 745 | u8 size; | ||
| 746 | u8 rsvd; | ||
| 747 | __be16 id; | ||
| 748 | __be32 rsvd1; | ||
| 749 | __be32 dst_ip; | ||
| 750 | __be32 dst_ip_msk; | ||
| 751 | __be32 src_ip; | ||
| 752 | __be32 src_ip_msk; | ||
| 753 | } __packed; | ||
| 754 | |||
| 755 | struct _rule_hw { | ||
| 756 | union { | ||
| 757 | struct { | ||
| 758 | u8 size; | ||
| 759 | u8 rsvd; | ||
| 760 | __be16 id; | ||
| 761 | }; | ||
| 762 | struct mlx4_net_trans_rule_hw_eth eth; | ||
| 763 | struct mlx4_net_trans_rule_hw_ib ib; | ||
| 764 | struct mlx4_net_trans_rule_hw_ipv4 ipv4; | ||
| 765 | struct mlx4_net_trans_rule_hw_tcp_udp tcp_udp; | ||
| 766 | }; | ||
| 767 | }; | ||
| 768 | |||
| 693 | struct mlx4_priv { | 769 | struct mlx4_priv { |
| 694 | struct mlx4_dev dev; | 770 | struct mlx4_dev dev; |
| 695 | 771 | ||
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 94ceddd17ab2..293c9e820c49 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | |||
| @@ -42,6 +42,7 @@ | |||
| 42 | #include <linux/mlx4/cmd.h> | 42 | #include <linux/mlx4/cmd.h> |
| 43 | #include <linux/mlx4/qp.h> | 43 | #include <linux/mlx4/qp.h> |
| 44 | #include <linux/if_ether.h> | 44 | #include <linux/if_ether.h> |
| 45 | #include <linux/etherdevice.h> | ||
| 45 | 46 | ||
| 46 | #include "mlx4.h" | 47 | #include "mlx4.h" |
| 47 | #include "fw.h" | 48 | #include "fw.h" |
| @@ -2776,18 +2777,133 @@ ex_put: | |||
| 2776 | return err; | 2777 | return err; |
| 2777 | } | 2778 | } |
| 2778 | 2779 | ||
| 2780 | /* | ||
| 2781 | * MAC validation for Flow Steering rules. | ||
| 2782 | * VF can attach rules only with a mac address which is assigned to it. | ||
| 2783 | */ | ||
| 2784 | static int validate_eth_header_mac(int slave, struct _rule_hw *eth_header, | ||
| 2785 | struct list_head *rlist) | ||
| 2786 | { | ||
| 2787 | struct mac_res *res, *tmp; | ||
| 2788 | __be64 be_mac; | ||
| 2789 | |||
| 2790 | /* make sure it isn't multicast or broadcast mac*/ | ||
| 2791 | if (!is_multicast_ether_addr(eth_header->eth.dst_mac) && | ||
| 2792 | !is_broadcast_ether_addr(eth_header->eth.dst_mac)) { | ||
| 2793 | list_for_each_entry_safe(res, tmp, rlist, list) { | ||
| 2794 | be_mac = cpu_to_be64(res->mac << 16); | ||
| 2795 | if (!memcmp(&be_mac, eth_header->eth.dst_mac, ETH_ALEN)) | ||
| 2796 | return 0; | ||
| 2797 | } | ||
| 2798 | pr_err("MAC %pM doesn't belong to VF %d, Steering rule rejected\n", | ||
| 2799 | eth_header->eth.dst_mac, slave); | ||
| 2800 | return -EINVAL; | ||
| 2801 | } | ||
| 2802 | return 0; | ||
| 2803 | } | ||
| 2804 | |||
| 2805 | /* | ||
| 2806 | * In case of missing eth header, append eth header with a MAC address | ||
| 2807 | * assigned to the VF. | ||
| 2808 | */ | ||
| 2809 | static int add_eth_header(struct mlx4_dev *dev, int slave, | ||
| 2810 | struct mlx4_cmd_mailbox *inbox, | ||
| 2811 | struct list_head *rlist, int header_id) | ||
| 2812 | { | ||
| 2813 | struct mac_res *res, *tmp; | ||
| 2814 | u8 port; | ||
| 2815 | struct mlx4_net_trans_rule_hw_ctrl *ctrl; | ||
| 2816 | struct mlx4_net_trans_rule_hw_eth *eth_header; | ||
| 2817 | struct mlx4_net_trans_rule_hw_ipv4 *ip_header; | ||
| 2818 | struct mlx4_net_trans_rule_hw_tcp_udp *l4_header; | ||
| 2819 | __be64 be_mac = 0; | ||
| 2820 | __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16); | ||
| 2821 | |||
| 2822 | ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; | ||
| 2823 | port = be32_to_cpu(ctrl->vf_vep_port) & 0xff; | ||
| 2824 | eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1); | ||
| 2825 | |||
| 2826 | /* Clear a space in the inbox for eth header */ | ||
| 2827 | switch (header_id) { | ||
| 2828 | case MLX4_NET_TRANS_RULE_ID_IPV4: | ||
| 2829 | ip_header = | ||
| 2830 | (struct mlx4_net_trans_rule_hw_ipv4 *)(eth_header + 1); | ||
| 2831 | memmove(ip_header, eth_header, | ||
| 2832 | sizeof(*ip_header) + sizeof(*l4_header)); | ||
| 2833 | break; | ||
| 2834 | case MLX4_NET_TRANS_RULE_ID_TCP: | ||
| 2835 | case MLX4_NET_TRANS_RULE_ID_UDP: | ||
| 2836 | l4_header = (struct mlx4_net_trans_rule_hw_tcp_udp *) | ||
| 2837 | (eth_header + 1); | ||
| 2838 | memmove(l4_header, eth_header, sizeof(*l4_header)); | ||
| 2839 | break; | ||
| 2840 | default: | ||
| 2841 | return -EINVAL; | ||
| 2842 | } | ||
| 2843 | list_for_each_entry_safe(res, tmp, rlist, list) { | ||
| 2844 | if (port == res->port) { | ||
| 2845 | be_mac = cpu_to_be64(res->mac << 16); | ||
| 2846 | break; | ||
| 2847 | } | ||
| 2848 | } | ||
| 2849 | if (!be_mac) { | ||
| 2850 | pr_err("Failed adding eth header to FS rule, Can't find matching MAC for port %d .\n", | ||
| 2851 | port); | ||
| 2852 | return -EINVAL; | ||
| 2853 | } | ||
| 2854 | |||
| 2855 | memset(eth_header, 0, sizeof(*eth_header)); | ||
| 2856 | eth_header->size = sizeof(*eth_header) >> 2; | ||
| 2857 | eth_header->id = cpu_to_be16(__sw_id_hw[MLX4_NET_TRANS_RULE_ID_ETH]); | ||
| 2858 | memcpy(eth_header->dst_mac, &be_mac, ETH_ALEN); | ||
| 2859 | memcpy(eth_header->dst_mac_msk, &mac_msk, ETH_ALEN); | ||
| 2860 | |||
| 2861 | return 0; | ||
| 2862 | |||
| 2863 | } | ||
| 2864 | |||
| 2779 | int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, | 2865 | int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, |
| 2780 | struct mlx4_vhcr *vhcr, | 2866 | struct mlx4_vhcr *vhcr, |
| 2781 | struct mlx4_cmd_mailbox *inbox, | 2867 | struct mlx4_cmd_mailbox *inbox, |
| 2782 | struct mlx4_cmd_mailbox *outbox, | 2868 | struct mlx4_cmd_mailbox *outbox, |
| 2783 | struct mlx4_cmd_info *cmd) | 2869 | struct mlx4_cmd_info *cmd) |
| 2784 | { | 2870 | { |
| 2871 | |||
| 2872 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
| 2873 | struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; | ||
| 2874 | struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC]; | ||
| 2785 | int err; | 2875 | int err; |
| 2876 | struct mlx4_net_trans_rule_hw_ctrl *ctrl; | ||
| 2877 | struct _rule_hw *rule_header; | ||
| 2878 | int header_id; | ||
| 2786 | 2879 | ||
| 2787 | if (dev->caps.steering_mode != | 2880 | if (dev->caps.steering_mode != |
| 2788 | MLX4_STEERING_MODE_DEVICE_MANAGED) | 2881 | MLX4_STEERING_MODE_DEVICE_MANAGED) |
| 2789 | return -EOPNOTSUPP; | 2882 | return -EOPNOTSUPP; |
| 2790 | 2883 | ||
| 2884 | ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; | ||
| 2885 | rule_header = (struct _rule_hw *)(ctrl + 1); | ||
| 2886 | header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id)); | ||
| 2887 | |||
| 2888 | switch (header_id) { | ||
| 2889 | case MLX4_NET_TRANS_RULE_ID_ETH: | ||
| 2890 | if (validate_eth_header_mac(slave, rule_header, rlist)) | ||
| 2891 | return -EINVAL; | ||
| 2892 | break; | ||
| 2893 | case MLX4_NET_TRANS_RULE_ID_IPV4: | ||
| 2894 | case MLX4_NET_TRANS_RULE_ID_TCP: | ||
| 2895 | case MLX4_NET_TRANS_RULE_ID_UDP: | ||
| 2896 | pr_warn("Can't attach FS rule without L2 headers, adding L2 header.\n"); | ||
| 2897 | if (add_eth_header(dev, slave, inbox, rlist, header_id)) | ||
| 2898 | return -EINVAL; | ||
| 2899 | vhcr->in_modifier += | ||
| 2900 | sizeof(struct mlx4_net_trans_rule_hw_eth) >> 2; | ||
| 2901 | break; | ||
| 2902 | default: | ||
| 2903 | pr_err("Corrupted mailbox.\n"); | ||
| 2904 | return -EINVAL; | ||
| 2905 | } | ||
| 2906 | |||
| 2791 | err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param, | 2907 | err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param, |
| 2792 | vhcr->in_modifier, 0, | 2908 | vhcr->in_modifier, 0, |
| 2793 | MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, | 2909 | MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, |
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c index c42bbb16cdae..a688a2ddcfd6 100644 --- a/drivers/net/ethernet/octeon/octeon_mgmt.c +++ b/drivers/net/ethernet/octeon/octeon_mgmt.c | |||
| @@ -722,10 +722,8 @@ static int octeon_mgmt_init_phy(struct net_device *netdev) | |||
| 722 | octeon_mgmt_adjust_link, 0, | 722 | octeon_mgmt_adjust_link, 0, |
| 723 | PHY_INTERFACE_MODE_MII); | 723 | PHY_INTERFACE_MODE_MII); |
| 724 | 724 | ||
| 725 | if (IS_ERR(p->phydev)) { | 725 | if (!p->phydev) |
| 726 | p->phydev = NULL; | ||
| 727 | return -1; | 726 | return -1; |
| 728 | } | ||
| 729 | 727 | ||
| 730 | phy_start_aneg(p->phydev); | 728 | phy_start_aneg(p->phydev); |
| 731 | 729 | ||
diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.c b/drivers/net/ethernet/pasemi/pasemi_mac.c index e559dfa06d6a..6fa74d530e44 100644 --- a/drivers/net/ethernet/pasemi/pasemi_mac.c +++ b/drivers/net/ethernet/pasemi/pasemi_mac.c | |||
| @@ -1101,9 +1101,9 @@ static int pasemi_mac_phy_init(struct net_device *dev) | |||
| 1101 | phydev = of_phy_connect(dev, phy_dn, &pasemi_adjust_link, 0, | 1101 | phydev = of_phy_connect(dev, phy_dn, &pasemi_adjust_link, 0, |
| 1102 | PHY_INTERFACE_MODE_SGMII); | 1102 | PHY_INTERFACE_MODE_SGMII); |
| 1103 | 1103 | ||
| 1104 | if (IS_ERR(phydev)) { | 1104 | if (!phydev) { |
| 1105 | printk(KERN_ERR "%s: Could not attach to phy\n", dev->name); | 1105 | printk(KERN_ERR "%s: Could not attach to phy\n", dev->name); |
| 1106 | return PTR_ERR(phydev); | 1106 | return -ENODEV; |
| 1107 | } | 1107 | } |
| 1108 | 1108 | ||
| 1109 | mac->phydev = phydev; | 1109 | mac->phydev = phydev; |
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index fdc5ca0f7b64..df450616ab37 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c | |||
| @@ -1378,6 +1378,10 @@ static void netxen_mask_aer_correctable(struct netxen_adapter *adapter) | |||
| 1378 | struct pci_dev *root = pdev->bus->self; | 1378 | struct pci_dev *root = pdev->bus->self; |
| 1379 | u32 aer_pos; | 1379 | u32 aer_pos; |
| 1380 | 1380 | ||
| 1381 | /* root bus? */ | ||
| 1382 | if (!root) | ||
| 1383 | return; | ||
| 1384 | |||
| 1381 | if (adapter->ahw.board_type != NETXEN_BRDTYPE_P3_4_GB_MM && | 1385 | if (adapter->ahw.board_type != NETXEN_BRDTYPE_P3_4_GB_MM && |
| 1382 | adapter->ahw.board_type != NETXEN_BRDTYPE_P3_10G_TP) | 1386 | adapter->ahw.board_type != NETXEN_BRDTYPE_P3_10G_TP) |
| 1383 | return; | 1387 | return; |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index b8ead696141e..2a179d087207 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c | |||
| @@ -15,7 +15,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter) | |||
| 15 | 15 | ||
| 16 | do { | 16 | do { |
| 17 | /* give atleast 1ms for firmware to respond */ | 17 | /* give atleast 1ms for firmware to respond */ |
| 18 | msleep(1); | 18 | mdelay(1); |
| 19 | 19 | ||
| 20 | if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT) | 20 | if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT) |
| 21 | return QLCNIC_CDRP_RSP_TIMEOUT; | 21 | return QLCNIC_CDRP_RSP_TIMEOUT; |
| @@ -601,7 +601,7 @@ void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter) | |||
| 601 | qlcnic_fw_cmd_destroy_tx_ctx(adapter); | 601 | qlcnic_fw_cmd_destroy_tx_ctx(adapter); |
| 602 | 602 | ||
| 603 | /* Allow dma queues to drain after context reset */ | 603 | /* Allow dma queues to drain after context reset */ |
| 604 | msleep(20); | 604 | mdelay(20); |
| 605 | } | 605 | } |
| 606 | } | 606 | } |
| 607 | 607 | ||
diff --git a/drivers/net/ethernet/seeq/sgiseeq.c b/drivers/net/ethernet/seeq/sgiseeq.c index bb8c8222122b..4d15bf413bdc 100644 --- a/drivers/net/ethernet/seeq/sgiseeq.c +++ b/drivers/net/ethernet/seeq/sgiseeq.c | |||
| @@ -751,6 +751,7 @@ static int __devinit sgiseeq_probe(struct platform_device *pdev) | |||
| 751 | sp->srings = sr; | 751 | sp->srings = sr; |
| 752 | sp->rx_desc = sp->srings->rxvector; | 752 | sp->rx_desc = sp->srings->rxvector; |
| 753 | sp->tx_desc = sp->srings->txvector; | 753 | sp->tx_desc = sp->srings->txvector; |
| 754 | spin_lock_init(&sp->tx_lock); | ||
| 754 | 755 | ||
| 755 | /* A couple calculations now, saves many cycles later. */ | 756 | /* A couple calculations now, saves many cycles later. */ |
| 756 | setup_rx_ring(dev, sp->rx_desc, SEEQ_RX_BUFFERS); | 757 | setup_rx_ring(dev, sp->rx_desc, SEEQ_RX_BUFFERS); |
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index c136162e6473..3be88331d17a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | |||
| @@ -1066,7 +1066,7 @@ static int stmmac_open(struct net_device *dev) | |||
| 1066 | } else | 1066 | } else |
| 1067 | priv->tm->enable = 1; | 1067 | priv->tm->enable = 1; |
| 1068 | #endif | 1068 | #endif |
| 1069 | clk_enable(priv->stmmac_clk); | 1069 | clk_prepare_enable(priv->stmmac_clk); |
| 1070 | 1070 | ||
| 1071 | stmmac_check_ether_addr(priv); | 1071 | stmmac_check_ether_addr(priv); |
| 1072 | 1072 | ||
| @@ -1188,7 +1188,7 @@ open_error: | |||
| 1188 | if (priv->phydev) | 1188 | if (priv->phydev) |
| 1189 | phy_disconnect(priv->phydev); | 1189 | phy_disconnect(priv->phydev); |
| 1190 | 1190 | ||
| 1191 | clk_disable(priv->stmmac_clk); | 1191 | clk_disable_unprepare(priv->stmmac_clk); |
| 1192 | 1192 | ||
| 1193 | return ret; | 1193 | return ret; |
| 1194 | } | 1194 | } |
| @@ -1246,7 +1246,7 @@ static int stmmac_release(struct net_device *dev) | |||
| 1246 | #ifdef CONFIG_STMMAC_DEBUG_FS | 1246 | #ifdef CONFIG_STMMAC_DEBUG_FS |
| 1247 | stmmac_exit_fs(); | 1247 | stmmac_exit_fs(); |
| 1248 | #endif | 1248 | #endif |
| 1249 | clk_disable(priv->stmmac_clk); | 1249 | clk_disable_unprepare(priv->stmmac_clk); |
| 1250 | 1250 | ||
| 1251 | return 0; | 1251 | return 0; |
| 1252 | } | 1252 | } |
| @@ -2178,7 +2178,7 @@ int stmmac_suspend(struct net_device *ndev) | |||
| 2178 | else { | 2178 | else { |
| 2179 | stmmac_set_mac(priv->ioaddr, false); | 2179 | stmmac_set_mac(priv->ioaddr, false); |
| 2180 | /* Disable clock in case of PWM is off */ | 2180 | /* Disable clock in case of PWM is off */ |
| 2181 | clk_disable(priv->stmmac_clk); | 2181 | clk_disable_unprepare(priv->stmmac_clk); |
| 2182 | } | 2182 | } |
| 2183 | spin_unlock_irqrestore(&priv->lock, flags); | 2183 | spin_unlock_irqrestore(&priv->lock, flags); |
| 2184 | return 0; | 2184 | return 0; |
| @@ -2203,7 +2203,7 @@ int stmmac_resume(struct net_device *ndev) | |||
| 2203 | priv->hw->mac->pmt(priv->ioaddr, 0); | 2203 | priv->hw->mac->pmt(priv->ioaddr, 0); |
| 2204 | else | 2204 | else |
| 2205 | /* enable the clk prevously disabled */ | 2205 | /* enable the clk prevously disabled */ |
| 2206 | clk_enable(priv->stmmac_clk); | 2206 | clk_prepare_enable(priv->stmmac_clk); |
| 2207 | 2207 | ||
| 2208 | netif_device_attach(ndev); | 2208 | netif_device_attach(ndev); |
| 2209 | 2209 | ||
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c index 2a0e1abde7e7..4ccd4e2977b7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c | |||
| @@ -97,19 +97,19 @@ static struct clk *timer_clock; | |||
| 97 | static void stmmac_tmu_start(unsigned int new_freq) | 97 | static void stmmac_tmu_start(unsigned int new_freq) |
| 98 | { | 98 | { |
| 99 | clk_set_rate(timer_clock, new_freq); | 99 | clk_set_rate(timer_clock, new_freq); |
| 100 | clk_enable(timer_clock); | 100 | clk_prepare_enable(timer_clock); |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | static void stmmac_tmu_stop(void) | 103 | static void stmmac_tmu_stop(void) |
| 104 | { | 104 | { |
| 105 | clk_disable(timer_clock); | 105 | clk_disable_unprepare(timer_clock); |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm) | 108 | int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm) |
| 109 | { | 109 | { |
| 110 | timer_clock = clk_get(NULL, TMU_CHANNEL); | 110 | timer_clock = clk_get(NULL, TMU_CHANNEL); |
| 111 | 111 | ||
| 112 | if (timer_clock == NULL) | 112 | if (IS_ERR(timer_clock)) |
| 113 | return -1; | 113 | return -1; |
| 114 | 114 | ||
| 115 | if (tmu2_register_user(stmmac_timer_handler, (void *)dev) < 0) { | 115 | if (tmu2_register_user(stmmac_timer_handler, (void *)dev) < 0) { |
| @@ -126,7 +126,7 @@ int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm) | |||
| 126 | 126 | ||
| 127 | int stmmac_close_ext_timer(void) | 127 | int stmmac_close_ext_timer(void) |
| 128 | { | 128 | { |
| 129 | clk_disable(timer_clock); | 129 | clk_disable_unprepare(timer_clock); |
| 130 | tmu2_unregister_user(); | 130 | tmu2_unregister_user(); |
| 131 | clk_put(timer_clock); | 131 | clk_put(timer_clock); |
| 132 | return 0; | 132 | return 0; |
diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c index 256eddf1f75a..795109425568 100644 --- a/drivers/net/irda/sh_sir.c +++ b/drivers/net/irda/sh_sir.c | |||
| @@ -280,7 +280,7 @@ static int sh_sir_set_baudrate(struct sh_sir_self *self, u32 baudrate) | |||
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | clk = clk_get(NULL, "irda_clk"); | 282 | clk = clk_get(NULL, "irda_clk"); |
| 283 | if (!clk) { | 283 | if (IS_ERR(clk)) { |
| 284 | dev_err(dev, "can not get irda_clk\n"); | 284 | dev_err(dev, "can not get irda_clk\n"); |
| 285 | return -EIO; | 285 | return -EIO; |
| 286 | } | 286 | } |
diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c index 2346b38b9837..799789518e87 100644 --- a/drivers/net/phy/bcm87xx.c +++ b/drivers/net/phy/bcm87xx.c | |||
| @@ -229,3 +229,5 @@ static void __exit bcm87xx_exit(void) | |||
| 229 | ARRAY_SIZE(bcm87xx_driver)); | 229 | ARRAY_SIZE(bcm87xx_driver)); |
| 230 | } | 230 | } |
| 231 | module_exit(bcm87xx_exit); | 231 | module_exit(bcm87xx_exit); |
| 232 | |||
| 233 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index cf287e0eb408..2165d5fdb8c0 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c | |||
| @@ -21,6 +21,12 @@ | |||
| 21 | #include <linux/phy.h> | 21 | #include <linux/phy.h> |
| 22 | #include <linux/micrel_phy.h> | 22 | #include <linux/micrel_phy.h> |
| 23 | 23 | ||
| 24 | /* Operation Mode Strap Override */ | ||
| 25 | #define MII_KSZPHY_OMSO 0x16 | ||
| 26 | #define KSZPHY_OMSO_B_CAST_OFF (1 << 9) | ||
| 27 | #define KSZPHY_OMSO_RMII_OVERRIDE (1 << 1) | ||
| 28 | #define KSZPHY_OMSO_MII_OVERRIDE (1 << 0) | ||
| 29 | |||
| 24 | /* general Interrupt control/status reg in vendor specific block. */ | 30 | /* general Interrupt control/status reg in vendor specific block. */ |
| 25 | #define MII_KSZPHY_INTCS 0x1B | 31 | #define MII_KSZPHY_INTCS 0x1B |
| 26 | #define KSZPHY_INTCS_JABBER (1 << 15) | 32 | #define KSZPHY_INTCS_JABBER (1 << 15) |
| @@ -101,6 +107,13 @@ static int kszphy_config_init(struct phy_device *phydev) | |||
| 101 | return 0; | 107 | return 0; |
| 102 | } | 108 | } |
| 103 | 109 | ||
| 110 | static int ksz8021_config_init(struct phy_device *phydev) | ||
| 111 | { | ||
| 112 | const u16 val = KSZPHY_OMSO_B_CAST_OFF | KSZPHY_OMSO_RMII_OVERRIDE; | ||
| 113 | phy_write(phydev, MII_KSZPHY_OMSO, val); | ||
| 114 | return 0; | ||
| 115 | } | ||
| 116 | |||
| 104 | static int ks8051_config_init(struct phy_device *phydev) | 117 | static int ks8051_config_init(struct phy_device *phydev) |
| 105 | { | 118 | { |
| 106 | int regval; | 119 | int regval; |
| @@ -128,9 +141,22 @@ static struct phy_driver ksphy_driver[] = { | |||
| 128 | .config_intr = ks8737_config_intr, | 141 | .config_intr = ks8737_config_intr, |
| 129 | .driver = { .owner = THIS_MODULE,}, | 142 | .driver = { .owner = THIS_MODULE,}, |
| 130 | }, { | 143 | }, { |
| 131 | .phy_id = PHY_ID_KS8041, | 144 | .phy_id = PHY_ID_KSZ8021, |
| 145 | .phy_id_mask = 0x00ffffff, | ||
| 146 | .name = "Micrel KSZ8021", | ||
| 147 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause | | ||
| 148 | SUPPORTED_Asym_Pause), | ||
| 149 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | ||
| 150 | .config_init = ksz8021_config_init, | ||
| 151 | .config_aneg = genphy_config_aneg, | ||
| 152 | .read_status = genphy_read_status, | ||
| 153 | .ack_interrupt = kszphy_ack_interrupt, | ||
| 154 | .config_intr = kszphy_config_intr, | ||
| 155 | .driver = { .owner = THIS_MODULE,}, | ||
| 156 | }, { | ||
| 157 | .phy_id = PHY_ID_KSZ8041, | ||
| 132 | .phy_id_mask = 0x00fffff0, | 158 | .phy_id_mask = 0x00fffff0, |
| 133 | .name = "Micrel KS8041", | 159 | .name = "Micrel KSZ8041", |
| 134 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause | 160 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
| 135 | | SUPPORTED_Asym_Pause), | 161 | | SUPPORTED_Asym_Pause), |
| 136 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | 162 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, |
| @@ -141,9 +167,9 @@ static struct phy_driver ksphy_driver[] = { | |||
| 141 | .config_intr = kszphy_config_intr, | 167 | .config_intr = kszphy_config_intr, |
| 142 | .driver = { .owner = THIS_MODULE,}, | 168 | .driver = { .owner = THIS_MODULE,}, |
| 143 | }, { | 169 | }, { |
| 144 | .phy_id = PHY_ID_KS8051, | 170 | .phy_id = PHY_ID_KSZ8051, |
| 145 | .phy_id_mask = 0x00fffff0, | 171 | .phy_id_mask = 0x00fffff0, |
| 146 | .name = "Micrel KS8051", | 172 | .name = "Micrel KSZ8051", |
| 147 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause | 173 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
| 148 | | SUPPORTED_Asym_Pause), | 174 | | SUPPORTED_Asym_Pause), |
| 149 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | 175 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, |
| @@ -154,8 +180,8 @@ static struct phy_driver ksphy_driver[] = { | |||
| 154 | .config_intr = kszphy_config_intr, | 180 | .config_intr = kszphy_config_intr, |
| 155 | .driver = { .owner = THIS_MODULE,}, | 181 | .driver = { .owner = THIS_MODULE,}, |
| 156 | }, { | 182 | }, { |
| 157 | .phy_id = PHY_ID_KS8001, | 183 | .phy_id = PHY_ID_KSZ8001, |
| 158 | .name = "Micrel KS8001 or KS8721", | 184 | .name = "Micrel KSZ8001 or KS8721", |
| 159 | .phy_id_mask = 0x00ffffff, | 185 | .phy_id_mask = 0x00ffffff, |
| 160 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), | 186 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), |
| 161 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | 187 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, |
| @@ -201,10 +227,11 @@ MODULE_LICENSE("GPL"); | |||
| 201 | 227 | ||
| 202 | static struct mdio_device_id __maybe_unused micrel_tbl[] = { | 228 | static struct mdio_device_id __maybe_unused micrel_tbl[] = { |
| 203 | { PHY_ID_KSZ9021, 0x000ffffe }, | 229 | { PHY_ID_KSZ9021, 0x000ffffe }, |
| 204 | { PHY_ID_KS8001, 0x00ffffff }, | 230 | { PHY_ID_KSZ8001, 0x00ffffff }, |
| 205 | { PHY_ID_KS8737, 0x00fffff0 }, | 231 | { PHY_ID_KS8737, 0x00fffff0 }, |
| 206 | { PHY_ID_KS8041, 0x00fffff0 }, | 232 | { PHY_ID_KSZ8021, 0x00ffffff }, |
| 207 | { PHY_ID_KS8051, 0x00fffff0 }, | 233 | { PHY_ID_KSZ8041, 0x00fffff0 }, |
| 234 | { PHY_ID_KSZ8051, 0x00fffff0 }, | ||
| 208 | { } | 235 | { } |
| 209 | }; | 236 | }; |
| 210 | 237 | ||
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 6d6192316b30..88e3991464e7 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c | |||
| @@ -56,6 +56,32 @@ static int smsc_phy_config_init(struct phy_device *phydev) | |||
| 56 | return smsc_phy_ack_interrupt (phydev); | 56 | return smsc_phy_ack_interrupt (phydev); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | static int lan87xx_config_init(struct phy_device *phydev) | ||
| 60 | { | ||
| 61 | /* | ||
| 62 | * Make sure the EDPWRDOWN bit is NOT set. Setting this bit on | ||
| 63 | * LAN8710/LAN8720 PHY causes the PHY to misbehave, likely due | ||
| 64 | * to a bug on the chip. | ||
| 65 | * | ||
| 66 | * When the system is powered on with the network cable being | ||
| 67 | * disconnected all the way until after ifconfig ethX up is | ||
| 68 | * issued for the LAN port with this PHY, connecting the cable | ||
| 69 | * afterwards does not cause LINK change detection, while the | ||
| 70 | * expected behavior is the Link UP being detected. | ||
| 71 | */ | ||
| 72 | int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); | ||
| 73 | if (rc < 0) | ||
| 74 | return rc; | ||
| 75 | |||
| 76 | rc &= ~MII_LAN83C185_EDPWRDOWN; | ||
| 77 | |||
| 78 | rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, rc); | ||
| 79 | if (rc < 0) | ||
| 80 | return rc; | ||
| 81 | |||
| 82 | return smsc_phy_ack_interrupt(phydev); | ||
| 83 | } | ||
| 84 | |||
| 59 | static int lan911x_config_init(struct phy_device *phydev) | 85 | static int lan911x_config_init(struct phy_device *phydev) |
| 60 | { | 86 | { |
| 61 | return smsc_phy_ack_interrupt(phydev); | 87 | return smsc_phy_ack_interrupt(phydev); |
| @@ -162,7 +188,7 @@ static struct phy_driver smsc_phy_driver[] = { | |||
| 162 | /* basic functions */ | 188 | /* basic functions */ |
| 163 | .config_aneg = genphy_config_aneg, | 189 | .config_aneg = genphy_config_aneg, |
| 164 | .read_status = genphy_read_status, | 190 | .read_status = genphy_read_status, |
| 165 | .config_init = smsc_phy_config_init, | 191 | .config_init = lan87xx_config_init, |
| 166 | 192 | ||
| 167 | /* IRQ related */ | 193 | /* IRQ related */ |
| 168 | .ack_interrupt = smsc_phy_ack_interrupt, | 194 | .ack_interrupt = smsc_phy_ack_interrupt, |
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index cbf7047decc0..20f31d0d1536 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c | |||
| @@ -570,7 +570,7 @@ static int pppoe_release(struct socket *sock) | |||
| 570 | 570 | ||
| 571 | po = pppox_sk(sk); | 571 | po = pppox_sk(sk); |
| 572 | 572 | ||
| 573 | if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { | 573 | if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { |
| 574 | dev_put(po->pppoe_dev); | 574 | dev_put(po->pppoe_dev); |
| 575 | po->pppoe_dev = NULL; | 575 | po->pppoe_dev = NULL; |
| 576 | } | 576 | } |
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 341b65dbbcd3..f8cd61f449a4 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c | |||
| @@ -848,7 +848,7 @@ static struct netpoll_info *team_netpoll_info(struct team *team) | |||
| 848 | } | 848 | } |
| 849 | #endif | 849 | #endif |
| 850 | 850 | ||
| 851 | static void __team_port_change_check(struct team_port *port, bool linkup); | 851 | static void __team_port_change_port_added(struct team_port *port, bool linkup); |
| 852 | 852 | ||
| 853 | static int team_port_add(struct team *team, struct net_device *port_dev) | 853 | static int team_port_add(struct team *team, struct net_device *port_dev) |
| 854 | { | 854 | { |
| @@ -948,7 +948,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev) | |||
| 948 | team_port_enable(team, port); | 948 | team_port_enable(team, port); |
| 949 | list_add_tail_rcu(&port->list, &team->port_list); | 949 | list_add_tail_rcu(&port->list, &team->port_list); |
| 950 | __team_compute_features(team); | 950 | __team_compute_features(team); |
| 951 | __team_port_change_check(port, !!netif_carrier_ok(port_dev)); | 951 | __team_port_change_port_added(port, !!netif_carrier_ok(port_dev)); |
| 952 | __team_options_change_check(team); | 952 | __team_options_change_check(team); |
| 953 | 953 | ||
| 954 | netdev_info(dev, "Port device %s added\n", portname); | 954 | netdev_info(dev, "Port device %s added\n", portname); |
| @@ -983,6 +983,8 @@ err_set_mtu: | |||
| 983 | return err; | 983 | return err; |
| 984 | } | 984 | } |
| 985 | 985 | ||
| 986 | static void __team_port_change_port_removed(struct team_port *port); | ||
| 987 | |||
| 986 | static int team_port_del(struct team *team, struct net_device *port_dev) | 988 | static int team_port_del(struct team *team, struct net_device *port_dev) |
| 987 | { | 989 | { |
| 988 | struct net_device *dev = team->dev; | 990 | struct net_device *dev = team->dev; |
| @@ -999,8 +1001,7 @@ static int team_port_del(struct team *team, struct net_device *port_dev) | |||
| 999 | __team_option_inst_mark_removed_port(team, port); | 1001 | __team_option_inst_mark_removed_port(team, port); |
| 1000 | __team_options_change_check(team); | 1002 | __team_options_change_check(team); |
| 1001 | __team_option_inst_del_port(team, port); | 1003 | __team_option_inst_del_port(team, port); |
| 1002 | port->removed = true; | 1004 | __team_port_change_port_removed(port); |
| 1003 | __team_port_change_check(port, false); | ||
| 1004 | team_port_disable(team, port); | 1005 | team_port_disable(team, port); |
| 1005 | list_del_rcu(&port->list); | 1006 | list_del_rcu(&port->list); |
| 1006 | netdev_rx_handler_unregister(port_dev); | 1007 | netdev_rx_handler_unregister(port_dev); |
| @@ -1652,8 +1653,8 @@ static int team_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info) | |||
| 1652 | 1653 | ||
| 1653 | hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, | 1654 | hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, |
| 1654 | &team_nl_family, 0, TEAM_CMD_NOOP); | 1655 | &team_nl_family, 0, TEAM_CMD_NOOP); |
| 1655 | if (IS_ERR(hdr)) { | 1656 | if (!hdr) { |
| 1656 | err = PTR_ERR(hdr); | 1657 | err = -EMSGSIZE; |
| 1657 | goto err_msg_put; | 1658 | goto err_msg_put; |
| 1658 | } | 1659 | } |
| 1659 | 1660 | ||
| @@ -1847,8 +1848,8 @@ start_again: | |||
| 1847 | 1848 | ||
| 1848 | hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags | NLM_F_MULTI, | 1849 | hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags | NLM_F_MULTI, |
| 1849 | TEAM_CMD_OPTIONS_GET); | 1850 | TEAM_CMD_OPTIONS_GET); |
| 1850 | if (IS_ERR(hdr)) | 1851 | if (!hdr) |
| 1851 | return PTR_ERR(hdr); | 1852 | return -EMSGSIZE; |
| 1852 | 1853 | ||
| 1853 | if (nla_put_u32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex)) | 1854 | if (nla_put_u32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex)) |
| 1854 | goto nla_put_failure; | 1855 | goto nla_put_failure; |
| @@ -2067,8 +2068,8 @@ static int team_nl_fill_port_list_get(struct sk_buff *skb, | |||
| 2067 | 2068 | ||
| 2068 | hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags, | 2069 | hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags, |
| 2069 | TEAM_CMD_PORT_LIST_GET); | 2070 | TEAM_CMD_PORT_LIST_GET); |
| 2070 | if (IS_ERR(hdr)) | 2071 | if (!hdr) |
| 2071 | return PTR_ERR(hdr); | 2072 | return -EMSGSIZE; |
| 2072 | 2073 | ||
| 2073 | if (nla_put_u32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex)) | 2074 | if (nla_put_u32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex)) |
| 2074 | goto nla_put_failure; | 2075 | goto nla_put_failure; |
| @@ -2251,13 +2252,11 @@ static void __team_options_change_check(struct team *team) | |||
| 2251 | } | 2252 | } |
| 2252 | 2253 | ||
| 2253 | /* rtnl lock is held */ | 2254 | /* rtnl lock is held */ |
| 2254 | static void __team_port_change_check(struct team_port *port, bool linkup) | 2255 | |
| 2256 | static void __team_port_change_send(struct team_port *port, bool linkup) | ||
| 2255 | { | 2257 | { |
| 2256 | int err; | 2258 | int err; |
| 2257 | 2259 | ||
| 2258 | if (!port->removed && port->state.linkup == linkup) | ||
| 2259 | return; | ||
| 2260 | |||
| 2261 | port->changed = true; | 2260 | port->changed = true; |
| 2262 | port->state.linkup = linkup; | 2261 | port->state.linkup = linkup; |
| 2263 | team_refresh_port_linkup(port); | 2262 | team_refresh_port_linkup(port); |
| @@ -2282,6 +2281,23 @@ send_event: | |||
| 2282 | 2281 | ||
| 2283 | } | 2282 | } |
| 2284 | 2283 | ||
| 2284 | static void __team_port_change_check(struct team_port *port, bool linkup) | ||
| 2285 | { | ||
| 2286 | if (port->state.linkup != linkup) | ||
| 2287 | __team_port_change_send(port, linkup); | ||
| 2288 | } | ||
| 2289 | |||
| 2290 | static void __team_port_change_port_added(struct team_port *port, bool linkup) | ||
| 2291 | { | ||
| 2292 | __team_port_change_send(port, linkup); | ||
| 2293 | } | ||
| 2294 | |||
| 2295 | static void __team_port_change_port_removed(struct team_port *port) | ||
| 2296 | { | ||
| 2297 | port->removed = true; | ||
| 2298 | __team_port_change_send(port, false); | ||
| 2299 | } | ||
| 2300 | |||
| 2285 | static void team_port_change_check(struct team_port *port, bool linkup) | 2301 | static void team_port_change_check(struct team_port *port, bool linkup) |
| 2286 | { | 2302 | { |
| 2287 | struct team *team = port->team; | 2303 | struct team *team = port->team; |
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 4fd48df6b989..32e31c5c5dc6 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c | |||
| @@ -962,6 +962,10 @@ static const struct usb_device_id products [] = { | |||
| 962 | USB_DEVICE (0x2001, 0x3c05), | 962 | USB_DEVICE (0x2001, 0x3c05), |
| 963 | .driver_info = (unsigned long) &ax88772_info, | 963 | .driver_info = (unsigned long) &ax88772_info, |
| 964 | }, { | 964 | }, { |
| 965 | // DLink DUB-E100 H/W Ver C1 | ||
| 966 | USB_DEVICE (0x2001, 0x1a02), | ||
| 967 | .driver_info = (unsigned long) &ax88772_info, | ||
| 968 | }, { | ||
| 965 | // Linksys USB1000 | 969 | // Linksys USB1000 |
| 966 | USB_DEVICE (0x1737, 0x0039), | 970 | USB_DEVICE (0x1737, 0x0039), |
| 967 | .driver_info = (unsigned long) &ax88178_info, | 971 | .driver_info = (unsigned long) &ax88178_info, |
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index adfab3fc5478..3543c9e57824 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c | |||
| @@ -297,7 +297,7 @@ static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message) | |||
| 297 | if (ret < 0) | 297 | if (ret < 0) |
| 298 | goto err; | 298 | goto err; |
| 299 | 299 | ||
| 300 | if (info->subdriver && info->subdriver->suspend) | 300 | if (intf == info->control && info->subdriver && info->subdriver->suspend) |
| 301 | ret = info->subdriver->suspend(intf, message); | 301 | ret = info->subdriver->suspend(intf, message); |
| 302 | if (ret < 0) | 302 | if (ret < 0) |
| 303 | usbnet_resume(intf); | 303 | usbnet_resume(intf); |
| @@ -310,13 +310,14 @@ static int qmi_wwan_resume(struct usb_interface *intf) | |||
| 310 | struct usbnet *dev = usb_get_intfdata(intf); | 310 | struct usbnet *dev = usb_get_intfdata(intf); |
| 311 | struct qmi_wwan_state *info = (void *)&dev->data; | 311 | struct qmi_wwan_state *info = (void *)&dev->data; |
| 312 | int ret = 0; | 312 | int ret = 0; |
| 313 | bool callsub = (intf == info->control && info->subdriver && info->subdriver->resume); | ||
| 313 | 314 | ||
| 314 | if (info->subdriver && info->subdriver->resume) | 315 | if (callsub) |
| 315 | ret = info->subdriver->resume(intf); | 316 | ret = info->subdriver->resume(intf); |
| 316 | if (ret < 0) | 317 | if (ret < 0) |
| 317 | goto err; | 318 | goto err; |
| 318 | ret = usbnet_resume(intf); | 319 | ret = usbnet_resume(intf); |
| 319 | if (ret < 0 && info->subdriver && info->subdriver->resume && info->subdriver->suspend) | 320 | if (ret < 0 && callsub && info->subdriver->suspend) |
| 320 | info->subdriver->suspend(intf, PMSG_SUSPEND); | 321 | info->subdriver->suspend(intf, PMSG_SUSPEND); |
| 321 | err: | 322 | err: |
| 322 | return ret; | 323 | return ret; |
| @@ -365,16 +366,20 @@ static const struct usb_device_id products[] = { | |||
| 365 | }, | 366 | }, |
| 366 | 367 | ||
| 367 | /* 2. Combined interface devices matching on class+protocol */ | 368 | /* 2. Combined interface devices matching on class+protocol */ |
| 369 | { /* Huawei E367 and possibly others in "Windows mode" */ | ||
| 370 | USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 7), | ||
| 371 | .driver_info = (unsigned long)&qmi_wwan_info, | ||
| 372 | }, | ||
| 368 | { /* Huawei E392, E398 and possibly others in "Windows mode" */ | 373 | { /* Huawei E392, E398 and possibly others in "Windows mode" */ |
| 369 | USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 17), | 374 | USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 17), |
| 370 | .driver_info = (unsigned long)&qmi_wwan_shared, | 375 | .driver_info = (unsigned long)&qmi_wwan_shared, |
| 371 | }, | 376 | }, |
| 372 | { /* Pantech UML290 */ | 377 | { /* Pantech UML290, P4200 and more */ |
| 373 | USB_DEVICE_AND_INTERFACE_INFO(0x106c, 0x3718, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff), | 378 | USB_VENDOR_AND_INTERFACE_INFO(0x106c, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff), |
| 374 | .driver_info = (unsigned long)&qmi_wwan_shared, | 379 | .driver_info = (unsigned long)&qmi_wwan_shared, |
| 375 | }, | 380 | }, |
| 376 | { /* Pantech UML290 - newer firmware */ | 381 | { /* Pantech UML290 - newer firmware */ |
| 377 | USB_DEVICE_AND_INTERFACE_INFO(0x106c, 0x3718, USB_CLASS_VENDOR_SPEC, 0xf1, 0xff), | 382 | USB_VENDOR_AND_INTERFACE_INFO(0x106c, USB_CLASS_VENDOR_SPEC, 0xf1, 0xff), |
| 378 | .driver_info = (unsigned long)&qmi_wwan_shared, | 383 | .driver_info = (unsigned long)&qmi_wwan_shared, |
| 379 | }, | 384 | }, |
| 380 | 385 | ||
| @@ -382,6 +387,7 @@ static const struct usb_device_id products[] = { | |||
| 382 | {QMI_FIXED_INTF(0x19d2, 0x0055, 1)}, /* ZTE (Vodafone) K3520-Z */ | 387 | {QMI_FIXED_INTF(0x19d2, 0x0055, 1)}, /* ZTE (Vodafone) K3520-Z */ |
| 383 | {QMI_FIXED_INTF(0x19d2, 0x0063, 4)}, /* ZTE (Vodafone) K3565-Z */ | 388 | {QMI_FIXED_INTF(0x19d2, 0x0063, 4)}, /* ZTE (Vodafone) K3565-Z */ |
| 384 | {QMI_FIXED_INTF(0x19d2, 0x0104, 4)}, /* ZTE (Vodafone) K4505-Z */ | 389 | {QMI_FIXED_INTF(0x19d2, 0x0104, 4)}, /* ZTE (Vodafone) K4505-Z */ |
| 390 | {QMI_FIXED_INTF(0x19d2, 0x0157, 5)}, /* ZTE MF683 */ | ||
| 385 | {QMI_FIXED_INTF(0x19d2, 0x0167, 4)}, /* ZTE MF820D */ | 391 | {QMI_FIXED_INTF(0x19d2, 0x0167, 4)}, /* ZTE MF820D */ |
| 386 | {QMI_FIXED_INTF(0x19d2, 0x0326, 4)}, /* ZTE MF821D */ | 392 | {QMI_FIXED_INTF(0x19d2, 0x0326, 4)}, /* ZTE MF821D */ |
| 387 | {QMI_FIXED_INTF(0x19d2, 0x1008, 4)}, /* ZTE (Vodafone) K3570-Z */ | 393 | {QMI_FIXED_INTF(0x19d2, 0x1008, 4)}, /* ZTE (Vodafone) K3570-Z */ |
| @@ -398,7 +404,6 @@ static const struct usb_device_id products[] = { | |||
| 398 | /* 4. Gobi 1000 devices */ | 404 | /* 4. Gobi 1000 devices */ |
| 399 | {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ | 405 | {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ |
| 400 | {QMI_GOBI1K_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ | 406 | {QMI_GOBI1K_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ |
| 401 | {QMI_GOBI1K_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ | ||
| 402 | {QMI_GOBI1K_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ | 407 | {QMI_GOBI1K_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ |
| 403 | {QMI_GOBI1K_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */ | 408 | {QMI_GOBI1K_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */ |
| 404 | {QMI_GOBI1K_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ | 409 | {QMI_GOBI1K_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ |
| @@ -440,6 +445,7 @@ static const struct usb_device_id products[] = { | |||
| 440 | {QMI_GOBI_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ | 445 | {QMI_GOBI_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ |
| 441 | {QMI_GOBI_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ | 446 | {QMI_GOBI_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ |
| 442 | {QMI_GOBI_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ | 447 | {QMI_GOBI_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ |
| 448 | {QMI_GOBI_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ | ||
| 443 | {QMI_GOBI_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */ | 449 | {QMI_GOBI_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */ |
| 444 | {QMI_GOBI_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */ | 450 | {QMI_GOBI_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */ |
| 445 | {QMI_GOBI_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */ | 451 | {QMI_GOBI_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */ |
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c index 7be49ea60b6d..8e22417fa6c1 100644 --- a/drivers/net/usb/sierra_net.c +++ b/drivers/net/usb/sierra_net.c | |||
| @@ -656,7 +656,7 @@ static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap) | |||
| 656 | return -EIO; | 656 | return -EIO; |
| 657 | } | 657 | } |
| 658 | 658 | ||
| 659 | *datap = *attrdata; | 659 | *datap = le16_to_cpu(*attrdata); |
| 660 | 660 | ||
| 661 | kfree(attrdata); | 661 | kfree(attrdata); |
| 662 | return result; | 662 | return result; |
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index f5ab6e613ec8..376143e8a1aa 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c | |||
| @@ -1253,6 +1253,7 @@ static struct usb_driver smsc75xx_driver = { | |||
| 1253 | .probe = usbnet_probe, | 1253 | .probe = usbnet_probe, |
| 1254 | .suspend = usbnet_suspend, | 1254 | .suspend = usbnet_suspend, |
| 1255 | .resume = usbnet_resume, | 1255 | .resume = usbnet_resume, |
| 1256 | .reset_resume = usbnet_resume, | ||
| 1256 | .disconnect = usbnet_disconnect, | 1257 | .disconnect = usbnet_disconnect, |
| 1257 | .disable_hub_initiated_lpm = 1, | 1258 | .disable_hub_initiated_lpm = 1, |
| 1258 | }; | 1259 | }; |
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index fd4b26d46fd5..fc9f578a1e25 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c | |||
| @@ -1201,19 +1201,26 @@ deferred: | |||
| 1201 | } | 1201 | } |
| 1202 | EXPORT_SYMBOL_GPL(usbnet_start_xmit); | 1202 | EXPORT_SYMBOL_GPL(usbnet_start_xmit); |
| 1203 | 1203 | ||
| 1204 | static void rx_alloc_submit(struct usbnet *dev, gfp_t flags) | 1204 | static int rx_alloc_submit(struct usbnet *dev, gfp_t flags) |
| 1205 | { | 1205 | { |
| 1206 | struct urb *urb; | 1206 | struct urb *urb; |
| 1207 | int i; | 1207 | int i; |
| 1208 | int ret = 0; | ||
| 1208 | 1209 | ||
| 1209 | /* don't refill the queue all at once */ | 1210 | /* don't refill the queue all at once */ |
| 1210 | for (i = 0; i < 10 && dev->rxq.qlen < RX_QLEN(dev); i++) { | 1211 | for (i = 0; i < 10 && dev->rxq.qlen < RX_QLEN(dev); i++) { |
| 1211 | urb = usb_alloc_urb(0, flags); | 1212 | urb = usb_alloc_urb(0, flags); |
| 1212 | if (urb != NULL) { | 1213 | if (urb != NULL) { |
| 1213 | if (rx_submit(dev, urb, flags) == -ENOLINK) | 1214 | ret = rx_submit(dev, urb, flags); |
| 1214 | return; | 1215 | if (ret) |
| 1216 | goto err; | ||
| 1217 | } else { | ||
| 1218 | ret = -ENOMEM; | ||
| 1219 | goto err; | ||
| 1215 | } | 1220 | } |
| 1216 | } | 1221 | } |
| 1222 | err: | ||
| 1223 | return ret; | ||
| 1217 | } | 1224 | } |
| 1218 | 1225 | ||
| 1219 | /*-------------------------------------------------------------------------*/ | 1226 | /*-------------------------------------------------------------------------*/ |
| @@ -1257,7 +1264,8 @@ static void usbnet_bh (unsigned long param) | |||
| 1257 | int temp = dev->rxq.qlen; | 1264 | int temp = dev->rxq.qlen; |
| 1258 | 1265 | ||
| 1259 | if (temp < RX_QLEN(dev)) { | 1266 | if (temp < RX_QLEN(dev)) { |
| 1260 | rx_alloc_submit(dev, GFP_ATOMIC); | 1267 | if (rx_alloc_submit(dev, GFP_ATOMIC) == -ENOLINK) |
| 1268 | return; | ||
| 1261 | if (temp != dev->rxq.qlen) | 1269 | if (temp != dev->rxq.qlen) |
| 1262 | netif_dbg(dev, link, dev->net, | 1270 | netif_dbg(dev, link, dev->net, |
| 1263 | "rxqlen %d --> %d\n", | 1271 | "rxqlen %d --> %d\n", |
diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index aaaca9aa2293..3f575afd8cfc 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | 10 | ||
| 11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 12 | 12 | ||
| 13 | #include <linux/module.h> | ||
| 13 | #include <linux/bitops.h> | 14 | #include <linux/bitops.h> |
| 14 | #include <linux/cdev.h> | 15 | #include <linux/cdev.h> |
| 15 | #include <linux/dma-mapping.h> | 16 | #include <linux/dma-mapping.h> |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 2588848f4a82..d066f2516e47 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | |||
| @@ -2982,6 +2982,10 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah, | |||
| 2982 | case EEP_RX_MASK: | 2982 | case EEP_RX_MASK: |
| 2983 | return pBase->txrxMask & 0xf; | 2983 | return pBase->txrxMask & 0xf; |
| 2984 | case EEP_PAPRD: | 2984 | case EEP_PAPRD: |
| 2985 | if (AR_SREV_9462(ah)) | ||
| 2986 | return false; | ||
| 2987 | if (!ah->config.enable_paprd); | ||
| 2988 | return false; | ||
| 2985 | return !!(pBase->featureEnable & BIT(5)); | 2989 | return !!(pBase->featureEnable & BIT(5)); |
| 2986 | case EEP_CHAIN_MASK_REDUCE: | 2990 | case EEP_CHAIN_MASK_REDUCE: |
| 2987 | return (pBase->miscConfiguration >> 0x3) & 0x1; | 2991 | return (pBase->miscConfiguration >> 0x3) & 0x1; |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index 2c9f7d7ed4cc..0ed3846f9cbb 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c | |||
| @@ -142,6 +142,7 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) | |||
| 142 | }; | 142 | }; |
| 143 | int training_power; | 143 | int training_power; |
| 144 | int i, val; | 144 | int i, val; |
| 145 | u32 am2pm_mask = ah->paprd_ratemask; | ||
| 145 | 146 | ||
| 146 | if (IS_CHAN_2GHZ(ah->curchan)) | 147 | if (IS_CHAN_2GHZ(ah->curchan)) |
| 147 | training_power = ar9003_get_training_power_2g(ah); | 148 | training_power = ar9003_get_training_power_2g(ah); |
| @@ -158,10 +159,13 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) | |||
| 158 | } | 159 | } |
| 159 | ah->paprd_training_power = training_power; | 160 | ah->paprd_training_power = training_power; |
| 160 | 161 | ||
| 162 | if (AR_SREV_9330(ah)) | ||
| 163 | am2pm_mask = 0; | ||
| 164 | |||
| 161 | REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, | 165 | REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, |
| 162 | ah->paprd_ratemask); | 166 | ah->paprd_ratemask); |
| 163 | REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, | 167 | REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, |
| 164 | ah->paprd_ratemask); | 168 | am2pm_mask); |
| 165 | REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, | 169 | REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, |
| 166 | ah->paprd_ratemask_ht40); | 170 | ah->paprd_ratemask_ht40); |
| 167 | 171 | ||
| @@ -782,6 +786,102 @@ int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) | |||
| 782 | } | 786 | } |
| 783 | EXPORT_SYMBOL(ar9003_paprd_setup_gain_table); | 787 | EXPORT_SYMBOL(ar9003_paprd_setup_gain_table); |
| 784 | 788 | ||
| 789 | static bool ar9003_paprd_retrain_pa_in(struct ath_hw *ah, | ||
| 790 | struct ath9k_hw_cal_data *caldata, | ||
| 791 | int chain) | ||
| 792 | { | ||
| 793 | u32 *pa_in = caldata->pa_table[chain]; | ||
| 794 | int capdiv_offset, quick_drop_offset; | ||
| 795 | int capdiv2g, quick_drop; | ||
| 796 | int count = 0; | ||
| 797 | int i; | ||
| 798 | |||
| 799 | if (!AR_SREV_9485(ah) && !AR_SREV_9330(ah)) | ||
| 800 | return false; | ||
| 801 | |||
| 802 | capdiv2g = REG_READ_FIELD(ah, AR_PHY_65NM_CH0_TXRF3, | ||
| 803 | AR_PHY_65NM_CH0_TXRF3_CAPDIV2G); | ||
| 804 | |||
| 805 | quick_drop = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, | ||
| 806 | AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP); | ||
| 807 | |||
| 808 | if (quick_drop) | ||
| 809 | quick_drop -= 0x40; | ||
| 810 | |||
| 811 | for (i = 0; i < NUM_BIN + 1; i++) { | ||
| 812 | if (pa_in[i] == 1400) | ||
| 813 | count++; | ||
| 814 | } | ||
| 815 | |||
| 816 | if (AR_SREV_9485(ah)) { | ||
| 817 | if (pa_in[23] < 800) { | ||
| 818 | capdiv_offset = (int)((1000 - pa_in[23] + 75) / 150); | ||
| 819 | capdiv2g += capdiv_offset; | ||
| 820 | if (capdiv2g > 7) { | ||
| 821 | capdiv2g = 7; | ||
| 822 | if (pa_in[23] < 600) { | ||
| 823 | quick_drop++; | ||
| 824 | if (quick_drop > 0) | ||
| 825 | quick_drop = 0; | ||
| 826 | } | ||
| 827 | } | ||
| 828 | } else if (pa_in[23] == 1400) { | ||
| 829 | quick_drop_offset = min_t(int, count / 3, 2); | ||
| 830 | quick_drop += quick_drop_offset; | ||
| 831 | capdiv2g += quick_drop_offset / 2; | ||
| 832 | |||
| 833 | if (capdiv2g > 7) | ||
| 834 | capdiv2g = 7; | ||
| 835 | |||
| 836 | if (quick_drop > 0) { | ||
| 837 | quick_drop = 0; | ||
| 838 | capdiv2g -= quick_drop_offset; | ||
| 839 | if (capdiv2g < 0) | ||
| 840 | capdiv2g = 0; | ||
| 841 | } | ||
| 842 | } else { | ||
| 843 | return false; | ||
| 844 | } | ||
| 845 | } else if (AR_SREV_9330(ah)) { | ||
| 846 | if (pa_in[23] < 1000) { | ||
| 847 | capdiv_offset = (1000 - pa_in[23]) / 100; | ||
| 848 | capdiv2g += capdiv_offset; | ||
| 849 | if (capdiv_offset > 3) { | ||
| 850 | capdiv_offset = 1; | ||
| 851 | quick_drop--; | ||
| 852 | } | ||
| 853 | |||
| 854 | capdiv2g += capdiv_offset; | ||
| 855 | if (capdiv2g > 6) | ||
| 856 | capdiv2g = 6; | ||
| 857 | if (quick_drop < -4) | ||
| 858 | quick_drop = -4; | ||
| 859 | } else if (pa_in[23] == 1400) { | ||
| 860 | if (count > 3) { | ||
| 861 | quick_drop++; | ||
| 862 | capdiv2g -= count / 4; | ||
| 863 | if (quick_drop > -2) | ||
| 864 | quick_drop = -2; | ||
| 865 | } else { | ||
| 866 | capdiv2g--; | ||
| 867 | } | ||
| 868 | |||
| 869 | if (capdiv2g < 0) | ||
| 870 | capdiv2g = 0; | ||
| 871 | } else { | ||
| 872 | return false; | ||
| 873 | } | ||
| 874 | } | ||
| 875 | |||
| 876 | REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_TXRF3, | ||
| 877 | AR_PHY_65NM_CH0_TXRF3_CAPDIV2G, capdiv2g); | ||
| 878 | REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, | ||
| 879 | AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, | ||
| 880 | quick_drop); | ||
| 881 | |||
| 882 | return true; | ||
| 883 | } | ||
| 884 | |||
| 785 | int ar9003_paprd_create_curve(struct ath_hw *ah, | 885 | int ar9003_paprd_create_curve(struct ath_hw *ah, |
| 786 | struct ath9k_hw_cal_data *caldata, int chain) | 886 | struct ath9k_hw_cal_data *caldata, int chain) |
| 787 | { | 887 | { |
| @@ -817,6 +917,9 @@ int ar9003_paprd_create_curve(struct ath_hw *ah, | |||
| 817 | if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain)) | 917 | if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain)) |
| 818 | status = -2; | 918 | status = -2; |
| 819 | 919 | ||
| 920 | if (ar9003_paprd_retrain_pa_in(ah, caldata, chain)) | ||
| 921 | status = -EINPROGRESS; | ||
| 922 | |||
| 820 | REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, | 923 | REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, |
| 821 | AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); | 924 | AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); |
| 822 | 925 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 7bfbaf065a43..84d3d4956861 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h | |||
| @@ -625,6 +625,10 @@ | |||
| 625 | #define AR_PHY_AIC_CTRL_4_B0 (AR_SM_BASE + 0x4c0) | 625 | #define AR_PHY_AIC_CTRL_4_B0 (AR_SM_BASE + 0x4c0) |
| 626 | #define AR_PHY_AIC_STAT_2_B0 (AR_SM_BASE + 0x4cc) | 626 | #define AR_PHY_AIC_STAT_2_B0 (AR_SM_BASE + 0x4cc) |
| 627 | 627 | ||
| 628 | #define AR_PHY_65NM_CH0_TXRF3 0x16048 | ||
| 629 | #define AR_PHY_65NM_CH0_TXRF3_CAPDIV2G 0x0000001e | ||
| 630 | #define AR_PHY_65NM_CH0_TXRF3_CAPDIV2G_S 1 | ||
| 631 | |||
| 628 | #define AR_PHY_65NM_CH0_SYNTH4 0x1608c | 632 | #define AR_PHY_65NM_CH0_SYNTH4 0x1608c |
| 629 | #define AR_PHY_SYNTH4_LONG_SHIFT_SELECT (AR_SREV_9462(ah) ? 0x00000001 : 0x00000002) | 633 | #define AR_PHY_SYNTH4_LONG_SHIFT_SELECT (AR_SREV_9462(ah) ? 0x00000001 : 0x00000002) |
| 630 | #define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S (AR_SREV_9462(ah) ? 0 : 1) | 634 | #define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S (AR_SREV_9462(ah) ? 0 : 1) |
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 68b643c8943c..c8ef30127adb 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c | |||
| @@ -1577,6 +1577,8 @@ int ath9k_init_debug(struct ath_hw *ah) | |||
| 1577 | sc->debug.debugfs_phy, sc, &fops_tx_chainmask); | 1577 | sc->debug.debugfs_phy, sc, &fops_tx_chainmask); |
| 1578 | debugfs_create_file("disable_ani", S_IRUSR | S_IWUSR, | 1578 | debugfs_create_file("disable_ani", S_IRUSR | S_IWUSR, |
| 1579 | sc->debug.debugfs_phy, sc, &fops_disable_ani); | 1579 | sc->debug.debugfs_phy, sc, &fops_disable_ani); |
| 1580 | debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, | ||
| 1581 | &sc->sc_ah->config.enable_paprd); | ||
| 1580 | debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, | 1582 | debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, |
| 1581 | sc, &fops_regidx); | 1583 | sc, &fops_regidx); |
| 1582 | debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, | 1584 | debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, |
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index bacdb8fb4ef4..9f83f71742a5 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c | |||
| @@ -341,7 +341,8 @@ void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc) | |||
| 341 | { | 341 | { |
| 342 | struct ath_btcoex *btcoex = &sc->btcoex; | 342 | struct ath_btcoex *btcoex = &sc->btcoex; |
| 343 | 343 | ||
| 344 | ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); | 344 | if (btcoex->hw_timer_enabled) |
| 345 | ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); | ||
| 345 | } | 346 | } |
| 346 | 347 | ||
| 347 | u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) | 348 | u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) |
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 60b6a9daff7e..4faf0a395876 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
| @@ -463,9 +463,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah) | |||
| 463 | ah->config.spurchans[i][1] = AR_NO_SPUR; | 463 | ah->config.spurchans[i][1] = AR_NO_SPUR; |
| 464 | } | 464 | } |
| 465 | 465 | ||
| 466 | /* PAPRD needs some more work to be enabled */ | ||
| 467 | ah->config.paprd_disable = 1; | ||
| 468 | |||
| 469 | ah->config.rx_intr_mitigation = true; | 466 | ah->config.rx_intr_mitigation = true; |
| 470 | ah->config.pcieSerDesWrite = true; | 467 | ah->config.pcieSerDesWrite = true; |
| 471 | 468 | ||
| @@ -978,9 +975,6 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, | |||
| 978 | else | 975 | else |
| 979 | imr_reg |= AR_IMR_TXOK; | 976 | imr_reg |= AR_IMR_TXOK; |
| 980 | 977 | ||
| 981 | if (opmode == NL80211_IFTYPE_AP) | ||
| 982 | imr_reg |= AR_IMR_MIB; | ||
| 983 | |||
| 984 | ENABLE_REGWRITE_BUFFER(ah); | 978 | ENABLE_REGWRITE_BUFFER(ah); |
| 985 | 979 | ||
| 986 | REG_WRITE(ah, AR_IMR, imr_reg); | 980 | REG_WRITE(ah, AR_IMR, imr_reg); |
| @@ -1778,6 +1772,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
| 1778 | /* Operating channel changed, reset channel calibration data */ | 1772 | /* Operating channel changed, reset channel calibration data */ |
| 1779 | memset(caldata, 0, sizeof(*caldata)); | 1773 | memset(caldata, 0, sizeof(*caldata)); |
| 1780 | ath9k_init_nfcal_hist_buffer(ah, chan); | 1774 | ath9k_init_nfcal_hist_buffer(ah, chan); |
| 1775 | } else if (caldata) { | ||
| 1776 | caldata->paprd_packet_sent = false; | ||
| 1781 | } | 1777 | } |
| 1782 | ah->noise = ath9k_hw_getchan_noise(ah, chan); | 1778 | ah->noise = ath9k_hw_getchan_noise(ah, chan); |
| 1783 | 1779 | ||
| @@ -2501,9 +2497,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
| 2501 | pCap->rx_status_len = sizeof(struct ar9003_rxs); | 2497 | pCap->rx_status_len = sizeof(struct ar9003_rxs); |
| 2502 | pCap->tx_desc_len = sizeof(struct ar9003_txc); | 2498 | pCap->tx_desc_len = sizeof(struct ar9003_txc); |
| 2503 | pCap->txs_len = sizeof(struct ar9003_txs); | 2499 | pCap->txs_len = sizeof(struct ar9003_txs); |
| 2504 | if (!ah->config.paprd_disable && | ||
| 2505 | ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) | ||
| 2506 | pCap->hw_caps |= ATH9K_HW_CAP_PAPRD; | ||
| 2507 | } else { | 2500 | } else { |
| 2508 | pCap->tx_desc_len = sizeof(struct ath_desc); | 2501 | pCap->tx_desc_len = sizeof(struct ath_desc); |
| 2509 | if (AR_SREV_9280_20(ah)) | 2502 | if (AR_SREV_9280_20(ah)) |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index ce7332c64efb..de6968fc64f4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
| @@ -236,7 +236,6 @@ enum ath9k_hw_caps { | |||
| 236 | ATH9K_HW_CAP_LDPC = BIT(6), | 236 | ATH9K_HW_CAP_LDPC = BIT(6), |
| 237 | ATH9K_HW_CAP_FASTCLOCK = BIT(7), | 237 | ATH9K_HW_CAP_FASTCLOCK = BIT(7), |
| 238 | ATH9K_HW_CAP_SGI_20 = BIT(8), | 238 | ATH9K_HW_CAP_SGI_20 = BIT(8), |
| 239 | ATH9K_HW_CAP_PAPRD = BIT(9), | ||
| 240 | ATH9K_HW_CAP_ANT_DIV_COMB = BIT(10), | 239 | ATH9K_HW_CAP_ANT_DIV_COMB = BIT(10), |
| 241 | ATH9K_HW_CAP_2GHZ = BIT(11), | 240 | ATH9K_HW_CAP_2GHZ = BIT(11), |
| 242 | ATH9K_HW_CAP_5GHZ = BIT(12), | 241 | ATH9K_HW_CAP_5GHZ = BIT(12), |
| @@ -287,12 +286,12 @@ struct ath9k_ops_config { | |||
| 287 | u8 pcie_clock_req; | 286 | u8 pcie_clock_req; |
| 288 | u32 pcie_waen; | 287 | u32 pcie_waen; |
| 289 | u8 analog_shiftreg; | 288 | u8 analog_shiftreg; |
| 290 | u8 paprd_disable; | ||
| 291 | u32 ofdm_trig_low; | 289 | u32 ofdm_trig_low; |
| 292 | u32 ofdm_trig_high; | 290 | u32 ofdm_trig_high; |
| 293 | u32 cck_trig_high; | 291 | u32 cck_trig_high; |
| 294 | u32 cck_trig_low; | 292 | u32 cck_trig_low; |
| 295 | u32 enable_ani; | 293 | u32 enable_ani; |
| 294 | u32 enable_paprd; | ||
| 296 | int serialize_regmode; | 295 | int serialize_regmode; |
| 297 | bool rx_intr_mitigation; | 296 | bool rx_intr_mitigation; |
| 298 | bool tx_intr_mitigation; | 297 | bool tx_intr_mitigation; |
| @@ -405,6 +404,7 @@ struct ath9k_hw_cal_data { | |||
| 405 | int8_t iCoff; | 404 | int8_t iCoff; |
| 406 | int8_t qCoff; | 405 | int8_t qCoff; |
| 407 | bool rtt_done; | 406 | bool rtt_done; |
| 407 | bool paprd_packet_sent; | ||
| 408 | bool paprd_done; | 408 | bool paprd_done; |
| 409 | bool nfcal_pending; | 409 | bool nfcal_pending; |
| 410 | bool nfcal_interference; | 410 | bool nfcal_interference; |
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index d4549e9aac5c..7b88b9c39ccd 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c | |||
| @@ -254,8 +254,9 @@ void ath_paprd_calibrate(struct work_struct *work) | |||
| 254 | int chain_ok = 0; | 254 | int chain_ok = 0; |
| 255 | int chain; | 255 | int chain; |
| 256 | int len = 1800; | 256 | int len = 1800; |
| 257 | int ret; | ||
| 257 | 258 | ||
| 258 | if (!caldata) | 259 | if (!caldata || !caldata->paprd_packet_sent || caldata->paprd_done) |
| 259 | return; | 260 | return; |
| 260 | 261 | ||
| 261 | ath9k_ps_wakeup(sc); | 262 | ath9k_ps_wakeup(sc); |
| @@ -282,13 +283,6 @@ void ath_paprd_calibrate(struct work_struct *work) | |||
| 282 | continue; | 283 | continue; |
| 283 | 284 | ||
| 284 | chain_ok = 0; | 285 | chain_ok = 0; |
| 285 | |||
| 286 | ath_dbg(common, CALIBRATE, | ||
| 287 | "Sending PAPRD frame for thermal measurement on chain %d\n", | ||
| 288 | chain); | ||
| 289 | if (!ath_paprd_send_frame(sc, skb, chain)) | ||
| 290 | goto fail_paprd; | ||
| 291 | |||
| 292 | ar9003_paprd_setup_gain_table(ah, chain); | 286 | ar9003_paprd_setup_gain_table(ah, chain); |
| 293 | 287 | ||
| 294 | ath_dbg(common, CALIBRATE, | 288 | ath_dbg(common, CALIBRATE, |
| @@ -302,7 +296,13 @@ void ath_paprd_calibrate(struct work_struct *work) | |||
| 302 | break; | 296 | break; |
| 303 | } | 297 | } |
| 304 | 298 | ||
| 305 | if (ar9003_paprd_create_curve(ah, caldata, chain)) { | 299 | ret = ar9003_paprd_create_curve(ah, caldata, chain); |
| 300 | if (ret == -EINPROGRESS) { | ||
| 301 | ath_dbg(common, CALIBRATE, | ||
| 302 | "PAPRD curve on chain %d needs to be re-trained\n", | ||
| 303 | chain); | ||
| 304 | break; | ||
| 305 | } else if (ret) { | ||
| 306 | ath_dbg(common, CALIBRATE, | 306 | ath_dbg(common, CALIBRATE, |
| 307 | "PAPRD create curve failed on chain %d\n", | 307 | "PAPRD create curve failed on chain %d\n", |
| 308 | chain); | 308 | chain); |
| @@ -423,7 +423,7 @@ set_timer: | |||
| 423 | cal_interval = min(cal_interval, (u32)short_cal_interval); | 423 | cal_interval = min(cal_interval, (u32)short_cal_interval); |
| 424 | 424 | ||
| 425 | mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); | 425 | mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); |
| 426 | if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) { | 426 | if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD) && ah->caldata) { |
| 427 | if (!ah->caldata->paprd_done) | 427 | if (!ah->caldata->paprd_done) |
| 428 | ieee80211_queue_work(sc->hw, &sc->paprd_work); | 428 | ieee80211_queue_work(sc->hw, &sc->paprd_work); |
| 429 | else if (!ah->paprd_table_write_done) | 429 | else if (!ah->paprd_table_write_done) |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2c9da6b2ecb1..0d4155aec48d 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
| @@ -2018,6 +2018,9 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, | |||
| 2018 | 2018 | ||
| 2019 | ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb); | 2019 | ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb); |
| 2020 | 2020 | ||
| 2021 | if (sc->sc_ah->caldata) | ||
| 2022 | sc->sc_ah->caldata->paprd_packet_sent = true; | ||
| 2023 | |||
| 2021 | if (!(tx_flags & ATH_TX_ERROR)) | 2024 | if (!(tx_flags & ATH_TX_ERROR)) |
| 2022 | /* Frame was ACKed */ | 2025 | /* Frame was ACKed */ |
| 2023 | tx_info->flags |= IEEE80211_TX_STAT_ACK; | 2026 | tx_info->flags |= IEEE80211_TX_STAT_ACK; |
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 3876c7ea54f4..7a28d21ac389 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig | |||
| @@ -34,8 +34,8 @@ config B43_BCMA | |||
| 34 | config B43_BCMA_EXTRA | 34 | config B43_BCMA_EXTRA |
| 35 | bool "Hardware support that overlaps with the brcmsmac driver" | 35 | bool "Hardware support that overlaps with the brcmsmac driver" |
| 36 | depends on B43_BCMA | 36 | depends on B43_BCMA |
| 37 | default n if BRCMSMAC || BRCMSMAC_MODULE | 37 | default n if BRCMSMAC |
| 38 | default y | 38 | default y |
| 39 | 39 | ||
| 40 | config B43_SSB | 40 | config B43_SSB |
| 41 | bool | 41 | bool |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 49765d34b4e0..7c4ee72f9d56 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c | |||
| @@ -638,6 +638,8 @@ static int brcmf_sdio_pd_probe(struct platform_device *pdev) | |||
| 638 | 638 | ||
| 639 | oobirq_entry = kzalloc(sizeof(struct brcmf_sdio_oobirq), | 639 | oobirq_entry = kzalloc(sizeof(struct brcmf_sdio_oobirq), |
| 640 | GFP_KERNEL); | 640 | GFP_KERNEL); |
| 641 | if (!oobirq_entry) | ||
| 642 | return -ENOMEM; | ||
| 641 | oobirq_entry->irq = res->start; | 643 | oobirq_entry->irq = res->start; |
| 642 | oobirq_entry->flags = res->flags & IRQF_TRIGGER_MASK; | 644 | oobirq_entry->flags = res->flags & IRQF_TRIGGER_MASK; |
| 643 | list_add_tail(&oobirq_entry->list, &oobirq_lh); | 645 | list_add_tail(&oobirq_entry->list, &oobirq_lh); |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index 2621dd3d7dcd..6f70953f0bad 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c | |||
| @@ -764,8 +764,11 @@ static void brcmf_c_arp_offload_set(struct brcmf_pub *drvr, int arp_mode) | |||
| 764 | { | 764 | { |
| 765 | char iovbuf[32]; | 765 | char iovbuf[32]; |
| 766 | int retcode; | 766 | int retcode; |
| 767 | __le32 arp_mode_le; | ||
| 767 | 768 | ||
| 768 | brcmf_c_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); | 769 | arp_mode_le = cpu_to_le32(arp_mode); |
| 770 | brcmf_c_mkiovar("arp_ol", (char *)&arp_mode_le, 4, iovbuf, | ||
| 771 | sizeof(iovbuf)); | ||
| 769 | retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, | 772 | retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, |
| 770 | iovbuf, sizeof(iovbuf)); | 773 | iovbuf, sizeof(iovbuf)); |
| 771 | retcode = retcode >= 0 ? 0 : retcode; | 774 | retcode = retcode >= 0 ? 0 : retcode; |
| @@ -781,8 +784,11 @@ static void brcmf_c_arp_offload_enable(struct brcmf_pub *drvr, int arp_enable) | |||
| 781 | { | 784 | { |
| 782 | char iovbuf[32]; | 785 | char iovbuf[32]; |
| 783 | int retcode; | 786 | int retcode; |
| 787 | __le32 arp_enable_le; | ||
| 784 | 788 | ||
| 785 | brcmf_c_mkiovar("arpoe", (char *)&arp_enable, 4, | 789 | arp_enable_le = cpu_to_le32(arp_enable); |
| 790 | |||
| 791 | brcmf_c_mkiovar("arpoe", (char *)&arp_enable_le, 4, | ||
| 786 | iovbuf, sizeof(iovbuf)); | 792 | iovbuf, sizeof(iovbuf)); |
| 787 | retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, | 793 | retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, |
| 788 | iovbuf, sizeof(iovbuf)); | 794 | iovbuf, sizeof(iovbuf)); |
| @@ -800,10 +806,10 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) | |||
| 800 | char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; /* Room for | 806 | char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; /* Room for |
| 801 | "event_msgs" + '\0' + bitvec */ | 807 | "event_msgs" + '\0' + bitvec */ |
| 802 | char buf[128], *ptr; | 808 | char buf[128], *ptr; |
| 803 | u32 roaming = 1; | 809 | __le32 roaming_le = cpu_to_le32(1); |
| 804 | uint bcn_timeout = 3; | 810 | __le32 bcn_timeout_le = cpu_to_le32(3); |
| 805 | int scan_assoc_time = 40; | 811 | __le32 scan_assoc_time_le = cpu_to_le32(40); |
| 806 | int scan_unassoc_time = 40; | 812 | __le32 scan_unassoc_time_le = cpu_to_le32(40); |
| 807 | int i; | 813 | int i; |
| 808 | struct brcmf_bus_dcmd *cmdlst; | 814 | struct brcmf_bus_dcmd *cmdlst; |
| 809 | struct list_head *cur, *q; | 815 | struct list_head *cur, *q; |
| @@ -829,14 +835,14 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) | |||
| 829 | 835 | ||
| 830 | /* Setup timeout if Beacons are lost and roam is off to report | 836 | /* Setup timeout if Beacons are lost and roam is off to report |
| 831 | link down */ | 837 | link down */ |
| 832 | brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, | 838 | brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout_le, 4, iovbuf, |
| 833 | sizeof(iovbuf)); | 839 | sizeof(iovbuf)); |
| 834 | brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, | 840 | brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, |
| 835 | sizeof(iovbuf)); | 841 | sizeof(iovbuf)); |
| 836 | 842 | ||
| 837 | /* Enable/Disable build-in roaming to allowed ext supplicant to take | 843 | /* Enable/Disable build-in roaming to allowed ext supplicant to take |
| 838 | of romaing */ | 844 | of romaing */ |
| 839 | brcmf_c_mkiovar("roam_off", (char *)&roaming, 4, | 845 | brcmf_c_mkiovar("roam_off", (char *)&roaming_le, 4, |
| 840 | iovbuf, sizeof(iovbuf)); | 846 | iovbuf, sizeof(iovbuf)); |
| 841 | brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, | 847 | brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, |
| 842 | sizeof(iovbuf)); | 848 | sizeof(iovbuf)); |
| @@ -848,9 +854,9 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) | |||
| 848 | sizeof(iovbuf)); | 854 | sizeof(iovbuf)); |
| 849 | 855 | ||
| 850 | brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME, | 856 | brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME, |
| 851 | (char *)&scan_assoc_time, sizeof(scan_assoc_time)); | 857 | (char *)&scan_assoc_time_le, sizeof(scan_assoc_time_le)); |
| 852 | brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME, | 858 | brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME, |
| 853 | (char *)&scan_unassoc_time, sizeof(scan_unassoc_time)); | 859 | (char *)&scan_unassoc_time_le, sizeof(scan_unassoc_time_le)); |
| 854 | 860 | ||
| 855 | /* Set and enable ARP offload feature */ | 861 | /* Set and enable ARP offload feature */ |
| 856 | brcmf_c_arp_offload_set(drvr, BRCMF_ARPOL_MODE); | 862 | brcmf_c_arp_offload_set(drvr, BRCMF_ARPOL_MODE); |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index a299d42da8e7..58f89fa9c9f8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c | |||
| @@ -519,7 +519,7 @@ static void brcmf_usb_tx_complete(struct urb *urb) | |||
| 519 | else | 519 | else |
| 520 | devinfo->bus_pub.bus->dstats.tx_errors++; | 520 | devinfo->bus_pub.bus->dstats.tx_errors++; |
| 521 | 521 | ||
| 522 | dev_kfree_skb(req->skb); | 522 | brcmu_pkt_buf_free_skb(req->skb); |
| 523 | req->skb = NULL; | 523 | req->skb = NULL; |
| 524 | brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req); | 524 | brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req); |
| 525 | 525 | ||
| @@ -540,7 +540,7 @@ static void brcmf_usb_rx_complete(struct urb *urb) | |||
| 540 | devinfo->bus_pub.bus->dstats.rx_packets++; | 540 | devinfo->bus_pub.bus->dstats.rx_packets++; |
| 541 | } else { | 541 | } else { |
| 542 | devinfo->bus_pub.bus->dstats.rx_errors++; | 542 | devinfo->bus_pub.bus->dstats.rx_errors++; |
| 543 | dev_kfree_skb(skb); | 543 | brcmu_pkt_buf_free_skb(skb); |
| 544 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); | 544 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); |
| 545 | return; | 545 | return; |
| 546 | } | 546 | } |
| @@ -550,13 +550,15 @@ static void brcmf_usb_rx_complete(struct urb *urb) | |||
| 550 | if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) { | 550 | if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) { |
| 551 | brcmf_dbg(ERROR, "rx protocol error\n"); | 551 | brcmf_dbg(ERROR, "rx protocol error\n"); |
| 552 | brcmu_pkt_buf_free_skb(skb); | 552 | brcmu_pkt_buf_free_skb(skb); |
| 553 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); | ||
| 553 | devinfo->bus_pub.bus->dstats.rx_errors++; | 554 | devinfo->bus_pub.bus->dstats.rx_errors++; |
| 554 | } else { | 555 | } else { |
| 555 | brcmf_rx_packet(devinfo->dev, ifidx, skb); | 556 | brcmf_rx_packet(devinfo->dev, ifidx, skb); |
| 556 | brcmf_usb_rx_refill(devinfo, req); | 557 | brcmf_usb_rx_refill(devinfo, req); |
| 557 | } | 558 | } |
| 558 | } else { | 559 | } else { |
| 559 | dev_kfree_skb(skb); | 560 | brcmu_pkt_buf_free_skb(skb); |
| 561 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); | ||
| 560 | } | 562 | } |
| 561 | return; | 563 | return; |
| 562 | 564 | ||
| @@ -581,14 +583,13 @@ static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo, | |||
| 581 | usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->rx_pipe, | 583 | usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->rx_pipe, |
| 582 | skb->data, skb_tailroom(skb), brcmf_usb_rx_complete, | 584 | skb->data, skb_tailroom(skb), brcmf_usb_rx_complete, |
| 583 | req); | 585 | req); |
| 584 | req->urb->transfer_flags |= URB_ZERO_PACKET; | ||
| 585 | req->devinfo = devinfo; | 586 | req->devinfo = devinfo; |
| 587 | brcmf_usb_enq(devinfo, &devinfo->rx_postq, req); | ||
| 586 | 588 | ||
| 587 | ret = usb_submit_urb(req->urb, GFP_ATOMIC); | 589 | ret = usb_submit_urb(req->urb, GFP_ATOMIC); |
| 588 | if (ret == 0) { | 590 | if (ret) { |
| 589 | brcmf_usb_enq(devinfo, &devinfo->rx_postq, req); | 591 | brcmf_usb_del_fromq(devinfo, req); |
| 590 | } else { | 592 | brcmu_pkt_buf_free_skb(req->skb); |
| 591 | dev_kfree_skb(req->skb); | ||
| 592 | req->skb = NULL; | 593 | req->skb = NULL; |
| 593 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); | 594 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); |
| 594 | } | 595 | } |
| @@ -683,23 +684,22 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb) | |||
| 683 | 684 | ||
| 684 | req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq); | 685 | req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq); |
| 685 | if (!req) { | 686 | if (!req) { |
| 687 | brcmu_pkt_buf_free_skb(skb); | ||
| 686 | brcmf_dbg(ERROR, "no req to send\n"); | 688 | brcmf_dbg(ERROR, "no req to send\n"); |
| 687 | return -ENOMEM; | 689 | return -ENOMEM; |
| 688 | } | 690 | } |
| 689 | if (!req->urb) { | ||
| 690 | brcmf_dbg(ERROR, "no urb for req %p\n", req); | ||
| 691 | return -ENOBUFS; | ||
| 692 | } | ||
| 693 | 691 | ||
| 694 | req->skb = skb; | 692 | req->skb = skb; |
| 695 | req->devinfo = devinfo; | 693 | req->devinfo = devinfo; |
| 696 | usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe, | 694 | usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe, |
| 697 | skb->data, skb->len, brcmf_usb_tx_complete, req); | 695 | skb->data, skb->len, brcmf_usb_tx_complete, req); |
| 698 | req->urb->transfer_flags |= URB_ZERO_PACKET; | 696 | req->urb->transfer_flags |= URB_ZERO_PACKET; |
| 697 | brcmf_usb_enq(devinfo, &devinfo->tx_postq, req); | ||
| 699 | ret = usb_submit_urb(req->urb, GFP_ATOMIC); | 698 | ret = usb_submit_urb(req->urb, GFP_ATOMIC); |
| 700 | if (!ret) { | 699 | if (ret) { |
| 701 | brcmf_usb_enq(devinfo, &devinfo->tx_postq, req); | 700 | brcmf_dbg(ERROR, "brcmf_usb_tx usb_submit_urb FAILED\n"); |
| 702 | } else { | 701 | brcmf_usb_del_fromq(devinfo, req); |
| 702 | brcmu_pkt_buf_free_skb(req->skb); | ||
| 703 | req->skb = NULL; | 703 | req->skb = NULL; |
| 704 | brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req); | 704 | brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req); |
| 705 | } | 705 | } |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 28c5fbb4af26..50b5553b6964 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | |||
| @@ -500,8 +500,10 @@ static void wl_iscan_prep(struct brcmf_scan_params_le *params_le, | |||
| 500 | params_le->active_time = cpu_to_le32(-1); | 500 | params_le->active_time = cpu_to_le32(-1); |
| 501 | params_le->passive_time = cpu_to_le32(-1); | 501 | params_le->passive_time = cpu_to_le32(-1); |
| 502 | params_le->home_time = cpu_to_le32(-1); | 502 | params_le->home_time = cpu_to_le32(-1); |
| 503 | if (ssid && ssid->SSID_len) | 503 | if (ssid && ssid->SSID_len) { |
| 504 | memcpy(¶ms_le->ssid_le, ssid, sizeof(struct brcmf_ssid)); | 504 | params_le->ssid_le.SSID_len = cpu_to_le32(ssid->SSID_len); |
| 505 | memcpy(¶ms_le->ssid_le.SSID, ssid->SSID, ssid->SSID_len); | ||
| 506 | } | ||
| 505 | } | 507 | } |
| 506 | 508 | ||
| 507 | static s32 | 509 | static s32 |
| @@ -1876,16 +1878,17 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, | |||
| 1876 | } | 1878 | } |
| 1877 | 1879 | ||
| 1878 | if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) { | 1880 | if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) { |
| 1879 | scb_val.val = cpu_to_le32(0); | 1881 | memset(&scb_val, 0, sizeof(scb_val)); |
| 1880 | err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val, | 1882 | err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val, |
| 1881 | sizeof(struct brcmf_scb_val_le)); | 1883 | sizeof(struct brcmf_scb_val_le)); |
| 1882 | if (err) | 1884 | if (err) { |
| 1883 | WL_ERR("Could not get rssi (%d)\n", err); | 1885 | WL_ERR("Could not get rssi (%d)\n", err); |
| 1884 | 1886 | } else { | |
| 1885 | rssi = le32_to_cpu(scb_val.val); | 1887 | rssi = le32_to_cpu(scb_val.val); |
| 1886 | sinfo->filled |= STATION_INFO_SIGNAL; | 1888 | sinfo->filled |= STATION_INFO_SIGNAL; |
| 1887 | sinfo->signal = rssi; | 1889 | sinfo->signal = rssi; |
| 1888 | WL_CONN("RSSI %d dBm\n", rssi); | 1890 | WL_CONN("RSSI %d dBm\n", rssi); |
| 1891 | } | ||
| 1889 | } | 1892 | } |
| 1890 | 1893 | ||
| 1891 | done: | 1894 | done: |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index 7ed7d7577024..64a48f06d68b 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c | |||
| @@ -77,7 +77,7 @@ | |||
| 77 | NL80211_RRF_NO_IBSS) | 77 | NL80211_RRF_NO_IBSS) |
| 78 | 78 | ||
| 79 | static const struct ieee80211_regdomain brcms_regdom_x2 = { | 79 | static const struct ieee80211_regdomain brcms_regdom_x2 = { |
| 80 | .n_reg_rules = 7, | 80 | .n_reg_rules = 6, |
| 81 | .alpha2 = "X2", | 81 | .alpha2 = "X2", |
| 82 | .reg_rules = { | 82 | .reg_rules = { |
| 83 | BRCM_2GHZ_2412_2462, | 83 | BRCM_2GHZ_2412_2462, |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index e316ca4632b1..063ecaff5b56 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
| @@ -1439,6 +1439,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) | |||
| 1439 | return err; | 1439 | return err; |
| 1440 | 1440 | ||
| 1441 | err_free_irq: | 1441 | err_free_irq: |
| 1442 | trans_pcie->irq_requested = false; | ||
| 1442 | free_irq(trans_pcie->irq, trans); | 1443 | free_irq(trans_pcie->irq, trans); |
| 1443 | error: | 1444 | error: |
| 1444 | iwl_free_isr_ict(trans); | 1445 | iwl_free_isr_ict(trans); |
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index e970897f6ab5..4cb234349fbf 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c | |||
| @@ -1326,6 +1326,11 @@ static int if_sdio_suspend(struct device *dev) | |||
| 1326 | 1326 | ||
| 1327 | mmc_pm_flag_t flags = sdio_get_host_pm_caps(func); | 1327 | mmc_pm_flag_t flags = sdio_get_host_pm_caps(func); |
| 1328 | 1328 | ||
| 1329 | /* If we're powered off anyway, just let the mmc layer remove the | ||
| 1330 | * card. */ | ||
| 1331 | if (!lbs_iface_active(card->priv)) | ||
| 1332 | return -ENOSYS; | ||
| 1333 | |||
| 1329 | dev_info(dev, "%s: suspend: PM flags = 0x%x\n", | 1334 | dev_info(dev, "%s: suspend: PM flags = 0x%x\n", |
| 1330 | sdio_func_id(func), flags); | 1335 | sdio_func_id(func), flags); |
| 1331 | 1336 | ||
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index c68adec3cc8b..565527aee0ea 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c | |||
| @@ -170,7 +170,20 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, | |||
| 170 | cmd_code = le16_to_cpu(host_cmd->command); | 170 | cmd_code = le16_to_cpu(host_cmd->command); |
| 171 | cmd_size = le16_to_cpu(host_cmd->size); | 171 | cmd_size = le16_to_cpu(host_cmd->size); |
| 172 | 172 | ||
| 173 | skb_trim(cmd_node->cmd_skb, cmd_size); | 173 | /* Adjust skb length */ |
| 174 | if (cmd_node->cmd_skb->len > cmd_size) | ||
| 175 | /* | ||
| 176 | * cmd_size is less than sizeof(struct host_cmd_ds_command). | ||
| 177 | * Trim off the unused portion. | ||
| 178 | */ | ||
| 179 | skb_trim(cmd_node->cmd_skb, cmd_size); | ||
| 180 | else if (cmd_node->cmd_skb->len < cmd_size) | ||
| 181 | /* | ||
| 182 | * cmd_size is larger than sizeof(struct host_cmd_ds_command) | ||
| 183 | * because we have appended custom IE TLV. Increase skb length | ||
| 184 | * accordingly. | ||
| 185 | */ | ||
| 186 | skb_put(cmd_node->cmd_skb, cmd_size - cmd_node->cmd_skb->len); | ||
| 174 | 187 | ||
| 175 | do_gettimeofday(&tstamp); | 188 | do_gettimeofday(&tstamp); |
| 176 | dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d," | 189 | dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d," |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 8b9dbd76a252..64328af496f5 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
| @@ -1611,6 +1611,7 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
| 1611 | static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) | 1611 | static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) |
| 1612 | { | 1612 | { |
| 1613 | int retval; | 1613 | int retval; |
| 1614 | u32 reg; | ||
| 1614 | 1615 | ||
| 1615 | /* | 1616 | /* |
| 1616 | * Allocate eeprom data. | 1617 | * Allocate eeprom data. |
| @@ -1624,6 +1625,14 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
| 1624 | return retval; | 1625 | return retval; |
| 1625 | 1626 | ||
| 1626 | /* | 1627 | /* |
| 1628 | * Enable rfkill polling by setting GPIO direction of the | ||
| 1629 | * rfkill switch GPIO pin correctly. | ||
| 1630 | */ | ||
| 1631 | rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); | ||
| 1632 | rt2x00_set_field32(®, GPIOCSR_BIT8, 1); | ||
| 1633 | rt2x00pci_register_write(rt2x00dev, GPIOCSR, reg); | ||
| 1634 | |||
| 1635 | /* | ||
| 1627 | * Initialize hw specifications. | 1636 | * Initialize hw specifications. |
| 1628 | */ | 1637 | */ |
| 1629 | retval = rt2400pci_probe_hw_mode(rt2x00dev); | 1638 | retval = rt2400pci_probe_hw_mode(rt2x00dev); |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index d3a4a68cc439..7564ae992b73 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h | |||
| @@ -670,6 +670,7 @@ | |||
| 670 | #define GPIOCSR_BIT5 FIELD32(0x00000020) | 670 | #define GPIOCSR_BIT5 FIELD32(0x00000020) |
| 671 | #define GPIOCSR_BIT6 FIELD32(0x00000040) | 671 | #define GPIOCSR_BIT6 FIELD32(0x00000040) |
| 672 | #define GPIOCSR_BIT7 FIELD32(0x00000080) | 672 | #define GPIOCSR_BIT7 FIELD32(0x00000080) |
| 673 | #define GPIOCSR_BIT8 FIELD32(0x00000100) | ||
| 673 | 674 | ||
| 674 | /* | 675 | /* |
| 675 | * BBPPCSR: BBP Pin control register. | 676 | * BBPPCSR: BBP Pin control register. |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index d2cf8a4bc8b5..3de0406735f6 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
| @@ -1929,6 +1929,7 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
| 1929 | static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) | 1929 | static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) |
| 1930 | { | 1930 | { |
| 1931 | int retval; | 1931 | int retval; |
| 1932 | u32 reg; | ||
| 1932 | 1933 | ||
| 1933 | /* | 1934 | /* |
| 1934 | * Allocate eeprom data. | 1935 | * Allocate eeprom data. |
| @@ -1942,6 +1943,14 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
| 1942 | return retval; | 1943 | return retval; |
| 1943 | 1944 | ||
| 1944 | /* | 1945 | /* |
| 1946 | * Enable rfkill polling by setting GPIO direction of the | ||
| 1947 | * rfkill switch GPIO pin correctly. | ||
| 1948 | */ | ||
| 1949 | rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); | ||
| 1950 | rt2x00_set_field32(®, GPIOCSR_DIR0, 1); | ||
| 1951 | rt2x00pci_register_write(rt2x00dev, GPIOCSR, reg); | ||
| 1952 | |||
| 1953 | /* | ||
| 1945 | * Initialize hw specifications. | 1954 | * Initialize hw specifications. |
| 1946 | */ | 1955 | */ |
| 1947 | retval = rt2500pci_probe_hw_mode(rt2x00dev); | 1956 | retval = rt2500pci_probe_hw_mode(rt2x00dev); |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 3aae36bb0a9e..89fee311d8fd 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
| @@ -283,7 +283,7 @@ static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) | |||
| 283 | u16 reg; | 283 | u16 reg; |
| 284 | 284 | ||
| 285 | rt2500usb_register_read(rt2x00dev, MAC_CSR19, ®); | 285 | rt2500usb_register_read(rt2x00dev, MAC_CSR19, ®); |
| 286 | return rt2x00_get_field32(reg, MAC_CSR19_BIT7); | 286 | return rt2x00_get_field16(reg, MAC_CSR19_BIT7); |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | #ifdef CONFIG_RT2X00_LIB_LEDS | 289 | #ifdef CONFIG_RT2X00_LIB_LEDS |
| @@ -1768,6 +1768,7 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
| 1768 | static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) | 1768 | static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) |
| 1769 | { | 1769 | { |
| 1770 | int retval; | 1770 | int retval; |
| 1771 | u16 reg; | ||
| 1771 | 1772 | ||
| 1772 | /* | 1773 | /* |
| 1773 | * Allocate eeprom data. | 1774 | * Allocate eeprom data. |
| @@ -1781,6 +1782,14 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
| 1781 | return retval; | 1782 | return retval; |
| 1782 | 1783 | ||
| 1783 | /* | 1784 | /* |
| 1785 | * Enable rfkill polling by setting GPIO direction of the | ||
| 1786 | * rfkill switch GPIO pin correctly. | ||
| 1787 | */ | ||
| 1788 | rt2500usb_register_read(rt2x00dev, MAC_CSR19, ®); | ||
| 1789 | rt2x00_set_field16(®, MAC_CSR19_BIT8, 0); | ||
| 1790 | rt2500usb_register_write(rt2x00dev, MAC_CSR19, reg); | ||
| 1791 | |||
| 1792 | /* | ||
| 1784 | * Initialize hw specifications. | 1793 | * Initialize hw specifications. |
| 1785 | */ | 1794 | */ |
| 1786 | retval = rt2500usb_probe_hw_mode(rt2x00dev); | 1795 | retval = rt2500usb_probe_hw_mode(rt2x00dev); |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index b493306a7eed..196bd5103e4f 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h | |||
| @@ -189,14 +189,15 @@ | |||
| 189 | * MAC_CSR19: GPIO control register. | 189 | * MAC_CSR19: GPIO control register. |
| 190 | */ | 190 | */ |
| 191 | #define MAC_CSR19 0x0426 | 191 | #define MAC_CSR19 0x0426 |
| 192 | #define MAC_CSR19_BIT0 FIELD32(0x0001) | 192 | #define MAC_CSR19_BIT0 FIELD16(0x0001) |
| 193 | #define MAC_CSR19_BIT1 FIELD32(0x0002) | 193 | #define MAC_CSR19_BIT1 FIELD16(0x0002) |
| 194 | #define MAC_CSR19_BIT2 FIELD32(0x0004) | 194 | #define MAC_CSR19_BIT2 FIELD16(0x0004) |
| 195 | #define MAC_CSR19_BIT3 FIELD32(0x0008) | 195 | #define MAC_CSR19_BIT3 FIELD16(0x0008) |
| 196 | #define MAC_CSR19_BIT4 FIELD32(0x0010) | 196 | #define MAC_CSR19_BIT4 FIELD16(0x0010) |
| 197 | #define MAC_CSR19_BIT5 FIELD32(0x0020) | 197 | #define MAC_CSR19_BIT5 FIELD16(0x0020) |
| 198 | #define MAC_CSR19_BIT6 FIELD32(0x0040) | 198 | #define MAC_CSR19_BIT6 FIELD16(0x0040) |
| 199 | #define MAC_CSR19_BIT7 FIELD32(0x0080) | 199 | #define MAC_CSR19_BIT7 FIELD16(0x0080) |
| 200 | #define MAC_CSR19_BIT8 FIELD16(0x0100) | ||
| 200 | 201 | ||
| 201 | /* | 202 | /* |
| 202 | * MAC_CSR20: LED control register. | 203 | * MAC_CSR20: LED control register. |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index cb8c2aca54e4..b93516d832fb 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
| @@ -4089,6 +4089,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) | |||
| 4089 | rt2800_register_write(rt2x00dev, LDO_CFG0, reg); | 4089 | rt2800_register_write(rt2x00dev, LDO_CFG0, reg); |
| 4090 | msleep(1); | 4090 | msleep(1); |
| 4091 | rt2800_register_read(rt2x00dev, LDO_CFG0, ®); | 4091 | rt2800_register_read(rt2x00dev, LDO_CFG0, ®); |
| 4092 | rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 0); | ||
| 4092 | rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); | 4093 | rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); |
| 4093 | rt2800_register_write(rt2x00dev, LDO_CFG0, reg); | 4094 | rt2800_register_write(rt2x00dev, LDO_CFG0, reg); |
| 4094 | } | 4095 | } |
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 98aa426a3564..4765bbd654cd 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c | |||
| @@ -983,6 +983,7 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) | |||
| 983 | static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) | 983 | static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) |
| 984 | { | 984 | { |
| 985 | int retval; | 985 | int retval; |
| 986 | u32 reg; | ||
| 986 | 987 | ||
| 987 | /* | 988 | /* |
| 988 | * Allocate eeprom data. | 989 | * Allocate eeprom data. |
| @@ -996,6 +997,14 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
| 996 | return retval; | 997 | return retval; |
| 997 | 998 | ||
| 998 | /* | 999 | /* |
| 1000 | * Enable rfkill polling by setting GPIO direction of the | ||
| 1001 | * rfkill switch GPIO pin correctly. | ||
| 1002 | */ | ||
| 1003 | rt2x00pci_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); | ||
| 1004 | rt2x00_set_field32(®, GPIO_CTRL_CFG_GPIOD_BIT2, 1); | ||
| 1005 | rt2x00pci_register_write(rt2x00dev, GPIO_CTRL_CFG, reg); | ||
| 1006 | |||
| 1007 | /* | ||
| 999 | * Initialize hw specifications. | 1008 | * Initialize hw specifications. |
| 1000 | */ | 1009 | */ |
| 1001 | retval = rt2800_probe_hw_mode(rt2x00dev); | 1010 | retval = rt2800_probe_hw_mode(rt2x00dev); |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 6cf336595e25..6b4226b71618 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
| @@ -667,8 +667,16 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, | |||
| 667 | skb_pull(entry->skb, RXINFO_DESC_SIZE); | 667 | skb_pull(entry->skb, RXINFO_DESC_SIZE); |
| 668 | 668 | ||
| 669 | /* | 669 | /* |
| 670 | * FIXME: we need to check for rx_pkt_len validity | 670 | * Check for rx_pkt_len validity. Return if invalid, leaving |
| 671 | * rxdesc->size zeroed out by the upper level. | ||
| 671 | */ | 672 | */ |
| 673 | if (unlikely(rx_pkt_len == 0 || | ||
| 674 | rx_pkt_len > entry->queue->data_size)) { | ||
| 675 | ERROR(entry->queue->rt2x00dev, | ||
| 676 | "Bad frame size %d, forcing to 0\n", rx_pkt_len); | ||
| 677 | return; | ||
| 678 | } | ||
| 679 | |||
| 672 | rxd = (__le32 *)(entry->skb->data + rx_pkt_len); | 680 | rxd = (__le32 *)(entry->skb->data + rx_pkt_len); |
| 673 | 681 | ||
| 674 | /* | 682 | /* |
| @@ -736,6 +744,7 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) | |||
| 736 | static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) | 744 | static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) |
| 737 | { | 745 | { |
| 738 | int retval; | 746 | int retval; |
| 747 | u32 reg; | ||
| 739 | 748 | ||
| 740 | /* | 749 | /* |
| 741 | * Allocate eeprom data. | 750 | * Allocate eeprom data. |
| @@ -749,6 +758,14 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
| 749 | return retval; | 758 | return retval; |
| 750 | 759 | ||
| 751 | /* | 760 | /* |
| 761 | * Enable rfkill polling by setting GPIO direction of the | ||
| 762 | * rfkill switch GPIO pin correctly. | ||
| 763 | */ | ||
| 764 | rt2x00usb_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); | ||
| 765 | rt2x00_set_field32(®, GPIO_CTRL_CFG_GPIOD_BIT2, 1); | ||
| 766 | rt2x00usb_register_write(rt2x00dev, GPIO_CTRL_CFG, reg); | ||
| 767 | |||
| 768 | /* | ||
| 752 | * Initialize hw specifications. | 769 | * Initialize hw specifications. |
| 753 | */ | 770 | */ |
| 754 | retval = rt2800_probe_hw_mode(rt2x00dev); | 771 | retval = rt2800_probe_hw_mode(rt2x00dev); |
| @@ -1157,6 +1174,8 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
| 1157 | { USB_DEVICE(0x1690, 0x0744) }, | 1174 | { USB_DEVICE(0x1690, 0x0744) }, |
| 1158 | { USB_DEVICE(0x1690, 0x0761) }, | 1175 | { USB_DEVICE(0x1690, 0x0761) }, |
| 1159 | { USB_DEVICE(0x1690, 0x0764) }, | 1176 | { USB_DEVICE(0x1690, 0x0764) }, |
| 1177 | /* ASUS */ | ||
| 1178 | { USB_DEVICE(0x0b05, 0x179d) }, | ||
| 1160 | /* Cisco */ | 1179 | /* Cisco */ |
| 1161 | { USB_DEVICE(0x167b, 0x4001) }, | 1180 | { USB_DEVICE(0x167b, 0x4001) }, |
| 1162 | /* EnGenius */ | 1181 | /* EnGenius */ |
| @@ -1222,7 +1241,6 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
| 1222 | { USB_DEVICE(0x0b05, 0x1760) }, | 1241 | { USB_DEVICE(0x0b05, 0x1760) }, |
| 1223 | { USB_DEVICE(0x0b05, 0x1761) }, | 1242 | { USB_DEVICE(0x0b05, 0x1761) }, |
| 1224 | { USB_DEVICE(0x0b05, 0x1790) }, | 1243 | { USB_DEVICE(0x0b05, 0x1790) }, |
| 1225 | { USB_DEVICE(0x0b05, 0x179d) }, | ||
| 1226 | /* AzureWave */ | 1244 | /* AzureWave */ |
| 1227 | { USB_DEVICE(0x13d3, 0x3262) }, | 1245 | { USB_DEVICE(0x13d3, 0x3262) }, |
| 1228 | { USB_DEVICE(0x13d3, 0x3284) }, | 1246 | { USB_DEVICE(0x13d3, 0x3284) }, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index a6b88bd4a1a5..3f07e36f462b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
| @@ -629,7 +629,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp) | |||
| 629 | */ | 629 | */ |
| 630 | if (unlikely(rxdesc.size == 0 || | 630 | if (unlikely(rxdesc.size == 0 || |
| 631 | rxdesc.size > entry->queue->data_size)) { | 631 | rxdesc.size > entry->queue->data_size)) { |
| 632 | WARNING(rt2x00dev, "Wrong frame size %d max %d.\n", | 632 | ERROR(rt2x00dev, "Wrong frame size %d max %d.\n", |
| 633 | rxdesc.size, entry->queue->data_size); | 633 | rxdesc.size, entry->queue->data_size); |
| 634 | dev_kfree_skb(entry->skb); | 634 | dev_kfree_skb(entry->skb); |
| 635 | goto renew_skb; | 635 | goto renew_skb; |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 3f7bc5cadf9a..b8ec96163922 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
| @@ -2832,6 +2832,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
| 2832 | static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) | 2832 | static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) |
| 2833 | { | 2833 | { |
| 2834 | int retval; | 2834 | int retval; |
| 2835 | u32 reg; | ||
| 2835 | 2836 | ||
| 2836 | /* | 2837 | /* |
| 2837 | * Disable power saving. | 2838 | * Disable power saving. |
| @@ -2850,6 +2851,14 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
| 2850 | return retval; | 2851 | return retval; |
| 2851 | 2852 | ||
| 2852 | /* | 2853 | /* |
| 2854 | * Enable rfkill polling by setting GPIO direction of the | ||
| 2855 | * rfkill switch GPIO pin correctly. | ||
| 2856 | */ | ||
| 2857 | rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®); | ||
| 2858 | rt2x00_set_field32(®, MAC_CSR13_BIT13, 1); | ||
| 2859 | rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg); | ||
| 2860 | |||
| 2861 | /* | ||
| 2853 | * Initialize hw specifications. | 2862 | * Initialize hw specifications. |
| 2854 | */ | 2863 | */ |
| 2855 | retval = rt61pci_probe_hw_mode(rt2x00dev); | 2864 | retval = rt61pci_probe_hw_mode(rt2x00dev); |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index e3cd6db76b0e..8f3da5a56766 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h | |||
| @@ -372,6 +372,7 @@ struct hw_pairwise_ta_entry { | |||
| 372 | #define MAC_CSR13_BIT10 FIELD32(0x00000400) | 372 | #define MAC_CSR13_BIT10 FIELD32(0x00000400) |
| 373 | #define MAC_CSR13_BIT11 FIELD32(0x00000800) | 373 | #define MAC_CSR13_BIT11 FIELD32(0x00000800) |
| 374 | #define MAC_CSR13_BIT12 FIELD32(0x00001000) | 374 | #define MAC_CSR13_BIT12 FIELD32(0x00001000) |
| 375 | #define MAC_CSR13_BIT13 FIELD32(0x00002000) | ||
| 375 | 376 | ||
| 376 | /* | 377 | /* |
| 377 | * MAC_CSR14: LED control register. | 378 | * MAC_CSR14: LED control register. |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ba6e434b859d..248436c13ce0 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
| @@ -2177,6 +2177,7 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
| 2177 | static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) | 2177 | static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) |
| 2178 | { | 2178 | { |
| 2179 | int retval; | 2179 | int retval; |
| 2180 | u32 reg; | ||
| 2180 | 2181 | ||
| 2181 | /* | 2182 | /* |
| 2182 | * Allocate eeprom data. | 2183 | * Allocate eeprom data. |
| @@ -2190,6 +2191,14 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
| 2190 | return retval; | 2191 | return retval; |
| 2191 | 2192 | ||
| 2192 | /* | 2193 | /* |
| 2194 | * Enable rfkill polling by setting GPIO direction of the | ||
| 2195 | * rfkill switch GPIO pin correctly. | ||
| 2196 | */ | ||
| 2197 | rt2x00usb_register_read(rt2x00dev, MAC_CSR13, ®); | ||
| 2198 | rt2x00_set_field32(®, MAC_CSR13_BIT15, 0); | ||
| 2199 | rt2x00usb_register_write(rt2x00dev, MAC_CSR13, reg); | ||
| 2200 | |||
| 2201 | /* | ||
| 2193 | * Initialize hw specifications. | 2202 | * Initialize hw specifications. |
| 2194 | */ | 2203 | */ |
| 2195 | retval = rt73usb_probe_hw_mode(rt2x00dev); | 2204 | retval = rt73usb_probe_hw_mode(rt2x00dev); |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 9f6b470414d3..df1cc116b83b 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h | |||
| @@ -282,6 +282,9 @@ struct hw_pairwise_ta_entry { | |||
| 282 | #define MAC_CSR13_BIT10 FIELD32(0x00000400) | 282 | #define MAC_CSR13_BIT10 FIELD32(0x00000400) |
| 283 | #define MAC_CSR13_BIT11 FIELD32(0x00000800) | 283 | #define MAC_CSR13_BIT11 FIELD32(0x00000800) |
| 284 | #define MAC_CSR13_BIT12 FIELD32(0x00001000) | 284 | #define MAC_CSR13_BIT12 FIELD32(0x00001000) |
| 285 | #define MAC_CSR13_BIT13 FIELD32(0x00002000) | ||
| 286 | #define MAC_CSR13_BIT14 FIELD32(0x00004000) | ||
| 287 | #define MAC_CSR13_BIT15 FIELD32(0x00008000) | ||
| 285 | 288 | ||
| 286 | /* | 289 | /* |
| 287 | * MAC_CSR14: LED control register. | 290 | * MAC_CSR14: LED control register. |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index 44febfde9493..8a7b864faca3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c | |||
| @@ -315,7 +315,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, | |||
| 315 | u16 box_reg = 0, box_extreg = 0; | 315 | u16 box_reg = 0, box_extreg = 0; |
| 316 | u8 u1b_tmp; | 316 | u8 u1b_tmp; |
| 317 | bool isfw_read = false; | 317 | bool isfw_read = false; |
| 318 | bool bwrite_sucess = false; | 318 | bool bwrite_success = false; |
| 319 | u8 wait_h2c_limmit = 100; | 319 | u8 wait_h2c_limmit = 100; |
| 320 | u8 wait_writeh2c_limmit = 100; | 320 | u8 wait_writeh2c_limmit = 100; |
| 321 | u8 boxcontent[4], boxextcontent[2]; | 321 | u8 boxcontent[4], boxextcontent[2]; |
| @@ -354,7 +354,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, | |||
| 354 | } | 354 | } |
| 355 | } | 355 | } |
| 356 | 356 | ||
| 357 | while (!bwrite_sucess) { | 357 | while (!bwrite_success) { |
| 358 | wait_writeh2c_limmit--; | 358 | wait_writeh2c_limmit--; |
| 359 | if (wait_writeh2c_limmit == 0) { | 359 | if (wait_writeh2c_limmit == 0) { |
| 360 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | 360 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, |
| @@ -491,7 +491,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, | |||
| 491 | break; | 491 | break; |
| 492 | } | 492 | } |
| 493 | 493 | ||
| 494 | bwrite_sucess = true; | 494 | bwrite_success = true; |
| 495 | 495 | ||
| 496 | rtlhal->last_hmeboxnum = boxnum + 1; | 496 | rtlhal->last_hmeboxnum = boxnum + 1; |
| 497 | if (rtlhal->last_hmeboxnum == 4) | 497 | if (rtlhal->last_hmeboxnum == 4) |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h index 04c3aef8a4f6..2925094b2d91 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h | |||
| @@ -117,6 +117,7 @@ | |||
| 117 | 117 | ||
| 118 | #define CHIP_VER_B BIT(4) | 118 | #define CHIP_VER_B BIT(4) |
| 119 | #define CHIP_92C_BITMASK BIT(0) | 119 | #define CHIP_92C_BITMASK BIT(0) |
| 120 | #define CHIP_UNKNOWN BIT(7) | ||
| 120 | #define CHIP_92C_1T2R 0x03 | 121 | #define CHIP_92C_1T2R 0x03 |
| 121 | #define CHIP_92C 0x01 | 122 | #define CHIP_92C 0x01 |
| 122 | #define CHIP_88C 0x00 | 123 | #define CHIP_88C 0x00 |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index bd0da7ef290b..dd4bb0950a57 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | |||
| @@ -994,8 +994,16 @@ static enum version_8192c _rtl92ce_read_chip_version(struct ieee80211_hw *hw) | |||
| 994 | version = (value32 & TYPE_ID) ? VERSION_A_CHIP_92C : | 994 | version = (value32 & TYPE_ID) ? VERSION_A_CHIP_92C : |
| 995 | VERSION_A_CHIP_88C; | 995 | VERSION_A_CHIP_88C; |
| 996 | } else { | 996 | } else { |
| 997 | version = (value32 & TYPE_ID) ? VERSION_B_CHIP_92C : | 997 | version = (enum version_8192c) (CHIP_VER_B | |
| 998 | VERSION_B_CHIP_88C; | 998 | ((value32 & TYPE_ID) ? CHIP_92C_BITMASK : 0) | |
| 999 | ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0)); | ||
| 1000 | if ((!IS_CHIP_VENDOR_UMC(version)) && (value32 & | ||
| 1001 | CHIP_VER_RTL_MASK)) { | ||
| 1002 | version = (enum version_8192c)(version | | ||
| 1003 | ((((value32 & CHIP_VER_RTL_MASK) == BIT(12)) | ||
| 1004 | ? CHIP_VENDOR_UMC_B_CUT : CHIP_UNKNOWN) | | ||
| 1005 | CHIP_VENDOR_UMC)); | ||
| 1006 | } | ||
| 999 | } | 1007 | } |
| 1000 | 1008 | ||
| 1001 | switch (version) { | 1009 | switch (version) { |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index 3aa927f8b9b9..7d8f96405f42 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c | |||
| @@ -162,10 +162,12 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) | |||
| 162 | 162 | ||
| 163 | /* request fw */ | 163 | /* request fw */ |
| 164 | if (IS_VENDOR_UMC_A_CUT(rtlhal->version) && | 164 | if (IS_VENDOR_UMC_A_CUT(rtlhal->version) && |
| 165 | !IS_92C_SERIAL(rtlhal->version)) | 165 | !IS_92C_SERIAL(rtlhal->version)) { |
| 166 | rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU.bin"; | 166 | rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU.bin"; |
| 167 | else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) | 167 | } else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) { |
| 168 | rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU_B.bin"; | 168 | rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU_B.bin"; |
| 169 | pr_info("****** This B_CUT device may not work with kernels 3.6 and earlier\n"); | ||
| 170 | } | ||
| 169 | 171 | ||
| 170 | rtlpriv->max_fw_size = 0x4000; | 172 | rtlpriv->max_fw_size = 0x4000; |
| 171 | pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); | 173 | pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c index 895ae6c1f354..eb22dccc418b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c | |||
| @@ -365,7 +365,7 @@ static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw, | |||
| 365 | u8 u1b_tmp; | 365 | u8 u1b_tmp; |
| 366 | bool isfw_read = false; | 366 | bool isfw_read = false; |
| 367 | u8 buf_index = 0; | 367 | u8 buf_index = 0; |
| 368 | bool bwrite_sucess = false; | 368 | bool bwrite_success = false; |
| 369 | u8 wait_h2c_limmit = 100; | 369 | u8 wait_h2c_limmit = 100; |
| 370 | u8 wait_writeh2c_limmit = 100; | 370 | u8 wait_writeh2c_limmit = 100; |
| 371 | u8 boxcontent[4], boxextcontent[2]; | 371 | u8 boxcontent[4], boxextcontent[2]; |
| @@ -408,7 +408,7 @@ static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw, | |||
| 408 | break; | 408 | break; |
| 409 | } | 409 | } |
| 410 | } | 410 | } |
| 411 | while (!bwrite_sucess) { | 411 | while (!bwrite_success) { |
| 412 | wait_writeh2c_limmit--; | 412 | wait_writeh2c_limmit--; |
| 413 | if (wait_writeh2c_limmit == 0) { | 413 | if (wait_writeh2c_limmit == 0) { |
| 414 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | 414 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, |
| @@ -515,7 +515,7 @@ static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw, | |||
| 515 | "switch case not processed\n"); | 515 | "switch case not processed\n"); |
| 516 | break; | 516 | break; |
| 517 | } | 517 | } |
| 518 | bwrite_sucess = true; | 518 | bwrite_success = true; |
| 519 | rtlhal->last_hmeboxnum = boxnum + 1; | 519 | rtlhal->last_hmeboxnum = boxnum + 1; |
| 520 | if (rtlhal->last_hmeboxnum == 4) | 520 | if (rtlhal->last_hmeboxnum == 4) |
| 521 | rtlhal->last_hmeboxnum = 0; | 521 | rtlhal->last_hmeboxnum = 0; |
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index b8ef8ddcc292..8aa73fac6ad4 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c | |||
| @@ -451,14 +451,9 @@ static void wq_sync_buffer(struct work_struct *work) | |||
| 451 | { | 451 | { |
| 452 | struct oprofile_cpu_buffer *b = | 452 | struct oprofile_cpu_buffer *b = |
| 453 | container_of(work, struct oprofile_cpu_buffer, work.work); | 453 | container_of(work, struct oprofile_cpu_buffer, work.work); |
| 454 | if (b->cpu != smp_processor_id()) { | 454 | if (b->cpu != smp_processor_id() && !cpu_online(b->cpu)) { |
| 455 | printk(KERN_DEBUG "WQ on CPU%d, prefer CPU%d\n", | 455 | cancel_delayed_work(&b->work); |
| 456 | smp_processor_id(), b->cpu); | 456 | return; |
| 457 | |||
| 458 | if (!cpu_online(b->cpu)) { | ||
| 459 | cancel_delayed_work(&b->work); | ||
| 460 | return; | ||
| 461 | } | ||
| 462 | } | 457 | } |
| 463 | sync_buffer(b->cpu); | 458 | sync_buffer(b->cpu); |
| 464 | 459 | ||
diff --git a/drivers/pci/.gitignore b/drivers/pci/.gitignore deleted file mode 100644 index f297ca8d313e..000000000000 --- a/drivers/pci/.gitignore +++ /dev/null | |||
| @@ -1,4 +0,0 @@ | |||
| 1 | classlist.h | ||
| 2 | devlist.h | ||
| 3 | gen-devlist | ||
| 4 | |||
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 3782e1cd3697..934d861a3235 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
| @@ -2196,10 +2196,8 @@ static int __init acer_wmi_init(void) | |||
| 2196 | interface->capability &= ~ACER_CAP_BRIGHTNESS; | 2196 | interface->capability &= ~ACER_CAP_BRIGHTNESS; |
| 2197 | pr_info("Brightness must be controlled by acpi video driver\n"); | 2197 | pr_info("Brightness must be controlled by acpi video driver\n"); |
| 2198 | } else { | 2198 | } else { |
| 2199 | #ifdef CONFIG_ACPI_VIDEO | ||
| 2200 | pr_info("Disabling ACPI video driver\n"); | 2199 | pr_info("Disabling ACPI video driver\n"); |
| 2201 | acpi_video_unregister(); | 2200 | acpi_video_unregister(); |
| 2202 | #endif | ||
| 2203 | } | 2201 | } |
| 2204 | 2202 | ||
| 2205 | if (wmi_has_guid(WMID_GUID3)) { | 2203 | if (wmi_has_guid(WMID_GUID3)) { |
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index dfb1a92ce949..db8f63841b42 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c | |||
| @@ -101,7 +101,7 @@ static void gmux_pio_write32(struct apple_gmux_data *gmux_data, int port, | |||
| 101 | 101 | ||
| 102 | for (i = 0; i < 4; i++) { | 102 | for (i = 0; i < 4; i++) { |
| 103 | tmpval = (val >> (i * 8)) & 0xff; | 103 | tmpval = (val >> (i * 8)) & 0xff; |
| 104 | outb(tmpval, port + i); | 104 | outb(tmpval, gmux_data->iostart + port + i); |
| 105 | } | 105 | } |
| 106 | } | 106 | } |
| 107 | 107 | ||
| @@ -142,8 +142,9 @@ static u8 gmux_index_read8(struct apple_gmux_data *gmux_data, int port) | |||
| 142 | u8 val; | 142 | u8 val; |
| 143 | 143 | ||
| 144 | mutex_lock(&gmux_data->index_lock); | 144 | mutex_lock(&gmux_data->index_lock); |
| 145 | outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ); | ||
| 146 | gmux_index_wait_ready(gmux_data); | 145 | gmux_index_wait_ready(gmux_data); |
| 146 | outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ); | ||
| 147 | gmux_index_wait_complete(gmux_data); | ||
| 147 | val = inb(gmux_data->iostart + GMUX_PORT_VALUE); | 148 | val = inb(gmux_data->iostart + GMUX_PORT_VALUE); |
| 148 | mutex_unlock(&gmux_data->index_lock); | 149 | mutex_unlock(&gmux_data->index_lock); |
| 149 | 150 | ||
| @@ -166,8 +167,9 @@ static u32 gmux_index_read32(struct apple_gmux_data *gmux_data, int port) | |||
| 166 | u32 val; | 167 | u32 val; |
| 167 | 168 | ||
| 168 | mutex_lock(&gmux_data->index_lock); | 169 | mutex_lock(&gmux_data->index_lock); |
| 169 | outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ); | ||
| 170 | gmux_index_wait_ready(gmux_data); | 170 | gmux_index_wait_ready(gmux_data); |
| 171 | outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ); | ||
| 172 | gmux_index_wait_complete(gmux_data); | ||
| 171 | val = inl(gmux_data->iostart + GMUX_PORT_VALUE); | 173 | val = inl(gmux_data->iostart + GMUX_PORT_VALUE); |
| 172 | mutex_unlock(&gmux_data->index_lock); | 174 | mutex_unlock(&gmux_data->index_lock); |
| 173 | 175 | ||
| @@ -461,18 +463,22 @@ static int __devinit gmux_probe(struct pnp_dev *pnp, | |||
| 461 | ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE); | 463 | ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE); |
| 462 | if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) { | 464 | if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) { |
| 463 | if (gmux_is_indexed(gmux_data)) { | 465 | if (gmux_is_indexed(gmux_data)) { |
| 466 | u32 version; | ||
| 464 | mutex_init(&gmux_data->index_lock); | 467 | mutex_init(&gmux_data->index_lock); |
| 465 | gmux_data->indexed = true; | 468 | gmux_data->indexed = true; |
| 469 | version = gmux_read32(gmux_data, | ||
| 470 | GMUX_PORT_VERSION_MAJOR); | ||
| 471 | ver_major = (version >> 24) & 0xff; | ||
| 472 | ver_minor = (version >> 16) & 0xff; | ||
| 473 | ver_release = (version >> 8) & 0xff; | ||
| 466 | } else { | 474 | } else { |
| 467 | pr_info("gmux device not present\n"); | 475 | pr_info("gmux device not present\n"); |
| 468 | ret = -ENODEV; | 476 | ret = -ENODEV; |
| 469 | goto err_release; | 477 | goto err_release; |
| 470 | } | 478 | } |
| 471 | pr_info("Found indexed gmux\n"); | ||
| 472 | } else { | ||
| 473 | pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor, | ||
| 474 | ver_release); | ||
| 475 | } | 479 | } |
| 480 | pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor, | ||
| 481 | ver_release, (gmux_data->indexed ? "indexed" : "classic")); | ||
| 476 | 482 | ||
| 477 | memset(&props, 0, sizeof(props)); | 483 | memset(&props, 0, sizeof(props)); |
| 478 | props.type = BACKLIGHT_PLATFORM; | 484 | props.type = BACKLIGHT_PLATFORM; |
| @@ -505,9 +511,7 @@ static int __devinit gmux_probe(struct pnp_dev *pnp, | |||
| 505 | * Disable the other backlight choices. | 511 | * Disable the other backlight choices. |
| 506 | */ | 512 | */ |
| 507 | acpi_video_dmi_promote_vendor(); | 513 | acpi_video_dmi_promote_vendor(); |
| 508 | #if defined (CONFIG_ACPI_VIDEO) || defined (CONFIG_ACPI_VIDEO_MODULE) | ||
| 509 | acpi_video_unregister(); | 514 | acpi_video_unregister(); |
| 510 | #endif | ||
| 511 | apple_bl_unregister(); | 515 | apple_bl_unregister(); |
| 512 | 516 | ||
| 513 | gmux_data->power_state = VGA_SWITCHEROO_ON; | 517 | gmux_data->power_state = VGA_SWITCHEROO_ON; |
| @@ -593,9 +597,7 @@ static void __devexit gmux_remove(struct pnp_dev *pnp) | |||
| 593 | kfree(gmux_data); | 597 | kfree(gmux_data); |
| 594 | 598 | ||
| 595 | acpi_video_dmi_demote_vendor(); | 599 | acpi_video_dmi_demote_vendor(); |
| 596 | #if defined (CONFIG_ACPI_VIDEO) || defined (CONFIG_ACPI_VIDEO_MODULE) | ||
| 597 | acpi_video_register(); | 600 | acpi_video_register(); |
| 598 | #endif | ||
| 599 | apple_bl_register(); | 601 | apple_bl_register(); |
| 600 | } | 602 | } |
| 601 | 603 | ||
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index e38f91be0b10..4b568df56643 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c | |||
| @@ -85,7 +85,7 @@ static char *wled_type = "unknown"; | |||
| 85 | static char *bled_type = "unknown"; | 85 | static char *bled_type = "unknown"; |
| 86 | 86 | ||
| 87 | module_param(wled_type, charp, 0444); | 87 | module_param(wled_type, charp, 0444); |
| 88 | MODULE_PARM_DESC(wlan_status, "Set the wled type on boot " | 88 | MODULE_PARM_DESC(wled_type, "Set the wled type on boot " |
| 89 | "(unknown, led or rfkill). " | 89 | "(unknown, led or rfkill). " |
| 90 | "default is unknown"); | 90 | "default is unknown"); |
| 91 | 91 | ||
| @@ -863,9 +863,9 @@ static ssize_t show_infos(struct device *dev, | |||
| 863 | * The significance of others is yet to be found. | 863 | * The significance of others is yet to be found. |
| 864 | * If we don't find the method, we assume the device are present. | 864 | * If we don't find the method, we assume the device are present. |
| 865 | */ | 865 | */ |
| 866 | rv = acpi_evaluate_integer(asus->handle, "HRWS", NULL, &temp); | 866 | rv = acpi_evaluate_integer(asus->handle, "HWRS", NULL, &temp); |
| 867 | if (!ACPI_FAILURE(rv)) | 867 | if (!ACPI_FAILURE(rv)) |
| 868 | len += sprintf(page + len, "HRWS value : %#x\n", | 868 | len += sprintf(page + len, "HWRS value : %#x\n", |
| 869 | (uint) temp); | 869 | (uint) temp); |
| 870 | /* | 870 | /* |
| 871 | * Another value for userspace: the ASYM method returns 0x02 for | 871 | * Another value for userspace: the ASYM method returns 0x02 for |
| @@ -1751,9 +1751,9 @@ static int asus_laptop_get_info(struct asus_laptop *asus) | |||
| 1751 | * The significance of others is yet to be found. | 1751 | * The significance of others is yet to be found. |
| 1752 | */ | 1752 | */ |
| 1753 | status = | 1753 | status = |
| 1754 | acpi_evaluate_integer(asus->handle, "HRWS", NULL, &hwrs_result); | 1754 | acpi_evaluate_integer(asus->handle, "HWRS", NULL, &hwrs_result); |
| 1755 | if (!ACPI_FAILURE(status)) | 1755 | if (!ACPI_FAILURE(status)) |
| 1756 | pr_notice(" HRWS returned %x", (int)hwrs_result); | 1756 | pr_notice(" HWRS returned %x", (int)hwrs_result); |
| 1757 | 1757 | ||
| 1758 | if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) | 1758 | if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) |
| 1759 | asus->have_rsts = true; | 1759 | asus->have_rsts = true; |
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 2eb9fe8e8efd..c0e9ff489b24 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c | |||
| @@ -47,9 +47,7 @@ | |||
| 47 | #include <linux/thermal.h> | 47 | #include <linux/thermal.h> |
| 48 | #include <acpi/acpi_bus.h> | 48 | #include <acpi/acpi_bus.h> |
| 49 | #include <acpi/acpi_drivers.h> | 49 | #include <acpi/acpi_drivers.h> |
| 50 | #ifdef CONFIG_ACPI_VIDEO | ||
| 51 | #include <acpi/video.h> | 50 | #include <acpi/video.h> |
| 52 | #endif | ||
| 53 | 51 | ||
| 54 | #include "asus-wmi.h" | 52 | #include "asus-wmi.h" |
| 55 | 53 | ||
| @@ -1704,10 +1702,8 @@ static int asus_wmi_add(struct platform_device *pdev) | |||
| 1704 | if (asus->driver->quirks->wmi_backlight_power) | 1702 | if (asus->driver->quirks->wmi_backlight_power) |
| 1705 | acpi_video_dmi_promote_vendor(); | 1703 | acpi_video_dmi_promote_vendor(); |
| 1706 | if (!acpi_video_backlight_support()) { | 1704 | if (!acpi_video_backlight_support()) { |
| 1707 | #ifdef CONFIG_ACPI_VIDEO | ||
| 1708 | pr_info("Disabling ACPI video driver\n"); | 1705 | pr_info("Disabling ACPI video driver\n"); |
| 1709 | acpi_video_unregister(); | 1706 | acpi_video_unregister(); |
| 1710 | #endif | ||
| 1711 | err = asus_wmi_backlight_init(asus); | 1707 | err = asus_wmi_backlight_init(asus); |
| 1712 | if (err && err != -ENODEV) | 1708 | if (err && err != -ENODEV) |
| 1713 | goto fail_backlight; | 1709 | goto fail_backlight; |
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index dab91b48d22c..5ca264179f4e 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c | |||
| @@ -610,12 +610,12 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle) | |||
| 610 | 610 | ||
| 611 | if (!bus) { | 611 | if (!bus) { |
| 612 | pr_warn("Unable to find PCI bus 1?\n"); | 612 | pr_warn("Unable to find PCI bus 1?\n"); |
| 613 | goto out_unlock; | 613 | goto out_put_dev; |
| 614 | } | 614 | } |
| 615 | 615 | ||
| 616 | if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) { | 616 | if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) { |
| 617 | pr_err("Unable to read PCI config space?\n"); | 617 | pr_err("Unable to read PCI config space?\n"); |
| 618 | goto out_unlock; | 618 | goto out_put_dev; |
| 619 | } | 619 | } |
| 620 | 620 | ||
| 621 | absent = (l == 0xffffffff); | 621 | absent = (l == 0xffffffff); |
| @@ -627,7 +627,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle) | |||
| 627 | absent ? "absent" : "present"); | 627 | absent ? "absent" : "present"); |
| 628 | pr_warn("skipped wireless hotplug as probably " | 628 | pr_warn("skipped wireless hotplug as probably " |
| 629 | "inappropriate for this model\n"); | 629 | "inappropriate for this model\n"); |
| 630 | goto out_unlock; | 630 | goto out_put_dev; |
| 631 | } | 631 | } |
| 632 | 632 | ||
| 633 | if (!blocked) { | 633 | if (!blocked) { |
| @@ -635,7 +635,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle) | |||
| 635 | if (dev) { | 635 | if (dev) { |
| 636 | /* Device already present */ | 636 | /* Device already present */ |
| 637 | pci_dev_put(dev); | 637 | pci_dev_put(dev); |
| 638 | goto out_unlock; | 638 | goto out_put_dev; |
| 639 | } | 639 | } |
| 640 | dev = pci_scan_single_device(bus, 0); | 640 | dev = pci_scan_single_device(bus, 0); |
| 641 | if (dev) { | 641 | if (dev) { |
| @@ -650,6 +650,8 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle) | |||
| 650 | pci_dev_put(dev); | 650 | pci_dev_put(dev); |
| 651 | } | 651 | } |
| 652 | } | 652 | } |
| 653 | out_put_dev: | ||
| 654 | pci_dev_put(port); | ||
| 653 | } | 655 | } |
| 654 | 656 | ||
| 655 | out_unlock: | 657 | out_unlock: |
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index c1ca7bcebb66..dd90d15f5210 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c | |||
| @@ -26,9 +26,7 @@ | |||
| 26 | #include <linux/seq_file.h> | 26 | #include <linux/seq_file.h> |
| 27 | #include <linux/debugfs.h> | 27 | #include <linux/debugfs.h> |
| 28 | #include <linux/ctype.h> | 28 | #include <linux/ctype.h> |
| 29 | #ifdef CONFIG_ACPI_VIDEO | ||
| 30 | #include <acpi/video.h> | 29 | #include <acpi/video.h> |
| 31 | #endif | ||
| 32 | 30 | ||
| 33 | /* | 31 | /* |
| 34 | * This driver is needed because a number of Samsung laptops do not hook | 32 | * This driver is needed because a number of Samsung laptops do not hook |
| @@ -1558,9 +1556,7 @@ static int __init samsung_init(void) | |||
| 1558 | samsung->handle_backlight = false; | 1556 | samsung->handle_backlight = false; |
| 1559 | } else if (samsung->quirks->broken_acpi_video) { | 1557 | } else if (samsung->quirks->broken_acpi_video) { |
| 1560 | pr_info("Disabling ACPI video driver\n"); | 1558 | pr_info("Disabling ACPI video driver\n"); |
| 1561 | #ifdef CONFIG_ACPI_VIDEO | ||
| 1562 | acpi_video_unregister(); | 1559 | acpi_video_unregister(); |
| 1563 | #endif | ||
| 1564 | } | 1560 | } |
| 1565 | #endif | 1561 | #endif |
| 1566 | 1562 | ||
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 80e377949314..52daaa816e53 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
| @@ -545,7 +545,7 @@ TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */ | |||
| 545 | */ | 545 | */ |
| 546 | 546 | ||
| 547 | static int acpi_evalf(acpi_handle handle, | 547 | static int acpi_evalf(acpi_handle handle, |
| 548 | void *res, char *method, char *fmt, ...) | 548 | int *res, char *method, char *fmt, ...) |
| 549 | { | 549 | { |
| 550 | char *fmt0 = fmt; | 550 | char *fmt0 = fmt; |
| 551 | struct acpi_object_list params; | 551 | struct acpi_object_list params; |
| @@ -606,7 +606,7 @@ static int acpi_evalf(acpi_handle handle, | |||
| 606 | success = (status == AE_OK && | 606 | success = (status == AE_OK && |
| 607 | out_obj.type == ACPI_TYPE_INTEGER); | 607 | out_obj.type == ACPI_TYPE_INTEGER); |
| 608 | if (success && res) | 608 | if (success && res) |
| 609 | *(int *)res = out_obj.integer.value; | 609 | *res = out_obj.integer.value; |
| 610 | break; | 610 | break; |
| 611 | case 'v': /* void */ | 611 | case 'v': /* void */ |
| 612 | success = status == AE_OK; | 612 | success = status == AE_OK; |
| @@ -7386,17 +7386,18 @@ static int fan_get_status(u8 *status) | |||
| 7386 | * Add TPACPI_FAN_RD_ACPI_FANS ? */ | 7386 | * Add TPACPI_FAN_RD_ACPI_FANS ? */ |
| 7387 | 7387 | ||
| 7388 | switch (fan_status_access_mode) { | 7388 | switch (fan_status_access_mode) { |
| 7389 | case TPACPI_FAN_RD_ACPI_GFAN: | 7389 | case TPACPI_FAN_RD_ACPI_GFAN: { |
| 7390 | /* 570, 600e/x, 770e, 770x */ | 7390 | /* 570, 600e/x, 770e, 770x */ |
| 7391 | int res; | ||
| 7391 | 7392 | ||
| 7392 | if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d"))) | 7393 | if (unlikely(!acpi_evalf(gfan_handle, &res, NULL, "d"))) |
| 7393 | return -EIO; | 7394 | return -EIO; |
| 7394 | 7395 | ||
| 7395 | if (likely(status)) | 7396 | if (likely(status)) |
| 7396 | *status = s & 0x07; | 7397 | *status = res & 0x07; |
| 7397 | 7398 | ||
| 7398 | break; | 7399 | break; |
| 7399 | 7400 | } | |
| 7400 | case TPACPI_FAN_RD_TPEC: | 7401 | case TPACPI_FAN_RD_TPEC: |
| 7401 | /* all except 570, 600e/x, 770e, 770x */ | 7402 | /* all except 570, 600e/x, 770e, 770x */ |
| 7402 | if (unlikely(!acpi_ec_read(fan_status_offset, &s))) | 7403 | if (unlikely(!acpi_ec_read(fan_status_offset, &s))) |
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index 0b66d0f25922..4b6688909fee 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c | |||
| @@ -100,6 +100,13 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
| 100 | writel(period_cycles, pc->mmio_base + CAP3); | 100 | writel(period_cycles, pc->mmio_base + CAP3); |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | if (!test_bit(PWMF_ENABLED, &pwm->flags)) { | ||
| 104 | reg_val = readw(pc->mmio_base + ECCTL2); | ||
| 105 | /* Disable APWM mode to put APWM output Low */ | ||
| 106 | reg_val &= ~ECCTL2_APWM_MODE; | ||
| 107 | writew(reg_val, pc->mmio_base + ECCTL2); | ||
| 108 | } | ||
| 109 | |||
| 103 | pm_runtime_put_sync(pc->chip.dev); | 110 | pm_runtime_put_sync(pc->chip.dev); |
| 104 | return 0; | 111 | return 0; |
| 105 | } | 112 | } |
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index c3756d1be194..b1996bcd5b78 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c | |||
| @@ -104,6 +104,7 @@ struct ehrpwm_pwm_chip { | |||
| 104 | struct pwm_chip chip; | 104 | struct pwm_chip chip; |
| 105 | unsigned int clk_rate; | 105 | unsigned int clk_rate; |
| 106 | void __iomem *mmio_base; | 106 | void __iomem *mmio_base; |
| 107 | unsigned long period_cycles[NUM_PWM_CHANNEL]; | ||
| 107 | }; | 108 | }; |
| 108 | 109 | ||
| 109 | static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) | 110 | static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) |
| @@ -210,6 +211,7 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
| 210 | unsigned long long c; | 211 | unsigned long long c; |
| 211 | unsigned long period_cycles, duty_cycles; | 212 | unsigned long period_cycles, duty_cycles; |
| 212 | unsigned short ps_divval, tb_divval; | 213 | unsigned short ps_divval, tb_divval; |
| 214 | int i; | ||
| 213 | 215 | ||
| 214 | if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC) | 216 | if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC) |
| 215 | return -ERANGE; | 217 | return -ERANGE; |
| @@ -229,6 +231,28 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
| 229 | duty_cycles = (unsigned long)c; | 231 | duty_cycles = (unsigned long)c; |
| 230 | } | 232 | } |
| 231 | 233 | ||
| 234 | /* | ||
| 235 | * Period values should be same for multiple PWM channels as IP uses | ||
| 236 | * same period register for multiple channels. | ||
| 237 | */ | ||
| 238 | for (i = 0; i < NUM_PWM_CHANNEL; i++) { | ||
| 239 | if (pc->period_cycles[i] && | ||
| 240 | (pc->period_cycles[i] != period_cycles)) { | ||
| 241 | /* | ||
| 242 | * Allow channel to reconfigure period if no other | ||
| 243 | * channels being configured. | ||
| 244 | */ | ||
| 245 | if (i == pwm->hwpwm) | ||
| 246 | continue; | ||
| 247 | |||
| 248 | dev_err(chip->dev, "Period value conflicts with channel %d\n", | ||
| 249 | i); | ||
| 250 | return -EINVAL; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | pc->period_cycles[pwm->hwpwm] = period_cycles; | ||
| 255 | |||
| 232 | /* Configure clock prescaler to support Low frequency PWM wave */ | 256 | /* Configure clock prescaler to support Low frequency PWM wave */ |
| 233 | if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval, | 257 | if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval, |
| 234 | &tb_divval)) { | 258 | &tb_divval)) { |
| @@ -320,10 +344,15 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
| 320 | 344 | ||
| 321 | static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) | 345 | static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) |
| 322 | { | 346 | { |
| 347 | struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); | ||
| 348 | |||
| 323 | if (test_bit(PWMF_ENABLED, &pwm->flags)) { | 349 | if (test_bit(PWMF_ENABLED, &pwm->flags)) { |
| 324 | dev_warn(chip->dev, "Removing PWM device without disabling\n"); | 350 | dev_warn(chip->dev, "Removing PWM device without disabling\n"); |
| 325 | pm_runtime_put_sync(chip->dev); | 351 | pm_runtime_put_sync(chip->dev); |
| 326 | } | 352 | } |
| 353 | |||
| 354 | /* set period value to zero on free */ | ||
| 355 | pc->period_cycles[pwm->hwpwm] = 0; | ||
| 327 | } | 356 | } |
| 328 | 357 | ||
| 329 | static const struct pwm_ops ehrpwm_pwm_ops = { | 358 | static const struct pwm_ops ehrpwm_pwm_ops = { |
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 4e932cc695e9..e98a5e7827df 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig | |||
| @@ -33,9 +33,8 @@ config REGULATOR_DUMMY | |||
| 33 | help | 33 | help |
| 34 | If this option is enabled then when a regulator lookup fails | 34 | If this option is enabled then when a regulator lookup fails |
| 35 | and the board has not specified that it has provided full | 35 | and the board has not specified that it has provided full |
| 36 | constraints then the regulator core will provide an always | 36 | constraints the regulator core will provide an always |
| 37 | enabled dummy regulator will be provided, allowing consumer | 37 | enabled dummy regulator, allowing consumer drivers to continue. |
| 38 | drivers to continue. | ||
| 39 | 38 | ||
| 40 | A warning will be generated when this substitution is done. | 39 | A warning will be generated when this substitution is done. |
| 41 | 40 | ||
| @@ -50,11 +49,11 @@ config REGULATOR_VIRTUAL_CONSUMER | |||
| 50 | tristate "Virtual regulator consumer support" | 49 | tristate "Virtual regulator consumer support" |
| 51 | help | 50 | help |
| 52 | This driver provides a virtual consumer for the voltage and | 51 | This driver provides a virtual consumer for the voltage and |
| 53 | current regulator API which provides sysfs controls for | 52 | current regulator API which provides sysfs controls for |
| 54 | configuring the supplies requested. This is mainly useful | 53 | configuring the supplies requested. This is mainly useful |
| 55 | for test purposes. | 54 | for test purposes. |
| 56 | 55 | ||
| 57 | If unsure, say no. | 56 | If unsure, say no. |
| 58 | 57 | ||
| 59 | config REGULATOR_USERSPACE_CONSUMER | 58 | config REGULATOR_USERSPACE_CONSUMER |
| 60 | tristate "Userspace regulator consumer support" | 59 | tristate "Userspace regulator consumer support" |
| @@ -63,7 +62,7 @@ config REGULATOR_USERSPACE_CONSUMER | |||
| 63 | from user space. Userspace consumer driver provides ability to | 62 | from user space. Userspace consumer driver provides ability to |
| 64 | control power supplies for such devices. | 63 | control power supplies for such devices. |
| 65 | 64 | ||
| 66 | If unsure, say no. | 65 | If unsure, say no. |
| 67 | 66 | ||
| 68 | config REGULATOR_GPIO | 67 | config REGULATOR_GPIO |
| 69 | tristate "GPIO regulator support" | 68 | tristate "GPIO regulator support" |
| @@ -110,6 +109,17 @@ config REGULATOR_DA9052 | |||
| 110 | This driver supports the voltage regulators of DA9052-BC and | 109 | This driver supports the voltage regulators of DA9052-BC and |
| 111 | DA9053-AA/Bx PMIC. | 110 | DA9053-AA/Bx PMIC. |
| 112 | 111 | ||
| 112 | config REGULATOR_FAN53555 | ||
| 113 | tristate "Fairchild FAN53555 Regulator" | ||
| 114 | depends on I2C | ||
| 115 | select REGMAP_I2C | ||
| 116 | help | ||
| 117 | This driver supports Fairchild FAN53555 Digitally Programmable | ||
| 118 | TinyBuck Regulator. The FAN53555 is a step-down switching voltage | ||
| 119 | regulator that delivers a digitally programmable output from an | ||
| 120 | input voltage supply of 2.5V to 5.5V. The output voltage is | ||
| 121 | programmed through an I2C interface. | ||
| 122 | |||
| 113 | config REGULATOR_ANATOP | 123 | config REGULATOR_ANATOP |
| 114 | tristate "Freescale i.MX on-chip ANATOP LDO regulators" | 124 | tristate "Freescale i.MX on-chip ANATOP LDO regulators" |
| 115 | depends on MFD_ANATOP | 125 | depends on MFD_ANATOP |
| @@ -172,6 +182,14 @@ config REGULATOR_MAX8660 | |||
| 172 | This driver controls a Maxim 8660/8661 voltage output | 182 | This driver controls a Maxim 8660/8661 voltage output |
| 173 | regulator via I2C bus. | 183 | regulator via I2C bus. |
| 174 | 184 | ||
| 185 | config REGULATOR_MAX8907 | ||
| 186 | tristate "Maxim 8907 voltage regulator" | ||
| 187 | depends on MFD_MAX8907 | ||
| 188 | help | ||
| 189 | This driver controls a Maxim 8907 voltage output regulator | ||
| 190 | via I2C bus. The provided regulator is suitable for Tegra | ||
| 191 | chip to control Step-Down DC-DC and LDOs. | ||
| 192 | |||
| 175 | config REGULATOR_MAX8925 | 193 | config REGULATOR_MAX8925 |
| 176 | tristate "Maxim MAX8925 Power Management IC" | 194 | tristate "Maxim MAX8925 Power Management IC" |
| 177 | depends on MFD_MAX8925 | 195 | depends on MFD_MAX8925 |
| @@ -247,7 +265,7 @@ config REGULATOR_LP8788 | |||
| 247 | 265 | ||
| 248 | config REGULATOR_PCF50633 | 266 | config REGULATOR_PCF50633 |
| 249 | tristate "NXP PCF50633 regulator driver" | 267 | tristate "NXP PCF50633 regulator driver" |
| 250 | depends on MFD_PCF50633 | 268 | depends on MFD_PCF50633 |
| 251 | help | 269 | help |
| 252 | Say Y here to support the voltage regulators and convertors | 270 | Say Y here to support the voltage regulators and convertors |
| 253 | on PCF50633 | 271 | on PCF50633 |
| @@ -416,7 +434,7 @@ config REGULATOR_WM8350 | |||
| 416 | depends on MFD_WM8350 | 434 | depends on MFD_WM8350 |
| 417 | help | 435 | help |
| 418 | This driver provides support for the voltage and current regulators | 436 | This driver provides support for the voltage and current regulators |
| 419 | of the WM8350 AudioPlus PMIC. | 437 | of the WM8350 AudioPlus PMIC. |
| 420 | 438 | ||
| 421 | config REGULATOR_WM8400 | 439 | config REGULATOR_WM8400 |
| 422 | tristate "Wolfson Microelectronics WM8400 AudioPlus PMIC" | 440 | tristate "Wolfson Microelectronics WM8400 AudioPlus PMIC" |
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 3342615cf25e..e431eed8a878 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile | |||
| @@ -20,6 +20,7 @@ obj-$(CONFIG_REGULATOR_DA903X) += da903x.o | |||
| 20 | obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o | 20 | obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o |
| 21 | obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o | 21 | obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o |
| 22 | obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o | 22 | obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o |
| 23 | obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o | ||
| 23 | obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o | 24 | obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o |
| 24 | obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o | 25 | obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o |
| 25 | obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o | 26 | obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o |
| @@ -30,6 +31,7 @@ obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o | |||
| 30 | obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o | 31 | obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o |
| 31 | obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o | 32 | obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o |
| 32 | obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o | 33 | obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o |
| 34 | obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o | ||
| 33 | obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o | 35 | obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o |
| 34 | obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o | 36 | obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o |
| 35 | obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o | 37 | obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o |
diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index 6f45bfd22e83..167c93f21981 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c | |||
| @@ -162,7 +162,7 @@ static struct aat2870_regulator *aat2870_get_regulator(int id) | |||
| 162 | static int aat2870_regulator_probe(struct platform_device *pdev) | 162 | static int aat2870_regulator_probe(struct platform_device *pdev) |
| 163 | { | 163 | { |
| 164 | struct aat2870_regulator *ri; | 164 | struct aat2870_regulator *ri; |
| 165 | struct regulator_config config = { 0 }; | 165 | struct regulator_config config = { }; |
| 166 | struct regulator_dev *rdev; | 166 | struct regulator_dev *rdev; |
| 167 | 167 | ||
| 168 | ri = aat2870_get_regulator(pdev->id); | 168 | ri = aat2870_get_regulator(pdev->id); |
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index c151fd5d8c97..65ad2b36ce36 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c | |||
| @@ -347,17 +347,11 @@ static int ab3100_get_voltage_regulator_external(struct regulator_dev *reg) | |||
| 347 | return abreg->plfdata->external_voltage; | 347 | return abreg->plfdata->external_voltage; |
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | static int ab3100_get_fixed_voltage_regulator(struct regulator_dev *reg) | ||
| 351 | { | ||
| 352 | return reg->desc->min_uV; | ||
| 353 | } | ||
| 354 | |||
| 355 | static struct regulator_ops regulator_ops_fixed = { | 350 | static struct regulator_ops regulator_ops_fixed = { |
| 356 | .list_voltage = regulator_list_voltage_linear, | 351 | .list_voltage = regulator_list_voltage_linear, |
| 357 | .enable = ab3100_enable_regulator, | 352 | .enable = ab3100_enable_regulator, |
| 358 | .disable = ab3100_disable_regulator, | 353 | .disable = ab3100_disable_regulator, |
| 359 | .is_enabled = ab3100_is_enabled_regulator, | 354 | .is_enabled = ab3100_is_enabled_regulator, |
| 360 | .get_voltage = ab3100_get_fixed_voltage_regulator, | ||
| 361 | }; | 355 | }; |
| 362 | 356 | ||
| 363 | static struct regulator_ops regulator_ops_variable = { | 357 | static struct regulator_ops regulator_ops_variable = { |
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 10f2f4d4d190..e3d1d063025a 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | * @voltage_bank: bank to control regulator voltage | 37 | * @voltage_bank: bank to control regulator voltage |
| 38 | * @voltage_reg: register to control regulator voltage | 38 | * @voltage_reg: register to control regulator voltage |
| 39 | * @voltage_mask: mask to control regulator voltage | 39 | * @voltage_mask: mask to control regulator voltage |
| 40 | * @voltage_shift: shift to control regulator voltage | ||
| 40 | * @delay: startup/set voltage delay in us | 41 | * @delay: startup/set voltage delay in us |
| 41 | */ | 42 | */ |
| 42 | struct ab8500_regulator_info { | 43 | struct ab8500_regulator_info { |
| @@ -50,6 +51,7 @@ struct ab8500_regulator_info { | |||
| 50 | u8 voltage_bank; | 51 | u8 voltage_bank; |
| 51 | u8 voltage_reg; | 52 | u8 voltage_reg; |
| 52 | u8 voltage_mask; | 53 | u8 voltage_mask; |
| 54 | u8 voltage_shift; | ||
| 53 | unsigned int delay; | 55 | unsigned int delay; |
| 54 | }; | 56 | }; |
| 55 | 57 | ||
| @@ -195,17 +197,14 @@ static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev) | |||
| 195 | } | 197 | } |
| 196 | 198 | ||
| 197 | dev_vdbg(rdev_get_dev(rdev), | 199 | dev_vdbg(rdev_get_dev(rdev), |
| 198 | "%s-get_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x," | 200 | "%s-get_voltage (bank, reg, mask, shift, value): " |
| 199 | " 0x%x\n", | 201 | "0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", |
| 200 | info->desc.name, info->voltage_bank, info->voltage_reg, | 202 | info->desc.name, info->voltage_bank, |
| 201 | info->voltage_mask, regval); | 203 | info->voltage_reg, info->voltage_mask, |
| 204 | info->voltage_shift, regval); | ||
| 202 | 205 | ||
| 203 | /* vintcore has a different layout */ | ||
| 204 | val = regval & info->voltage_mask; | 206 | val = regval & info->voltage_mask; |
| 205 | if (info->desc.id == AB8500_LDO_INTCORE) | 207 | return val >> info->voltage_shift; |
| 206 | return val >> 0x3; | ||
| 207 | else | ||
| 208 | return val; | ||
| 209 | } | 208 | } |
| 210 | 209 | ||
| 211 | static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev, | 210 | static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev, |
| @@ -221,7 +220,7 @@ static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev, | |||
| 221 | } | 220 | } |
| 222 | 221 | ||
| 223 | /* set the registers for the request */ | 222 | /* set the registers for the request */ |
| 224 | regval = (u8)selector; | 223 | regval = (u8)selector << info->voltage_shift; |
| 225 | ret = abx500_mask_and_set_register_interruptible(info->dev, | 224 | ret = abx500_mask_and_set_register_interruptible(info->dev, |
| 226 | info->voltage_bank, info->voltage_reg, | 225 | info->voltage_bank, info->voltage_reg, |
| 227 | info->voltage_mask, regval); | 226 | info->voltage_mask, regval); |
| @@ -238,13 +237,6 @@ static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev, | |||
| 238 | return ret; | 237 | return ret; |
| 239 | } | 238 | } |
| 240 | 239 | ||
| 241 | static int ab8500_regulator_enable_time(struct regulator_dev *rdev) | ||
| 242 | { | ||
| 243 | struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); | ||
| 244 | |||
| 245 | return info->delay; | ||
| 246 | } | ||
| 247 | |||
| 248 | static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev, | 240 | static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev, |
| 249 | unsigned int old_sel, | 241 | unsigned int old_sel, |
| 250 | unsigned int new_sel) | 242 | unsigned int new_sel) |
| @@ -261,22 +253,14 @@ static struct regulator_ops ab8500_regulator_ops = { | |||
| 261 | .get_voltage_sel = ab8500_regulator_get_voltage_sel, | 253 | .get_voltage_sel = ab8500_regulator_get_voltage_sel, |
| 262 | .set_voltage_sel = ab8500_regulator_set_voltage_sel, | 254 | .set_voltage_sel = ab8500_regulator_set_voltage_sel, |
| 263 | .list_voltage = regulator_list_voltage_table, | 255 | .list_voltage = regulator_list_voltage_table, |
| 264 | .enable_time = ab8500_regulator_enable_time, | ||
| 265 | .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel, | 256 | .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel, |
| 266 | }; | 257 | }; |
| 267 | 258 | ||
| 268 | static int ab8500_fixed_get_voltage(struct regulator_dev *rdev) | ||
| 269 | { | ||
| 270 | return rdev->desc->min_uV; | ||
| 271 | } | ||
| 272 | |||
| 273 | static struct regulator_ops ab8500_regulator_fixed_ops = { | 259 | static struct regulator_ops ab8500_regulator_fixed_ops = { |
| 274 | .enable = ab8500_regulator_enable, | 260 | .enable = ab8500_regulator_enable, |
| 275 | .disable = ab8500_regulator_disable, | 261 | .disable = ab8500_regulator_disable, |
| 276 | .is_enabled = ab8500_regulator_is_enabled, | 262 | .is_enabled = ab8500_regulator_is_enabled, |
| 277 | .get_voltage = ab8500_fixed_get_voltage, | ||
| 278 | .list_voltage = regulator_list_voltage_linear, | 263 | .list_voltage = regulator_list_voltage_linear, |
| 279 | .enable_time = ab8500_regulator_enable_time, | ||
| 280 | }; | 264 | }; |
| 281 | 265 | ||
| 282 | static struct ab8500_regulator_info | 266 | static struct ab8500_regulator_info |
| @@ -358,6 +342,7 @@ static struct ab8500_regulator_info | |||
| 358 | .voltage_bank = 0x03, | 342 | .voltage_bank = 0x03, |
| 359 | .voltage_reg = 0x80, | 343 | .voltage_reg = 0x80, |
| 360 | .voltage_mask = 0x38, | 344 | .voltage_mask = 0x38, |
| 345 | .voltage_shift = 3, | ||
| 361 | }, | 346 | }, |
| 362 | 347 | ||
| 363 | /* | 348 | /* |
| @@ -374,6 +359,7 @@ static struct ab8500_regulator_info | |||
| 374 | .owner = THIS_MODULE, | 359 | .owner = THIS_MODULE, |
| 375 | .n_voltages = 1, | 360 | .n_voltages = 1, |
| 376 | .min_uV = 2000000, | 361 | .min_uV = 2000000, |
| 362 | .enable_time = 10000, | ||
| 377 | }, | 363 | }, |
| 378 | .delay = 10000, | 364 | .delay = 10000, |
| 379 | .update_bank = 0x03, | 365 | .update_bank = 0x03, |
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index c8f95c07adb6..d184aa35abcb 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c | |||
| @@ -39,6 +39,8 @@ static struct regulator_ops arizona_ldo1_ops = { | |||
| 39 | .map_voltage = regulator_map_voltage_linear, | 39 | .map_voltage = regulator_map_voltage_linear, |
| 40 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | 40 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
| 41 | .set_voltage_sel = regulator_set_voltage_sel_regmap, | 41 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
| 42 | .get_bypass = regulator_get_bypass_regmap, | ||
| 43 | .set_bypass = regulator_set_bypass_regmap, | ||
| 42 | }; | 44 | }; |
| 43 | 45 | ||
| 44 | static const struct regulator_desc arizona_ldo1 = { | 46 | static const struct regulator_desc arizona_ldo1 = { |
| @@ -49,9 +51,11 @@ static const struct regulator_desc arizona_ldo1 = { | |||
| 49 | 51 | ||
| 50 | .vsel_reg = ARIZONA_LDO1_CONTROL_1, | 52 | .vsel_reg = ARIZONA_LDO1_CONTROL_1, |
| 51 | .vsel_mask = ARIZONA_LDO1_VSEL_MASK, | 53 | .vsel_mask = ARIZONA_LDO1_VSEL_MASK, |
| 54 | .bypass_reg = ARIZONA_LDO1_CONTROL_1, | ||
| 55 | .bypass_mask = ARIZONA_LDO1_BYPASS, | ||
| 52 | .min_uV = 900000, | 56 | .min_uV = 900000, |
| 53 | .uV_step = 50000, | 57 | .uV_step = 50000, |
| 54 | .n_voltages = 7, | 58 | .n_voltages = 6, |
| 55 | 59 | ||
| 56 | .owner = THIS_MODULE, | 60 | .owner = THIS_MODULE, |
| 57 | }; | 61 | }; |
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index 450a069aa9b6..d9b1f82cc5bd 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c | |||
| @@ -82,6 +82,9 @@ static struct regulator_ops arizona_micsupp_ops = { | |||
| 82 | 82 | ||
| 83 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | 83 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
| 84 | .set_voltage_sel = regulator_set_voltage_sel_regmap, | 84 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
| 85 | |||
| 86 | .get_bypass = regulator_get_bypass_regmap, | ||
| 87 | .set_bypass = regulator_set_bypass_regmap, | ||
| 85 | }; | 88 | }; |
| 86 | 89 | ||
| 87 | static const struct regulator_desc arizona_micsupp = { | 90 | static const struct regulator_desc arizona_micsupp = { |
| @@ -95,6 +98,8 @@ static const struct regulator_desc arizona_micsupp = { | |||
| 95 | .vsel_mask = ARIZONA_LDO2_VSEL_MASK, | 98 | .vsel_mask = ARIZONA_LDO2_VSEL_MASK, |
| 96 | .enable_reg = ARIZONA_MIC_CHARGE_PUMP_1, | 99 | .enable_reg = ARIZONA_MIC_CHARGE_PUMP_1, |
| 97 | .enable_mask = ARIZONA_CPMIC_ENA, | 100 | .enable_mask = ARIZONA_CPMIC_ENA, |
| 101 | .bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1, | ||
| 102 | .bypass_mask = ARIZONA_CPMIC_BYPASS, | ||
| 98 | 103 | ||
| 99 | .owner = THIS_MODULE, | 104 | .owner = THIS_MODULE, |
| 100 | }; | 105 | }; |
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 48385318175a..2e0352dc26bd 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c | |||
| @@ -77,6 +77,7 @@ struct regulator { | |||
| 77 | struct device *dev; | 77 | struct device *dev; |
| 78 | struct list_head list; | 78 | struct list_head list; |
| 79 | unsigned int always_on:1; | 79 | unsigned int always_on:1; |
| 80 | unsigned int bypass:1; | ||
| 80 | int uA_load; | 81 | int uA_load; |
| 81 | int min_uV; | 82 | int min_uV; |
| 82 | int max_uV; | 83 | int max_uV; |
| @@ -394,6 +395,9 @@ static ssize_t regulator_status_show(struct device *dev, | |||
| 394 | case REGULATOR_STATUS_STANDBY: | 395 | case REGULATOR_STATUS_STANDBY: |
| 395 | label = "standby"; | 396 | label = "standby"; |
| 396 | break; | 397 | break; |
| 398 | case REGULATOR_STATUS_BYPASS: | ||
| 399 | label = "bypass"; | ||
| 400 | break; | ||
| 397 | case REGULATOR_STATUS_UNDEFINED: | 401 | case REGULATOR_STATUS_UNDEFINED: |
| 398 | label = "undefined"; | 402 | label = "undefined"; |
| 399 | break; | 403 | break; |
| @@ -585,6 +589,27 @@ static ssize_t regulator_suspend_standby_state_show(struct device *dev, | |||
| 585 | static DEVICE_ATTR(suspend_standby_state, 0444, | 589 | static DEVICE_ATTR(suspend_standby_state, 0444, |
| 586 | regulator_suspend_standby_state_show, NULL); | 590 | regulator_suspend_standby_state_show, NULL); |
| 587 | 591 | ||
| 592 | static ssize_t regulator_bypass_show(struct device *dev, | ||
| 593 | struct device_attribute *attr, char *buf) | ||
| 594 | { | ||
| 595 | struct regulator_dev *rdev = dev_get_drvdata(dev); | ||
| 596 | const char *report; | ||
| 597 | bool bypass; | ||
| 598 | int ret; | ||
| 599 | |||
| 600 | ret = rdev->desc->ops->get_bypass(rdev, &bypass); | ||
| 601 | |||
| 602 | if (ret != 0) | ||
| 603 | report = "unknown"; | ||
| 604 | else if (bypass) | ||
| 605 | report = "enabled"; | ||
| 606 | else | ||
| 607 | report = "disabled"; | ||
| 608 | |||
| 609 | return sprintf(buf, "%s\n", report); | ||
| 610 | } | ||
| 611 | static DEVICE_ATTR(bypass, 0444, | ||
| 612 | regulator_bypass_show, NULL); | ||
| 588 | 613 | ||
| 589 | /* | 614 | /* |
| 590 | * These are the only attributes are present for all regulators. | 615 | * These are the only attributes are present for all regulators. |
| @@ -778,6 +803,9 @@ static void print_constraints(struct regulator_dev *rdev) | |||
| 778 | if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) | 803 | if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) |
| 779 | count += sprintf(buf + count, "standby"); | 804 | count += sprintf(buf + count, "standby"); |
| 780 | 805 | ||
| 806 | if (!count) | ||
| 807 | sprintf(buf, "no parameters"); | ||
| 808 | |||
| 781 | rdev_info(rdev, "%s\n", buf); | 809 | rdev_info(rdev, "%s\n", buf); |
| 782 | 810 | ||
| 783 | if ((constraints->min_uV != constraints->max_uV) && | 811 | if ((constraints->min_uV != constraints->max_uV) && |
| @@ -974,6 +1002,7 @@ static int set_supply(struct regulator_dev *rdev, | |||
| 974 | err = -ENOMEM; | 1002 | err = -ENOMEM; |
| 975 | return err; | 1003 | return err; |
| 976 | } | 1004 | } |
| 1005 | supply_rdev->open_count++; | ||
| 977 | 1006 | ||
| 978 | return 0; | 1007 | return 0; |
| 979 | } | 1008 | } |
| @@ -1720,6 +1749,9 @@ int regulator_disable_deferred(struct regulator *regulator, int ms) | |||
| 1720 | if (regulator->always_on) | 1749 | if (regulator->always_on) |
| 1721 | return 0; | 1750 | return 0; |
| 1722 | 1751 | ||
| 1752 | if (!ms) | ||
| 1753 | return regulator_disable(regulator); | ||
| 1754 | |||
| 1723 | mutex_lock(&rdev->mutex); | 1755 | mutex_lock(&rdev->mutex); |
| 1724 | rdev->deferred_disables++; | 1756 | rdev->deferred_disables++; |
| 1725 | mutex_unlock(&rdev->mutex); | 1757 | mutex_unlock(&rdev->mutex); |
| @@ -2178,9 +2210,12 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, | |||
| 2178 | } | 2210 | } |
| 2179 | } | 2211 | } |
| 2180 | 2212 | ||
| 2181 | if (ret == 0 && best_val >= 0) | 2213 | if (ret == 0 && best_val >= 0) { |
| 2214 | unsigned long data = best_val; | ||
| 2215 | |||
| 2182 | _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, | 2216 | _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, |
| 2183 | (void *)best_val); | 2217 | (void *)data); |
| 2218 | } | ||
| 2184 | 2219 | ||
| 2185 | trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val); | 2220 | trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val); |
| 2186 | 2221 | ||
| @@ -2291,8 +2326,8 @@ int regulator_set_voltage_time(struct regulator *regulator, | |||
| 2291 | EXPORT_SYMBOL_GPL(regulator_set_voltage_time); | 2326 | EXPORT_SYMBOL_GPL(regulator_set_voltage_time); |
| 2292 | 2327 | ||
| 2293 | /** | 2328 | /** |
| 2294 | *regulator_set_voltage_time_sel - get raise/fall time | 2329 | * regulator_set_voltage_time_sel - get raise/fall time |
| 2295 | * @regulator: regulator source | 2330 | * @rdev: regulator source device |
| 2296 | * @old_selector: selector for starting voltage | 2331 | * @old_selector: selector for starting voltage |
| 2297 | * @new_selector: selector for target voltage | 2332 | * @new_selector: selector for target voltage |
| 2298 | * | 2333 | * |
| @@ -2388,6 +2423,8 @@ static int _regulator_get_voltage(struct regulator_dev *rdev) | |||
| 2388 | ret = rdev->desc->ops->list_voltage(rdev, sel); | 2423 | ret = rdev->desc->ops->list_voltage(rdev, sel); |
| 2389 | } else if (rdev->desc->ops->get_voltage) { | 2424 | } else if (rdev->desc->ops->get_voltage) { |
| 2390 | ret = rdev->desc->ops->get_voltage(rdev); | 2425 | ret = rdev->desc->ops->get_voltage(rdev); |
| 2426 | } else if (rdev->desc->ops->list_voltage) { | ||
| 2427 | ret = rdev->desc->ops->list_voltage(rdev, 0); | ||
| 2391 | } else { | 2428 | } else { |
| 2392 | return -EINVAL; | 2429 | return -EINVAL; |
| 2393 | } | 2430 | } |
| @@ -2674,6 +2711,100 @@ out: | |||
| 2674 | EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); | 2711 | EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); |
| 2675 | 2712 | ||
| 2676 | /** | 2713 | /** |
| 2714 | * regulator_set_bypass_regmap - Default set_bypass() using regmap | ||
| 2715 | * | ||
| 2716 | * @rdev: device to operate on. | ||
| 2717 | * @enable: state to set. | ||
| 2718 | */ | ||
| 2719 | int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable) | ||
| 2720 | { | ||
| 2721 | unsigned int val; | ||
| 2722 | |||
| 2723 | if (enable) | ||
| 2724 | val = rdev->desc->bypass_mask; | ||
| 2725 | else | ||
| 2726 | val = 0; | ||
| 2727 | |||
| 2728 | return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg, | ||
| 2729 | rdev->desc->bypass_mask, val); | ||
| 2730 | } | ||
| 2731 | EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap); | ||
| 2732 | |||
| 2733 | /** | ||
| 2734 | * regulator_get_bypass_regmap - Default get_bypass() using regmap | ||
| 2735 | * | ||
| 2736 | * @rdev: device to operate on. | ||
| 2737 | * @enable: current state. | ||
| 2738 | */ | ||
| 2739 | int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable) | ||
| 2740 | { | ||
| 2741 | unsigned int val; | ||
| 2742 | int ret; | ||
| 2743 | |||
| 2744 | ret = regmap_read(rdev->regmap, rdev->desc->bypass_reg, &val); | ||
| 2745 | if (ret != 0) | ||
| 2746 | return ret; | ||
| 2747 | |||
| 2748 | *enable = val & rdev->desc->bypass_mask; | ||
| 2749 | |||
| 2750 | return 0; | ||
| 2751 | } | ||
| 2752 | EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap); | ||
| 2753 | |||
| 2754 | /** | ||
| 2755 | * regulator_allow_bypass - allow the regulator to go into bypass mode | ||
| 2756 | * | ||
| 2757 | * @regulator: Regulator to configure | ||
| 2758 | * @allow: enable or disable bypass mode | ||
| 2759 | * | ||
| 2760 | * Allow the regulator to go into bypass mode if all other consumers | ||
| 2761 | * for the regulator also enable bypass mode and the machine | ||
| 2762 | * constraints allow this. Bypass mode means that the regulator is | ||
| 2763 | * simply passing the input directly to the output with no regulation. | ||
| 2764 | */ | ||
| 2765 | int regulator_allow_bypass(struct regulator *regulator, bool enable) | ||
| 2766 | { | ||
| 2767 | struct regulator_dev *rdev = regulator->rdev; | ||
| 2768 | int ret = 0; | ||
| 2769 | |||
| 2770 | if (!rdev->desc->ops->set_bypass) | ||
| 2771 | return 0; | ||
| 2772 | |||
| 2773 | if (rdev->constraints && | ||
| 2774 | !(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_BYPASS)) | ||
| 2775 | return 0; | ||
| 2776 | |||
| 2777 | mutex_lock(&rdev->mutex); | ||
| 2778 | |||
| 2779 | if (enable && !regulator->bypass) { | ||
| 2780 | rdev->bypass_count++; | ||
| 2781 | |||
| 2782 | if (rdev->bypass_count == rdev->open_count) { | ||
| 2783 | ret = rdev->desc->ops->set_bypass(rdev, enable); | ||
| 2784 | if (ret != 0) | ||
| 2785 | rdev->bypass_count--; | ||
| 2786 | } | ||
| 2787 | |||
| 2788 | } else if (!enable && regulator->bypass) { | ||
| 2789 | rdev->bypass_count--; | ||
| 2790 | |||
| 2791 | if (rdev->bypass_count != rdev->open_count) { | ||
| 2792 | ret = rdev->desc->ops->set_bypass(rdev, enable); | ||
| 2793 | if (ret != 0) | ||
| 2794 | rdev->bypass_count++; | ||
| 2795 | } | ||
| 2796 | } | ||
| 2797 | |||
| 2798 | if (ret == 0) | ||
| 2799 | regulator->bypass = enable; | ||
| 2800 | |||
| 2801 | mutex_unlock(&rdev->mutex); | ||
| 2802 | |||
| 2803 | return ret; | ||
| 2804 | } | ||
| 2805 | EXPORT_SYMBOL_GPL(regulator_allow_bypass); | ||
| 2806 | |||
| 2807 | /** | ||
| 2677 | * regulator_register_notifier - register regulator event notifier | 2808 | * regulator_register_notifier - register regulator event notifier |
| 2678 | * @regulator: regulator source | 2809 | * @regulator: regulator source |
| 2679 | * @nb: notifier block | 2810 | * @nb: notifier block |
| @@ -3011,7 +3142,8 @@ static int add_regulator_attributes(struct regulator_dev *rdev) | |||
| 3011 | 3142 | ||
| 3012 | /* some attributes need specific methods to be displayed */ | 3143 | /* some attributes need specific methods to be displayed */ |
| 3013 | if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || | 3144 | if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || |
| 3014 | (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0)) { | 3145 | (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) || |
| 3146 | (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0)) { | ||
| 3015 | status = device_create_file(dev, &dev_attr_microvolts); | 3147 | status = device_create_file(dev, &dev_attr_microvolts); |
| 3016 | if (status < 0) | 3148 | if (status < 0) |
| 3017 | return status; | 3149 | return status; |
| @@ -3036,6 +3168,11 @@ static int add_regulator_attributes(struct regulator_dev *rdev) | |||
| 3036 | if (status < 0) | 3168 | if (status < 0) |
| 3037 | return status; | 3169 | return status; |
| 3038 | } | 3170 | } |
| 3171 | if (ops->get_bypass) { | ||
| 3172 | status = device_create_file(dev, &dev_attr_bypass); | ||
| 3173 | if (status < 0) | ||
| 3174 | return status; | ||
| 3175 | } | ||
| 3039 | 3176 | ||
| 3040 | /* some attributes are type-specific */ | 3177 | /* some attributes are type-specific */ |
| 3041 | if (rdev->desc->type == REGULATOR_CURRENT) { | 3178 | if (rdev->desc->type == REGULATOR_CURRENT) { |
| @@ -3124,6 +3261,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) | |||
| 3124 | &rdev->use_count); | 3261 | &rdev->use_count); |
| 3125 | debugfs_create_u32("open_count", 0444, rdev->debugfs, | 3262 | debugfs_create_u32("open_count", 0444, rdev->debugfs, |
| 3126 | &rdev->open_count); | 3263 | &rdev->open_count); |
| 3264 | debugfs_create_u32("bypass_count", 0444, rdev->debugfs, | ||
| 3265 | &rdev->bypass_count); | ||
| 3127 | } | 3266 | } |
| 3128 | 3267 | ||
| 3129 | /** | 3268 | /** |
| @@ -3189,8 +3328,10 @@ regulator_register(const struct regulator_desc *regulator_desc, | |||
| 3189 | rdev->desc = regulator_desc; | 3328 | rdev->desc = regulator_desc; |
| 3190 | if (config->regmap) | 3329 | if (config->regmap) |
| 3191 | rdev->regmap = config->regmap; | 3330 | rdev->regmap = config->regmap; |
| 3192 | else | 3331 | else if (dev_get_regmap(dev, NULL)) |
| 3193 | rdev->regmap = dev_get_regmap(dev, NULL); | 3332 | rdev->regmap = dev_get_regmap(dev, NULL); |
| 3333 | else if (dev->parent) | ||
| 3334 | rdev->regmap = dev_get_regmap(dev->parent, NULL); | ||
| 3194 | INIT_LIST_HEAD(&rdev->consumer_list); | 3335 | INIT_LIST_HEAD(&rdev->consumer_list); |
| 3195 | INIT_LIST_HEAD(&rdev->list); | 3336 | INIT_LIST_HEAD(&rdev->list); |
| 3196 | BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); | 3337 | BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); |
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 903299cf15cf..27355b1199e5 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c | |||
| @@ -133,8 +133,8 @@ static int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA, | |||
| 133 | max_uA < da9052_current_limits[row][DA9052_MIN_UA]) | 133 | max_uA < da9052_current_limits[row][DA9052_MIN_UA]) |
| 134 | return -EINVAL; | 134 | return -EINVAL; |
| 135 | 135 | ||
| 136 | for (i = 0; i < DA9052_CURRENT_RANGE; i++) { | 136 | for (i = DA9052_CURRENT_RANGE - 1; i >= 0; i--) { |
| 137 | if (min_uA <= da9052_current_limits[row][i]) { | 137 | if (da9052_current_limits[row][i] <= max_uA) { |
| 138 | reg_val = i; | 138 | reg_val = i; |
| 139 | break; | 139 | break; |
| 140 | } | 140 | } |
diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c index 86f655c7f7a1..03a1d7c11ef2 100644 --- a/drivers/regulator/dummy.c +++ b/drivers/regulator/dummy.c | |||
| @@ -30,7 +30,7 @@ static struct regulator_init_data dummy_initdata; | |||
| 30 | static struct regulator_ops dummy_ops; | 30 | static struct regulator_ops dummy_ops; |
| 31 | 31 | ||
| 32 | static struct regulator_desc dummy_desc = { | 32 | static struct regulator_desc dummy_desc = { |
| 33 | .name = "dummy", | 33 | .name = "regulator-dummy", |
| 34 | .id = -1, | 34 | .id = -1, |
| 35 | .type = REGULATOR_VOLTAGE, | 35 | .type = REGULATOR_VOLTAGE, |
| 36 | .owner = THIS_MODULE, | 36 | .owner = THIS_MODULE, |
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c new file mode 100644 index 000000000000..339f4d732e97 --- /dev/null +++ b/drivers/regulator/fan53555.c | |||
| @@ -0,0 +1,322 @@ | |||
| 1 | /* | ||
| 2 | * FAN53555 Fairchild Digitally Programmable TinyBuck Regulator Driver. | ||
| 3 | * | ||
| 4 | * Supported Part Numbers: | ||
| 5 | * FAN53555UC00X/01X/03X/04X/05X | ||
| 6 | * | ||
| 7 | * Copyright (c) 2012 Marvell Technology Ltd. | ||
| 8 | * Yunfan Zhang <yfzhang@marvell.com> | ||
| 9 | * | ||
| 10 | * This package is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/param.h> | ||
| 17 | #include <linux/err.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <linux/regulator/driver.h> | ||
| 20 | #include <linux/regulator/machine.h> | ||
| 21 | #include <linux/i2c.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/regmap.h> | ||
| 24 | #include <linux/regulator/fan53555.h> | ||
| 25 | |||
| 26 | /* Voltage setting */ | ||
| 27 | #define FAN53555_VSEL0 0x00 | ||
| 28 | #define FAN53555_VSEL1 0x01 | ||
| 29 | /* Control register */ | ||
| 30 | #define FAN53555_CONTROL 0x02 | ||
| 31 | /* IC Type */ | ||
| 32 | #define FAN53555_ID1 0x03 | ||
| 33 | /* IC mask version */ | ||
| 34 | #define FAN53555_ID2 0x04 | ||
| 35 | /* Monitor register */ | ||
| 36 | #define FAN53555_MONITOR 0x05 | ||
| 37 | |||
| 38 | /* VSEL bit definitions */ | ||
| 39 | #define VSEL_BUCK_EN (1 << 7) | ||
| 40 | #define VSEL_MODE (1 << 6) | ||
| 41 | #define VSEL_NSEL_MASK 0x3F | ||
| 42 | /* Chip ID and Verison */ | ||
| 43 | #define DIE_ID 0x0F /* ID1 */ | ||
| 44 | #define DIE_REV 0x0F /* ID2 */ | ||
| 45 | /* Control bit definitions */ | ||
| 46 | #define CTL_OUTPUT_DISCHG (1 << 7) | ||
| 47 | #define CTL_SLEW_MASK (0x7 << 4) | ||
| 48 | #define CTL_SLEW_SHIFT 4 | ||
| 49 | #define CTL_RESET (1 << 2) | ||
| 50 | |||
| 51 | #define FAN53555_NVOLTAGES 64 /* Numbers of voltages */ | ||
| 52 | |||
| 53 | /* IC Type */ | ||
| 54 | enum { | ||
| 55 | FAN53555_CHIP_ID_00 = 0, | ||
| 56 | FAN53555_CHIP_ID_01, | ||
| 57 | FAN53555_CHIP_ID_02, | ||
| 58 | FAN53555_CHIP_ID_03, | ||
| 59 | FAN53555_CHIP_ID_04, | ||
| 60 | FAN53555_CHIP_ID_05, | ||
| 61 | }; | ||
| 62 | |||
| 63 | struct fan53555_device_info { | ||
| 64 | struct regmap *regmap; | ||
| 65 | struct device *dev; | ||
| 66 | struct regulator_desc desc; | ||
| 67 | struct regulator_dev *rdev; | ||
| 68 | struct regulator_init_data *regulator; | ||
| 69 | /* IC Type and Rev */ | ||
| 70 | int chip_id; | ||
| 71 | int chip_rev; | ||
| 72 | /* Voltage setting register */ | ||
| 73 | unsigned int vol_reg; | ||
| 74 | unsigned int sleep_reg; | ||
| 75 | /* Voltage range and step(linear) */ | ||
| 76 | unsigned int vsel_min; | ||
| 77 | unsigned int vsel_step; | ||
| 78 | /* Voltage slew rate limiting */ | ||
| 79 | unsigned int slew_rate; | ||
| 80 | /* Sleep voltage cache */ | ||
| 81 | unsigned int sleep_vol_cache; | ||
| 82 | }; | ||
| 83 | |||
| 84 | static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) | ||
| 85 | { | ||
| 86 | struct fan53555_device_info *di = rdev_get_drvdata(rdev); | ||
| 87 | int ret; | ||
| 88 | |||
| 89 | if (di->sleep_vol_cache == uV) | ||
| 90 | return 0; | ||
| 91 | ret = regulator_map_voltage_linear(rdev, uV, uV); | ||
| 92 | if (ret < 0) | ||
| 93 | return -EINVAL; | ||
| 94 | ret = regmap_update_bits(di->regmap, di->sleep_reg, | ||
| 95 | VSEL_NSEL_MASK, ret); | ||
| 96 | if (ret < 0) | ||
| 97 | return -EINVAL; | ||
| 98 | /* Cache the sleep voltage setting. | ||
| 99 | * Might not be the real voltage which is rounded */ | ||
| 100 | di->sleep_vol_cache = uV; | ||
| 101 | |||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode) | ||
| 106 | { | ||
| 107 | struct fan53555_device_info *di = rdev_get_drvdata(rdev); | ||
| 108 | |||
| 109 | switch (mode) { | ||
| 110 | case REGULATOR_MODE_FAST: | ||
| 111 | regmap_update_bits(di->regmap, di->vol_reg, | ||
| 112 | VSEL_MODE, VSEL_MODE); | ||
| 113 | break; | ||
| 114 | case REGULATOR_MODE_NORMAL: | ||
| 115 | regmap_update_bits(di->regmap, di->vol_reg, VSEL_MODE, 0); | ||
| 116 | break; | ||
| 117 | default: | ||
| 118 | return -EINVAL; | ||
| 119 | } | ||
| 120 | return 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | static unsigned int fan53555_get_mode(struct regulator_dev *rdev) | ||
| 124 | { | ||
| 125 | struct fan53555_device_info *di = rdev_get_drvdata(rdev); | ||
| 126 | unsigned int val; | ||
| 127 | int ret = 0; | ||
| 128 | |||
| 129 | ret = regmap_read(di->regmap, di->vol_reg, &val); | ||
| 130 | if (ret < 0) | ||
| 131 | return ret; | ||
| 132 | if (val & VSEL_MODE) | ||
| 133 | return REGULATOR_MODE_FAST; | ||
| 134 | else | ||
| 135 | return REGULATOR_MODE_NORMAL; | ||
| 136 | } | ||
| 137 | |||
| 138 | static struct regulator_ops fan53555_regulator_ops = { | ||
| 139 | .set_voltage_sel = regulator_set_voltage_sel_regmap, | ||
| 140 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | ||
| 141 | .map_voltage = regulator_map_voltage_linear, | ||
| 142 | .list_voltage = regulator_list_voltage_linear, | ||
| 143 | .set_suspend_voltage = fan53555_set_suspend_voltage, | ||
| 144 | .enable = regulator_enable_regmap, | ||
| 145 | .disable = regulator_disable_regmap, | ||
| 146 | .is_enabled = regulator_is_enabled_regmap, | ||
| 147 | .set_mode = fan53555_set_mode, | ||
| 148 | .get_mode = fan53555_get_mode, | ||
| 149 | }; | ||
| 150 | |||
| 151 | /* For 00,01,03,05 options: | ||
| 152 | * VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V. | ||
| 153 | * For 04 option: | ||
| 154 | * VOUT = 0.603V + NSELx * 12.826mV, from 0.603 to 1.411V. | ||
| 155 | * */ | ||
| 156 | static int fan53555_device_setup(struct fan53555_device_info *di, | ||
| 157 | struct fan53555_platform_data *pdata) | ||
| 158 | { | ||
| 159 | unsigned int reg, data, mask; | ||
| 160 | |||
| 161 | /* Setup voltage control register */ | ||
| 162 | switch (pdata->sleep_vsel_id) { | ||
| 163 | case FAN53555_VSEL_ID_0: | ||
| 164 | di->sleep_reg = FAN53555_VSEL0; | ||
| 165 | di->vol_reg = FAN53555_VSEL1; | ||
| 166 | break; | ||
| 167 | case FAN53555_VSEL_ID_1: | ||
| 168 | di->sleep_reg = FAN53555_VSEL1; | ||
| 169 | di->vol_reg = FAN53555_VSEL0; | ||
| 170 | break; | ||
| 171 | default: | ||
| 172 | dev_err(di->dev, "Invalid VSEL ID!\n"); | ||
| 173 | return -EINVAL; | ||
| 174 | } | ||
| 175 | /* Init voltage range and step */ | ||
| 176 | switch (di->chip_id) { | ||
| 177 | case FAN53555_CHIP_ID_00: | ||
| 178 | case FAN53555_CHIP_ID_01: | ||
| 179 | case FAN53555_CHIP_ID_03: | ||
| 180 | case FAN53555_CHIP_ID_05: | ||
| 181 | di->vsel_min = 600000; | ||
| 182 | di->vsel_step = 10000; | ||
| 183 | break; | ||
| 184 | case FAN53555_CHIP_ID_04: | ||
| 185 | di->vsel_min = 603000; | ||
| 186 | di->vsel_step = 12826; | ||
| 187 | break; | ||
| 188 | default: | ||
| 189 | dev_err(di->dev, | ||
| 190 | "Chip ID[%d]\n not supported!\n", di->chip_id); | ||
| 191 | return -EINVAL; | ||
| 192 | } | ||
| 193 | /* Init slew rate */ | ||
| 194 | if (pdata->slew_rate & 0x7) | ||
| 195 | di->slew_rate = pdata->slew_rate; | ||
| 196 | else | ||
| 197 | di->slew_rate = FAN53555_SLEW_RATE_64MV; | ||
| 198 | reg = FAN53555_CONTROL; | ||
| 199 | data = di->slew_rate << CTL_SLEW_SHIFT; | ||
| 200 | mask = CTL_SLEW_MASK; | ||
| 201 | return regmap_update_bits(di->regmap, reg, mask, data); | ||
| 202 | } | ||
| 203 | |||
| 204 | static int fan53555_regulator_register(struct fan53555_device_info *di, | ||
| 205 | struct regulator_config *config) | ||
| 206 | { | ||
| 207 | struct regulator_desc *rdesc = &di->desc; | ||
| 208 | |||
| 209 | rdesc->name = "fan53555-reg"; | ||
| 210 | rdesc->ops = &fan53555_regulator_ops; | ||
| 211 | rdesc->type = REGULATOR_VOLTAGE; | ||
| 212 | rdesc->n_voltages = FAN53555_NVOLTAGES; | ||
| 213 | rdesc->enable_reg = di->vol_reg; | ||
| 214 | rdesc->enable_mask = VSEL_BUCK_EN; | ||
| 215 | rdesc->min_uV = di->vsel_min; | ||
| 216 | rdesc->uV_step = di->vsel_step; | ||
| 217 | rdesc->vsel_reg = di->vol_reg; | ||
| 218 | rdesc->vsel_mask = VSEL_NSEL_MASK; | ||
| 219 | rdesc->owner = THIS_MODULE; | ||
| 220 | |||
| 221 | di->rdev = regulator_register(&di->desc, config); | ||
| 222 | if (IS_ERR(di->rdev)) | ||
| 223 | return PTR_ERR(di->rdev); | ||
| 224 | return 0; | ||
| 225 | |||
| 226 | } | ||
| 227 | |||
| 228 | static struct regmap_config fan53555_regmap_config = { | ||
| 229 | .reg_bits = 8, | ||
| 230 | .val_bits = 8, | ||
| 231 | }; | ||
| 232 | |||
| 233 | static int __devinit fan53555_regulator_probe(struct i2c_client *client, | ||
| 234 | const struct i2c_device_id *id) | ||
| 235 | { | ||
| 236 | struct fan53555_device_info *di; | ||
| 237 | struct fan53555_platform_data *pdata; | ||
| 238 | struct regulator_config config = { }; | ||
| 239 | unsigned int val; | ||
| 240 | int ret; | ||
| 241 | |||
| 242 | pdata = client->dev.platform_data; | ||
| 243 | if (!pdata || !pdata->regulator) { | ||
| 244 | dev_err(&client->dev, "Platform data not found!\n"); | ||
| 245 | return -ENODEV; | ||
| 246 | } | ||
| 247 | |||
| 248 | di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info), | ||
| 249 | GFP_KERNEL); | ||
| 250 | if (!di) { | ||
| 251 | dev_err(&client->dev, "Failed to allocate device info data!\n"); | ||
| 252 | return -ENOMEM; | ||
| 253 | } | ||
| 254 | di->regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config); | ||
| 255 | if (IS_ERR(di->regmap)) { | ||
| 256 | dev_err(&client->dev, "Failed to allocate regmap!\n"); | ||
| 257 | return PTR_ERR(di->regmap); | ||
| 258 | } | ||
| 259 | di->dev = &client->dev; | ||
| 260 | di->regulator = pdata->regulator; | ||
| 261 | i2c_set_clientdata(client, di); | ||
| 262 | /* Get chip ID */ | ||
| 263 | ret = regmap_read(di->regmap, FAN53555_ID1, &val); | ||
| 264 | if (ret < 0) { | ||
| 265 | dev_err(&client->dev, "Failed to get chip ID!\n"); | ||
| 266 | return -ENODEV; | ||
| 267 | } | ||
| 268 | di->chip_id = val & DIE_ID; | ||
| 269 | /* Get chip revision */ | ||
| 270 | ret = regmap_read(di->regmap, FAN53555_ID2, &val); | ||
| 271 | if (ret < 0) { | ||
| 272 | dev_err(&client->dev, "Failed to get chip Rev!\n"); | ||
| 273 | return -ENODEV; | ||
| 274 | } | ||
| 275 | di->chip_rev = val & DIE_REV; | ||
| 276 | dev_info(&client->dev, "FAN53555 Option[%d] Rev[%d] Detected!\n", | ||
| 277 | di->chip_id, di->chip_rev); | ||
| 278 | /* Device init */ | ||
| 279 | ret = fan53555_device_setup(di, pdata); | ||
| 280 | if (ret < 0) { | ||
| 281 | dev_err(&client->dev, "Failed to setup device!\n"); | ||
| 282 | return ret; | ||
| 283 | } | ||
| 284 | /* Register regulator */ | ||
| 285 | config.dev = di->dev; | ||
| 286 | config.init_data = di->regulator; | ||
| 287 | config.regmap = di->regmap; | ||
| 288 | config.driver_data = di; | ||
| 289 | ret = fan53555_regulator_register(di, &config); | ||
| 290 | if (ret < 0) | ||
| 291 | dev_err(&client->dev, "Failed to register regulator!\n"); | ||
| 292 | return ret; | ||
| 293 | |||
| 294 | } | ||
| 295 | |||
| 296 | static int __devexit fan53555_regulator_remove(struct i2c_client *client) | ||
| 297 | { | ||
| 298 | struct fan53555_device_info *di = i2c_get_clientdata(client); | ||
| 299 | |||
| 300 | regulator_unregister(di->rdev); | ||
| 301 | return 0; | ||
| 302 | } | ||
| 303 | |||
| 304 | static const struct i2c_device_id fan53555_id[] = { | ||
| 305 | {"fan53555", -1}, | ||
| 306 | { }, | ||
| 307 | }; | ||
| 308 | |||
| 309 | static struct i2c_driver fan53555_regulator_driver = { | ||
| 310 | .driver = { | ||
| 311 | .name = "fan53555-regulator", | ||
| 312 | }, | ||
| 313 | .probe = fan53555_regulator_probe, | ||
| 314 | .remove = __devexit_p(fan53555_regulator_remove), | ||
| 315 | .id_table = fan53555_id, | ||
| 316 | }; | ||
| 317 | |||
| 318 | module_i2c_driver(fan53555_regulator_driver); | ||
| 319 | |||
| 320 | MODULE_AUTHOR("Yunfan Zhang <yfzhang@marvell.com>"); | ||
| 321 | MODULE_DESCRIPTION("FAN53555 regulator driver"); | ||
| 322 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index 1d145a07ada9..d8ecf49a5777 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c | |||
| @@ -73,13 +73,7 @@ static struct regulator_ops isl_core_ops = { | |||
| 73 | .map_voltage = regulator_map_voltage_linear, | 73 | .map_voltage = regulator_map_voltage_linear, |
| 74 | }; | 74 | }; |
| 75 | 75 | ||
| 76 | static int isl6271a_get_fixed_voltage(struct regulator_dev *dev) | ||
| 77 | { | ||
| 78 | return dev->desc->min_uV; | ||
| 79 | } | ||
| 80 | |||
| 81 | static struct regulator_ops isl_fixed_ops = { | 76 | static struct regulator_ops isl_fixed_ops = { |
| 82 | .get_voltage = isl6271a_get_fixed_voltage, | ||
| 83 | .list_voltage = regulator_list_voltage_linear, | 77 | .list_voltage = regulator_list_voltage_linear, |
| 84 | }; | 78 | }; |
| 85 | 79 | ||
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 212c38eaba70..708f4b6a17dc 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c | |||
| @@ -86,6 +86,10 @@ | |||
| 86 | #define EXTERN_DVS_USED 0 | 86 | #define EXTERN_DVS_USED 0 |
| 87 | #define MAX_DELAY 6 | 87 | #define MAX_DELAY 6 |
| 88 | 88 | ||
| 89 | /* Default DVS Mode */ | ||
| 90 | #define LP8720_DEFAULT_DVS 0 | ||
| 91 | #define LP8725_DEFAULT_DVS BIT(2) | ||
| 92 | |||
| 89 | /* dump registers in regmap-debugfs */ | 93 | /* dump registers in regmap-debugfs */ |
| 90 | #define MAX_REGISTERS 0x0F | 94 | #define MAX_REGISTERS 0x0F |
| 91 | 95 | ||
| @@ -269,9 +273,9 @@ static int lp872x_regulator_enable_time(struct regulator_dev *rdev) | |||
| 269 | return val > MAX_DELAY ? 0 : val * time_step_us; | 273 | return val > MAX_DELAY ? 0 : val * time_step_us; |
| 270 | } | 274 | } |
| 271 | 275 | ||
| 272 | static void lp872x_set_dvs(struct lp872x *lp, int gpio) | 276 | static void lp872x_set_dvs(struct lp872x *lp, enum lp872x_dvs_sel dvs_sel, |
| 277 | int gpio) | ||
| 273 | { | 278 | { |
| 274 | enum lp872x_dvs_sel dvs_sel = lp->pdata->dvs->vsel; | ||
| 275 | enum lp872x_dvs_state state; | 279 | enum lp872x_dvs_state state; |
| 276 | 280 | ||
| 277 | state = dvs_sel == SEL_V1 ? DVS_HIGH : DVS_LOW; | 281 | state = dvs_sel == SEL_V1 ? DVS_HIGH : DVS_LOW; |
| @@ -339,10 +343,10 @@ static int lp872x_buck_set_voltage_sel(struct regulator_dev *rdev, | |||
| 339 | struct lp872x *lp = rdev_get_drvdata(rdev); | 343 | struct lp872x *lp = rdev_get_drvdata(rdev); |
| 340 | enum lp872x_regulator_id buck = rdev_get_id(rdev); | 344 | enum lp872x_regulator_id buck = rdev_get_id(rdev); |
| 341 | u8 addr, mask = LP872X_VOUT_M; | 345 | u8 addr, mask = LP872X_VOUT_M; |
| 342 | struct lp872x_dvs *dvs = lp->pdata->dvs; | 346 | struct lp872x_dvs *dvs = lp->pdata ? lp->pdata->dvs : NULL; |
| 343 | 347 | ||
| 344 | if (dvs && gpio_is_valid(dvs->gpio)) | 348 | if (dvs && gpio_is_valid(dvs->gpio)) |
| 345 | lp872x_set_dvs(lp, dvs->gpio); | 349 | lp872x_set_dvs(lp, dvs->vsel, dvs->gpio); |
| 346 | 350 | ||
| 347 | addr = lp872x_select_buck_vout_addr(lp, buck); | 351 | addr = lp872x_select_buck_vout_addr(lp, buck); |
| 348 | if (!lp872x_is_valid_buck_addr(addr)) | 352 | if (!lp872x_is_valid_buck_addr(addr)) |
| @@ -374,8 +378,8 @@ static int lp8725_buck_set_current_limit(struct regulator_dev *rdev, | |||
| 374 | { | 378 | { |
| 375 | struct lp872x *lp = rdev_get_drvdata(rdev); | 379 | struct lp872x *lp = rdev_get_drvdata(rdev); |
| 376 | enum lp872x_regulator_id buck = rdev_get_id(rdev); | 380 | enum lp872x_regulator_id buck = rdev_get_id(rdev); |
| 377 | int i, max = ARRAY_SIZE(lp8725_buck_uA); | 381 | int i; |
| 378 | u8 addr, val; | 382 | u8 addr; |
| 379 | 383 | ||
| 380 | switch (buck) { | 384 | switch (buck) { |
| 381 | case LP8725_ID_BUCK1: | 385 | case LP8725_ID_BUCK1: |
| @@ -388,17 +392,15 @@ static int lp8725_buck_set_current_limit(struct regulator_dev *rdev, | |||
| 388 | return -EINVAL; | 392 | return -EINVAL; |
| 389 | } | 393 | } |
| 390 | 394 | ||
| 391 | for (i = 0 ; i < max ; i++) | 395 | for (i = ARRAY_SIZE(lp8725_buck_uA) - 1 ; i >= 0; i--) { |
| 392 | if (lp8725_buck_uA[i] >= min_uA && | 396 | if (lp8725_buck_uA[i] >= min_uA && |
| 393 | lp8725_buck_uA[i] <= max_uA) | 397 | lp8725_buck_uA[i] <= max_uA) |
| 394 | break; | 398 | return lp872x_update_bits(lp, addr, |
| 395 | 399 | LP8725_BUCK_CL_M, | |
| 396 | if (i == max) | 400 | i << LP8725_BUCK_CL_S); |
| 397 | return -EINVAL; | 401 | } |
| 398 | |||
| 399 | val = i << LP8725_BUCK_CL_S; | ||
| 400 | 402 | ||
| 401 | return lp872x_update_bits(lp, addr, LP8725_BUCK_CL_M, val); | 403 | return -EINVAL; |
| 402 | } | 404 | } |
| 403 | 405 | ||
| 404 | static int lp8725_buck_get_current_limit(struct regulator_dev *rdev) | 406 | static int lp8725_buck_get_current_limit(struct regulator_dev *rdev) |
| @@ -727,39 +729,16 @@ static struct regulator_desc lp8725_regulator_desc[] = { | |||
| 727 | }, | 729 | }, |
| 728 | }; | 730 | }; |
| 729 | 731 | ||
| 730 | static int lp872x_check_dvs_validity(struct lp872x *lp) | ||
| 731 | { | ||
| 732 | struct lp872x_dvs *dvs = lp->pdata->dvs; | ||
| 733 | u8 val = 0; | ||
| 734 | int ret; | ||
| 735 | |||
| 736 | ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val); | ||
| 737 | if (ret) | ||
| 738 | return ret; | ||
| 739 | |||
| 740 | ret = 0; | ||
| 741 | if (lp->chipid == LP8720) { | ||
| 742 | if (val & LP8720_EXT_DVS_M) | ||
| 743 | ret = dvs ? 0 : -EINVAL; | ||
| 744 | } else { | ||
| 745 | if ((val & LP8725_DVS1_M) == EXTERN_DVS_USED) | ||
| 746 | ret = dvs ? 0 : -EINVAL; | ||
| 747 | } | ||
| 748 | |||
| 749 | return ret; | ||
| 750 | } | ||
| 751 | |||
| 752 | static int lp872x_init_dvs(struct lp872x *lp) | 732 | static int lp872x_init_dvs(struct lp872x *lp) |
| 753 | { | 733 | { |
| 754 | int ret, gpio; | 734 | int ret, gpio; |
| 755 | struct lp872x_dvs *dvs = lp->pdata->dvs; | 735 | struct lp872x_dvs *dvs = lp->pdata ? lp->pdata->dvs : NULL; |
| 756 | enum lp872x_dvs_state pinstate; | 736 | enum lp872x_dvs_state pinstate; |
| 737 | u8 mask[] = { LP8720_EXT_DVS_M, LP8725_DVS1_M | LP8725_DVS2_M }; | ||
| 738 | u8 default_dvs_mode[] = { LP8720_DEFAULT_DVS, LP8725_DEFAULT_DVS }; | ||
| 757 | 739 | ||
| 758 | ret = lp872x_check_dvs_validity(lp); | 740 | if (!dvs) |
| 759 | if (ret) { | 741 | goto set_default_dvs_mode; |
| 760 | dev_warn(lp->dev, "invalid dvs data: %d\n", ret); | ||
| 761 | return ret; | ||
| 762 | } | ||
| 763 | 742 | ||
| 764 | gpio = dvs->gpio; | 743 | gpio = dvs->gpio; |
| 765 | if (!gpio_is_valid(gpio)) { | 744 | if (!gpio_is_valid(gpio)) { |
| @@ -778,6 +757,10 @@ static int lp872x_init_dvs(struct lp872x *lp) | |||
| 778 | lp->dvs_gpio = gpio; | 757 | lp->dvs_gpio = gpio; |
| 779 | 758 | ||
| 780 | return 0; | 759 | return 0; |
| 760 | |||
| 761 | set_default_dvs_mode: | ||
| 762 | return lp872x_update_bits(lp, LP872X_GENERAL_CFG, mask[lp->chipid], | ||
| 763 | default_dvs_mode[lp->chipid]); | ||
| 781 | } | 764 | } |
| 782 | 765 | ||
| 783 | static int lp872x_config(struct lp872x *lp) | 766 | static int lp872x_config(struct lp872x *lp) |
| @@ -785,24 +768,29 @@ static int lp872x_config(struct lp872x *lp) | |||
| 785 | struct lp872x_platform_data *pdata = lp->pdata; | 768 | struct lp872x_platform_data *pdata = lp->pdata; |
| 786 | int ret; | 769 | int ret; |
| 787 | 770 | ||
| 788 | if (!pdata->update_config) | 771 | if (!pdata || !pdata->update_config) |
| 789 | return 0; | 772 | goto init_dvs; |
| 790 | 773 | ||
| 791 | ret = lp872x_write_byte(lp, LP872X_GENERAL_CFG, pdata->general_config); | 774 | ret = lp872x_write_byte(lp, LP872X_GENERAL_CFG, pdata->general_config); |
| 792 | if (ret) | 775 | if (ret) |
| 793 | return ret; | 776 | return ret; |
| 794 | 777 | ||
| 778 | init_dvs: | ||
| 795 | return lp872x_init_dvs(lp); | 779 | return lp872x_init_dvs(lp); |
| 796 | } | 780 | } |
| 797 | 781 | ||
| 798 | static struct regulator_init_data | 782 | static struct regulator_init_data |
| 799 | *lp872x_find_regulator_init_data(int id, struct lp872x *lp) | 783 | *lp872x_find_regulator_init_data(int id, struct lp872x *lp) |
| 800 | { | 784 | { |
| 785 | struct lp872x_platform_data *pdata = lp->pdata; | ||
| 801 | int i; | 786 | int i; |
| 802 | 787 | ||
| 788 | if (!pdata) | ||
| 789 | return NULL; | ||
| 790 | |||
| 803 | for (i = 0; i < lp->num_regulators; i++) { | 791 | for (i = 0; i < lp->num_regulators; i++) { |
| 804 | if (lp->pdata->regulator_data[i].id == id) | 792 | if (pdata->regulator_data[i].id == id) |
| 805 | return lp->pdata->regulator_data[i].init_data; | 793 | return pdata->regulator_data[i].init_data; |
| 806 | } | 794 | } |
| 807 | 795 | ||
| 808 | return NULL; | 796 | return NULL; |
| @@ -863,18 +851,12 @@ static const struct regmap_config lp872x_regmap_config = { | |||
| 863 | static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id) | 851 | static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id) |
| 864 | { | 852 | { |
| 865 | struct lp872x *lp; | 853 | struct lp872x *lp; |
| 866 | struct lp872x_platform_data *pdata = cl->dev.platform_data; | ||
| 867 | int ret, size, num_regulators; | 854 | int ret, size, num_regulators; |
| 868 | const int lp872x_num_regulators[] = { | 855 | const int lp872x_num_regulators[] = { |
| 869 | [LP8720] = LP8720_NUM_REGULATORS, | 856 | [LP8720] = LP8720_NUM_REGULATORS, |
| 870 | [LP8725] = LP8725_NUM_REGULATORS, | 857 | [LP8725] = LP8725_NUM_REGULATORS, |
| 871 | }; | 858 | }; |
| 872 | 859 | ||
| 873 | if (!pdata) { | ||
| 874 | dev_err(&cl->dev, "no platform data\n"); | ||
| 875 | return -EINVAL; | ||
| 876 | } | ||
| 877 | |||
| 878 | lp = devm_kzalloc(&cl->dev, sizeof(struct lp872x), GFP_KERNEL); | 860 | lp = devm_kzalloc(&cl->dev, sizeof(struct lp872x), GFP_KERNEL); |
| 879 | if (!lp) | 861 | if (!lp) |
| 880 | goto err_mem; | 862 | goto err_mem; |
| @@ -894,7 +876,7 @@ static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id) | |||
| 894 | } | 876 | } |
| 895 | 877 | ||
| 896 | lp->dev = &cl->dev; | 878 | lp->dev = &cl->dev; |
| 897 | lp->pdata = pdata; | 879 | lp->pdata = cl->dev.platform_data; |
| 898 | lp->chipid = id->driver_data; | 880 | lp->chipid = id->driver_data; |
| 899 | lp->num_regulators = num_regulators; | 881 | lp->num_regulators = num_regulators; |
| 900 | i2c_set_clientdata(cl, lp); | 882 | i2c_set_clientdata(cl, lp); |
diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c index 6356e821400f..ba3e0aa402de 100644 --- a/drivers/regulator/lp8788-buck.c +++ b/drivers/regulator/lp8788-buck.c | |||
| @@ -69,6 +69,9 @@ | |||
| 69 | #define PIN_HIGH 1 | 69 | #define PIN_HIGH 1 |
| 70 | #define ENABLE_TIME_USEC 32 | 70 | #define ENABLE_TIME_USEC 32 |
| 71 | 71 | ||
| 72 | #define BUCK_FPWM_MASK(x) (1 << (x)) | ||
| 73 | #define BUCK_FPWM_SHIFT(x) (x) | ||
| 74 | |||
| 72 | enum lp8788_dvs_state { | 75 | enum lp8788_dvs_state { |
| 73 | DVS_LOW = GPIOF_OUT_INIT_LOW, | 76 | DVS_LOW = GPIOF_OUT_INIT_LOW, |
| 74 | DVS_HIGH = GPIOF_OUT_INIT_HIGH, | 77 | DVS_HIGH = GPIOF_OUT_INIT_HIGH, |
| @@ -86,15 +89,9 @@ enum lp8788_buck_id { | |||
| 86 | BUCK4, | 89 | BUCK4, |
| 87 | }; | 90 | }; |
| 88 | 91 | ||
| 89 | struct lp8788_pwm_map { | ||
| 90 | u8 mask; | ||
| 91 | u8 shift; | ||
| 92 | }; | ||
| 93 | |||
| 94 | struct lp8788_buck { | 92 | struct lp8788_buck { |
| 95 | struct lp8788 *lp; | 93 | struct lp8788 *lp; |
| 96 | struct regulator_dev *regulator; | 94 | struct regulator_dev *regulator; |
| 97 | struct lp8788_pwm_map *pmap; | ||
| 98 | void *dvs; | 95 | void *dvs; |
| 99 | }; | 96 | }; |
| 100 | 97 | ||
| @@ -106,29 +103,6 @@ static const int lp8788_buck_vtbl[] = { | |||
| 106 | 1950000, 2000000, | 103 | 1950000, 2000000, |
| 107 | }; | 104 | }; |
| 108 | 105 | ||
| 109 | /* buck pwm mode selection : used for set/get_mode in regulator ops | ||
| 110 | * @forced pwm : fast mode | ||
| 111 | * @auto pwm : normal mode | ||
| 112 | */ | ||
| 113 | static struct lp8788_pwm_map buck_pmap[] = { | ||
| 114 | [BUCK1] = { | ||
| 115 | .mask = LP8788_FPWM_BUCK1_M, | ||
| 116 | .shift = LP8788_FPWM_BUCK1_S, | ||
| 117 | }, | ||
| 118 | [BUCK2] = { | ||
| 119 | .mask = LP8788_FPWM_BUCK2_M, | ||
| 120 | .shift = LP8788_FPWM_BUCK2_S, | ||
| 121 | }, | ||
| 122 | [BUCK3] = { | ||
| 123 | .mask = LP8788_FPWM_BUCK3_M, | ||
| 124 | .shift = LP8788_FPWM_BUCK3_S, | ||
| 125 | }, | ||
| 126 | [BUCK4] = { | ||
| 127 | .mask = LP8788_FPWM_BUCK4_M, | ||
| 128 | .shift = LP8788_FPWM_BUCK4_S, | ||
| 129 | }, | ||
| 130 | }; | ||
| 131 | |||
| 132 | static const u8 buck1_vout_addr[] = { | 106 | static const u8 buck1_vout_addr[] = { |
| 133 | LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1, | 107 | LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1, |
| 134 | LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3, | 108 | LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3, |
| @@ -347,41 +321,37 @@ static int lp8788_buck_enable_time(struct regulator_dev *rdev) | |||
| 347 | static int lp8788_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) | 321 | static int lp8788_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) |
| 348 | { | 322 | { |
| 349 | struct lp8788_buck *buck = rdev_get_drvdata(rdev); | 323 | struct lp8788_buck *buck = rdev_get_drvdata(rdev); |
| 350 | struct lp8788_pwm_map *pmap = buck->pmap; | 324 | enum lp8788_buck_id id = rdev_get_id(rdev); |
| 351 | u8 val; | 325 | u8 mask, val; |
| 352 | |||
| 353 | if (!pmap) | ||
| 354 | return -EINVAL; | ||
| 355 | 326 | ||
| 327 | mask = BUCK_FPWM_MASK(id); | ||
| 356 | switch (mode) { | 328 | switch (mode) { |
| 357 | case REGULATOR_MODE_FAST: | 329 | case REGULATOR_MODE_FAST: |
| 358 | val = LP8788_FORCE_PWM << pmap->shift; | 330 | val = LP8788_FORCE_PWM << BUCK_FPWM_SHIFT(id); |
| 359 | break; | 331 | break; |
| 360 | case REGULATOR_MODE_NORMAL: | 332 | case REGULATOR_MODE_NORMAL: |
| 361 | val = LP8788_AUTO_PWM << pmap->shift; | 333 | val = LP8788_AUTO_PWM << BUCK_FPWM_SHIFT(id); |
| 362 | break; | 334 | break; |
| 363 | default: | 335 | default: |
| 364 | return -EINVAL; | 336 | return -EINVAL; |
| 365 | } | 337 | } |
| 366 | 338 | ||
| 367 | return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, pmap->mask, val); | 339 | return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, mask, val); |
| 368 | } | 340 | } |
| 369 | 341 | ||
| 370 | static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev) | 342 | static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev) |
| 371 | { | 343 | { |
| 372 | struct lp8788_buck *buck = rdev_get_drvdata(rdev); | 344 | struct lp8788_buck *buck = rdev_get_drvdata(rdev); |
| 373 | struct lp8788_pwm_map *pmap = buck->pmap; | 345 | enum lp8788_buck_id id = rdev_get_id(rdev); |
| 374 | u8 val; | 346 | u8 val; |
| 375 | int ret; | 347 | int ret; |
| 376 | 348 | ||
| 377 | if (!pmap) | ||
| 378 | return -EINVAL; | ||
| 379 | |||
| 380 | ret = lp8788_read_byte(buck->lp, LP8788_BUCK_PWM, &val); | 349 | ret = lp8788_read_byte(buck->lp, LP8788_BUCK_PWM, &val); |
| 381 | if (ret) | 350 | if (ret) |
| 382 | return ret; | 351 | return ret; |
| 383 | 352 | ||
| 384 | return val & pmap->mask ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; | 353 | return val & BUCK_FPWM_MASK(id) ? |
| 354 | REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; | ||
| 385 | } | 355 | } |
| 386 | 356 | ||
| 387 | static struct regulator_ops lp8788_buck12_ops = { | 357 | static struct regulator_ops lp8788_buck12_ops = { |
| @@ -459,27 +429,6 @@ static struct regulator_desc lp8788_buck_desc[] = { | |||
| 459 | }, | 429 | }, |
| 460 | }; | 430 | }; |
| 461 | 431 | ||
| 462 | static int lp8788_set_default_dvs_ctrl_mode(struct lp8788 *lp, | ||
| 463 | enum lp8788_buck_id id) | ||
| 464 | { | ||
| 465 | u8 mask, val; | ||
| 466 | |||
| 467 | switch (id) { | ||
| 468 | case BUCK1: | ||
| 469 | mask = LP8788_BUCK1_DVS_SEL_M; | ||
| 470 | val = LP8788_BUCK1_DVS_I2C; | ||
| 471 | break; | ||
| 472 | case BUCK2: | ||
| 473 | mask = LP8788_BUCK2_DVS_SEL_M; | ||
| 474 | val = LP8788_BUCK2_DVS_I2C; | ||
| 475 | break; | ||
| 476 | default: | ||
| 477 | return 0; | ||
| 478 | } | ||
| 479 | |||
| 480 | return lp8788_update_bits(lp, LP8788_BUCK_DVS_SEL, mask, val); | ||
| 481 | } | ||
| 482 | |||
| 483 | static int _gpio_request(struct lp8788_buck *buck, int gpio, char *name) | 432 | static int _gpio_request(struct lp8788_buck *buck, int gpio, char *name) |
| 484 | { | 433 | { |
| 485 | struct device *dev = buck->lp->dev; | 434 | struct device *dev = buck->lp->dev; |
| @@ -530,6 +479,7 @@ static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id) | |||
| 530 | struct lp8788_platform_data *pdata = buck->lp->pdata; | 479 | struct lp8788_platform_data *pdata = buck->lp->pdata; |
| 531 | u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M }; | 480 | u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M }; |
| 532 | u8 val[] = { LP8788_BUCK1_DVS_PIN, LP8788_BUCK2_DVS_PIN }; | 481 | u8 val[] = { LP8788_BUCK1_DVS_PIN, LP8788_BUCK2_DVS_PIN }; |
| 482 | u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C }; | ||
| 533 | 483 | ||
| 534 | /* no dvs for buck3, 4 */ | 484 | /* no dvs for buck3, 4 */ |
| 535 | if (id == BUCK3 || id == BUCK4) | 485 | if (id == BUCK3 || id == BUCK4) |
| @@ -550,7 +500,8 @@ static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id) | |||
| 550 | val[id]); | 500 | val[id]); |
| 551 | 501 | ||
| 552 | set_default_dvs_mode: | 502 | set_default_dvs_mode: |
| 553 | return lp8788_set_default_dvs_ctrl_mode(buck->lp, id); | 503 | return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id], |
| 504 | default_dvs_mode[id]); | ||
| 554 | } | 505 | } |
| 555 | 506 | ||
| 556 | static __devinit int lp8788_buck_probe(struct platform_device *pdev) | 507 | static __devinit int lp8788_buck_probe(struct platform_device *pdev) |
| @@ -567,7 +518,6 @@ static __devinit int lp8788_buck_probe(struct platform_device *pdev) | |||
| 567 | return -ENOMEM; | 518 | return -ENOMEM; |
| 568 | 519 | ||
| 569 | buck->lp = lp; | 520 | buck->lp = lp; |
| 570 | buck->pmap = &buck_pmap[id]; | ||
| 571 | 521 | ||
| 572 | ret = lp8788_init_dvs(buck, id); | 522 | ret = lp8788_init_dvs(buck, id); |
| 573 | if (ret) | 523 | if (ret) |
diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c index d2122e41a96d..6796eeb47dc6 100644 --- a/drivers/regulator/lp8788-ldo.c +++ b/drivers/regulator/lp8788-ldo.c | |||
| @@ -496,6 +496,7 @@ static struct regulator_desc lp8788_dldo_desc[] = { | |||
| 496 | .name = "dldo12", | 496 | .name = "dldo12", |
| 497 | .id = DLDO12, | 497 | .id = DLDO12, |
| 498 | .ops = &lp8788_ldo_voltage_fixed_ops, | 498 | .ops = &lp8788_ldo_voltage_fixed_ops, |
| 499 | .n_voltages = 1, | ||
| 499 | .type = REGULATOR_VOLTAGE, | 500 | .type = REGULATOR_VOLTAGE, |
| 500 | .owner = THIS_MODULE, | 501 | .owner = THIS_MODULE, |
| 501 | .enable_reg = LP8788_EN_LDO_B, | 502 | .enable_reg = LP8788_EN_LDO_B, |
| @@ -521,6 +522,7 @@ static struct regulator_desc lp8788_aldo_desc[] = { | |||
| 521 | .name = "aldo2", | 522 | .name = "aldo2", |
| 522 | .id = ALDO2, | 523 | .id = ALDO2, |
| 523 | .ops = &lp8788_ldo_voltage_fixed_ops, | 524 | .ops = &lp8788_ldo_voltage_fixed_ops, |
| 525 | .n_voltages = 1, | ||
| 524 | .type = REGULATOR_VOLTAGE, | 526 | .type = REGULATOR_VOLTAGE, |
| 525 | .owner = THIS_MODULE, | 527 | .owner = THIS_MODULE, |
| 526 | .enable_reg = LP8788_EN_LDO_B, | 528 | .enable_reg = LP8788_EN_LDO_B, |
| @@ -530,6 +532,7 @@ static struct regulator_desc lp8788_aldo_desc[] = { | |||
| 530 | .name = "aldo3", | 532 | .name = "aldo3", |
| 531 | .id = ALDO3, | 533 | .id = ALDO3, |
| 532 | .ops = &lp8788_ldo_voltage_fixed_ops, | 534 | .ops = &lp8788_ldo_voltage_fixed_ops, |
| 535 | .n_voltages = 1, | ||
| 533 | .type = REGULATOR_VOLTAGE, | 536 | .type = REGULATOR_VOLTAGE, |
| 534 | .owner = THIS_MODULE, | 537 | .owner = THIS_MODULE, |
| 535 | .enable_reg = LP8788_EN_LDO_B, | 538 | .enable_reg = LP8788_EN_LDO_B, |
| @@ -539,6 +542,7 @@ static struct regulator_desc lp8788_aldo_desc[] = { | |||
| 539 | .name = "aldo4", | 542 | .name = "aldo4", |
| 540 | .id = ALDO4, | 543 | .id = ALDO4, |
| 541 | .ops = &lp8788_ldo_voltage_fixed_ops, | 544 | .ops = &lp8788_ldo_voltage_fixed_ops, |
| 545 | .n_voltages = 1, | ||
| 542 | .type = REGULATOR_VOLTAGE, | 546 | .type = REGULATOR_VOLTAGE, |
| 543 | .owner = THIS_MODULE, | 547 | .owner = THIS_MODULE, |
| 544 | .enable_reg = LP8788_EN_LDO_B, | 548 | .enable_reg = LP8788_EN_LDO_B, |
| @@ -548,6 +552,7 @@ static struct regulator_desc lp8788_aldo_desc[] = { | |||
| 548 | .name = "aldo5", | 552 | .name = "aldo5", |
| 549 | .id = ALDO5, | 553 | .id = ALDO5, |
| 550 | .ops = &lp8788_ldo_voltage_fixed_ops, | 554 | .ops = &lp8788_ldo_voltage_fixed_ops, |
| 555 | .n_voltages = 1, | ||
| 551 | .type = REGULATOR_VOLTAGE, | 556 | .type = REGULATOR_VOLTAGE, |
| 552 | .owner = THIS_MODULE, | 557 | .owner = THIS_MODULE, |
| 553 | .enable_reg = LP8788_EN_LDO_C, | 558 | .enable_reg = LP8788_EN_LDO_C, |
| @@ -583,6 +588,7 @@ static struct regulator_desc lp8788_aldo_desc[] = { | |||
| 583 | .name = "aldo8", | 588 | .name = "aldo8", |
| 584 | .id = ALDO8, | 589 | .id = ALDO8, |
| 585 | .ops = &lp8788_ldo_voltage_fixed_ops, | 590 | .ops = &lp8788_ldo_voltage_fixed_ops, |
| 591 | .n_voltages = 1, | ||
| 586 | .type = REGULATOR_VOLTAGE, | 592 | .type = REGULATOR_VOLTAGE, |
| 587 | .owner = THIS_MODULE, | 593 | .owner = THIS_MODULE, |
| 588 | .enable_reg = LP8788_EN_LDO_C, | 594 | .enable_reg = LP8788_EN_LDO_C, |
| @@ -592,6 +598,7 @@ static struct regulator_desc lp8788_aldo_desc[] = { | |||
| 592 | .name = "aldo9", | 598 | .name = "aldo9", |
| 593 | .id = ALDO9, | 599 | .id = ALDO9, |
| 594 | .ops = &lp8788_ldo_voltage_fixed_ops, | 600 | .ops = &lp8788_ldo_voltage_fixed_ops, |
| 601 | .n_voltages = 1, | ||
| 595 | .type = REGULATOR_VOLTAGE, | 602 | .type = REGULATOR_VOLTAGE, |
| 596 | .owner = THIS_MODULE, | 603 | .owner = THIS_MODULE, |
| 597 | .enable_reg = LP8788_EN_LDO_C, | 604 | .enable_reg = LP8788_EN_LDO_C, |
| @@ -601,6 +608,7 @@ static struct regulator_desc lp8788_aldo_desc[] = { | |||
| 601 | .name = "aldo10", | 608 | .name = "aldo10", |
| 602 | .id = ALDO10, | 609 | .id = ALDO10, |
| 603 | .ops = &lp8788_ldo_voltage_fixed_ops, | 610 | .ops = &lp8788_ldo_voltage_fixed_ops, |
| 611 | .n_voltages = 1, | ||
| 604 | .type = REGULATOR_VOLTAGE, | 612 | .type = REGULATOR_VOLTAGE, |
| 605 | .owner = THIS_MODULE, | 613 | .owner = THIS_MODULE, |
| 606 | .enable_reg = LP8788_EN_LDO_C, | 614 | .enable_reg = LP8788_EN_LDO_C, |
diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c index c564af6f05a3..2a67d08658ad 100644 --- a/drivers/regulator/max77686.c +++ b/drivers/regulator/max77686.c | |||
| @@ -66,7 +66,7 @@ enum max77686_ramp_rate { | |||
| 66 | }; | 66 | }; |
| 67 | 67 | ||
| 68 | struct max77686_data { | 68 | struct max77686_data { |
| 69 | struct regulator_dev **rdev; | 69 | struct regulator_dev *rdev[MAX77686_REGULATORS]; |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) | 72 | static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) |
| @@ -265,6 +265,7 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev, | |||
| 265 | rmatch.of_node = NULL; | 265 | rmatch.of_node = NULL; |
| 266 | of_regulator_match(iodev->dev, regulators_np, &rmatch, 1); | 266 | of_regulator_match(iodev->dev, regulators_np, &rmatch, 1); |
| 267 | rdata[i].initdata = rmatch.init_data; | 267 | rdata[i].initdata = rmatch.init_data; |
| 268 | rdata[i].of_node = rmatch.of_node; | ||
| 268 | } | 269 | } |
| 269 | 270 | ||
| 270 | pdata->regulators = rdata; | 271 | pdata->regulators = rdata; |
| @@ -283,10 +284,8 @@ static __devinit int max77686_pmic_probe(struct platform_device *pdev) | |||
| 283 | { | 284 | { |
| 284 | struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 285 | struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); |
| 285 | struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev); | 286 | struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev); |
| 286 | struct regulator_dev **rdev; | ||
| 287 | struct max77686_data *max77686; | 287 | struct max77686_data *max77686; |
| 288 | int i, size; | 288 | int i, ret = 0; |
| 289 | int ret = 0; | ||
| 290 | struct regulator_config config = { }; | 289 | struct regulator_config config = { }; |
| 291 | 290 | ||
| 292 | dev_dbg(&pdev->dev, "%s\n", __func__); | 291 | dev_dbg(&pdev->dev, "%s\n", __func__); |
| @@ -313,45 +312,38 @@ static __devinit int max77686_pmic_probe(struct platform_device *pdev) | |||
| 313 | if (!max77686) | 312 | if (!max77686) |
| 314 | return -ENOMEM; | 313 | return -ENOMEM; |
| 315 | 314 | ||
| 316 | size = sizeof(struct regulator_dev *) * MAX77686_REGULATORS; | ||
| 317 | max77686->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); | ||
| 318 | if (!max77686->rdev) | ||
| 319 | return -ENOMEM; | ||
| 320 | |||
| 321 | rdev = max77686->rdev; | ||
| 322 | config.dev = &pdev->dev; | 315 | config.dev = &pdev->dev; |
| 323 | config.regmap = iodev->regmap; | 316 | config.regmap = iodev->regmap; |
| 324 | platform_set_drvdata(pdev, max77686); | 317 | platform_set_drvdata(pdev, max77686); |
| 325 | 318 | ||
| 326 | for (i = 0; i < MAX77686_REGULATORS; i++) { | 319 | for (i = 0; i < MAX77686_REGULATORS; i++) { |
| 327 | config.init_data = pdata->regulators[i].initdata; | 320 | config.init_data = pdata->regulators[i].initdata; |
| 321 | config.of_node = pdata->regulators[i].of_node; | ||
| 328 | 322 | ||
| 329 | rdev[i] = regulator_register(®ulators[i], &config); | 323 | max77686->rdev[i] = regulator_register(®ulators[i], &config); |
| 330 | if (IS_ERR(rdev[i])) { | 324 | if (IS_ERR(max77686->rdev[i])) { |
| 331 | ret = PTR_ERR(rdev[i]); | 325 | ret = PTR_ERR(max77686->rdev[i]); |
| 332 | dev_err(&pdev->dev, | 326 | dev_err(&pdev->dev, |
| 333 | "regulator init failed for %d\n", i); | 327 | "regulator init failed for %d\n", i); |
| 334 | rdev[i] = NULL; | 328 | max77686->rdev[i] = NULL; |
| 335 | goto err; | 329 | goto err; |
| 336 | } | 330 | } |
| 337 | } | 331 | } |
| 338 | 332 | ||
| 339 | return 0; | 333 | return 0; |
| 340 | err: | 334 | err: |
| 341 | while (--i >= 0) | 335 | while (--i >= 0) |
| 342 | regulator_unregister(rdev[i]); | 336 | regulator_unregister(max77686->rdev[i]); |
| 343 | return ret; | 337 | return ret; |
| 344 | } | 338 | } |
| 345 | 339 | ||
| 346 | static int __devexit max77686_pmic_remove(struct platform_device *pdev) | 340 | static int __devexit max77686_pmic_remove(struct platform_device *pdev) |
| 347 | { | 341 | { |
| 348 | struct max77686_data *max77686 = platform_get_drvdata(pdev); | 342 | struct max77686_data *max77686 = platform_get_drvdata(pdev); |
| 349 | struct regulator_dev **rdev = max77686->rdev; | ||
| 350 | int i; | 343 | int i; |
| 351 | 344 | ||
| 352 | for (i = 0; i < MAX77686_REGULATORS; i++) | 345 | for (i = 0; i < MAX77686_REGULATORS; i++) |
| 353 | if (rdev[i]) | 346 | regulator_unregister(max77686->rdev[i]); |
| 354 | regulator_unregister(rdev[i]); | ||
| 355 | 347 | ||
| 356 | return 0; | 348 | return 0; |
| 357 | } | 349 | } |
diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c new file mode 100644 index 000000000000..af7607515ab9 --- /dev/null +++ b/drivers/regulator/max8907-regulator.c | |||
| @@ -0,0 +1,408 @@ | |||
| 1 | /* | ||
| 2 | * max8907-regulator.c -- support regulators in max8907 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com> | ||
| 5 | * Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved. | ||
| 6 | * | ||
| 7 | * Portions based on drivers/regulator/tps65910-regulator.c, | ||
| 8 | * Copyright 2010 Texas Instruments Inc. | ||
| 9 | * Author: Graeme Gregory <gg@slimlogic.co.uk> | ||
| 10 | * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License version 2 as | ||
| 14 | * published by the Free Software Foundation. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/err.h> | ||
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/mfd/core.h> | ||
| 20 | #include <linux/mfd/max8907.h> | ||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/of.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | #include <linux/regulator/driver.h> | ||
| 25 | #include <linux/regulator/machine.h> | ||
| 26 | #include <linux/regulator/of_regulator.h> | ||
| 27 | #include <linux/regmap.h> | ||
| 28 | #include <linux/slab.h> | ||
| 29 | |||
| 30 | #define MAX8907_II2RR_VERSION_MASK 0xF0 | ||
| 31 | #define MAX8907_II2RR_VERSION_REV_A 0x00 | ||
| 32 | #define MAX8907_II2RR_VERSION_REV_B 0x10 | ||
| 33 | #define MAX8907_II2RR_VERSION_REV_C 0x30 | ||
| 34 | |||
| 35 | struct max8907_regulator { | ||
| 36 | struct regulator_desc desc[MAX8907_NUM_REGULATORS]; | ||
| 37 | struct regulator_dev *rdev[MAX8907_NUM_REGULATORS]; | ||
| 38 | }; | ||
| 39 | |||
| 40 | #define REG_MBATT() \ | ||
| 41 | [MAX8907_MBATT] = { \ | ||
| 42 | .name = "MBATT", \ | ||
| 43 | .supply_name = "mbatt", \ | ||
| 44 | .id = MAX8907_MBATT, \ | ||
| 45 | .ops = &max8907_mbatt_ops, \ | ||
| 46 | .type = REGULATOR_VOLTAGE, \ | ||
| 47 | .owner = THIS_MODULE, \ | ||
| 48 | } | ||
| 49 | |||
| 50 | #define REG_LDO(ids, supply, base, min, max, step) \ | ||
| 51 | [MAX8907_##ids] = { \ | ||
| 52 | .name = #ids, \ | ||
| 53 | .supply_name = supply, \ | ||
| 54 | .id = MAX8907_##ids, \ | ||
| 55 | .n_voltages = ((max) - (min)) / (step) + 1, \ | ||
| 56 | .ops = &max8907_ldo_ops, \ | ||
| 57 | .type = REGULATOR_VOLTAGE, \ | ||
| 58 | .owner = THIS_MODULE, \ | ||
| 59 | .min_uV = (min), \ | ||
| 60 | .uV_step = (step), \ | ||
| 61 | .vsel_reg = (base) + MAX8907_VOUT, \ | ||
| 62 | .vsel_mask = 0x3f, \ | ||
| 63 | .enable_reg = (base) + MAX8907_CTL, \ | ||
| 64 | .enable_mask = MAX8907_MASK_LDO_EN, \ | ||
| 65 | } | ||
| 66 | |||
| 67 | #define REG_FIXED(ids, supply, voltage) \ | ||
| 68 | [MAX8907_##ids] = { \ | ||
| 69 | .name = #ids, \ | ||
| 70 | .supply_name = supply, \ | ||
| 71 | .id = MAX8907_##ids, \ | ||
| 72 | .n_voltages = 1, \ | ||
| 73 | .ops = &max8907_fixed_ops, \ | ||
| 74 | .type = REGULATOR_VOLTAGE, \ | ||
| 75 | .owner = THIS_MODULE, \ | ||
| 76 | .min_uV = (voltage), \ | ||
| 77 | } | ||
| 78 | |||
| 79 | #define REG_OUT5V(ids, supply, base, voltage) \ | ||
| 80 | [MAX8907_##ids] = { \ | ||
| 81 | .name = #ids, \ | ||
| 82 | .supply_name = supply, \ | ||
| 83 | .id = MAX8907_##ids, \ | ||
| 84 | .n_voltages = 1, \ | ||
| 85 | .ops = &max8907_out5v_ops, \ | ||
| 86 | .type = REGULATOR_VOLTAGE, \ | ||
| 87 | .owner = THIS_MODULE, \ | ||
| 88 | .min_uV = (voltage), \ | ||
| 89 | .enable_reg = (base), \ | ||
| 90 | .enable_mask = MAX8907_MASK_OUT5V_EN, \ | ||
| 91 | } | ||
| 92 | |||
| 93 | #define REG_BBAT(ids, supply, base, min, max, step) \ | ||
| 94 | [MAX8907_##ids] = { \ | ||
| 95 | .name = #ids, \ | ||
| 96 | .supply_name = supply, \ | ||
| 97 | .id = MAX8907_##ids, \ | ||
| 98 | .n_voltages = ((max) - (min)) / (step) + 1, \ | ||
| 99 | .ops = &max8907_bbat_ops, \ | ||
| 100 | .type = REGULATOR_VOLTAGE, \ | ||
| 101 | .owner = THIS_MODULE, \ | ||
| 102 | .min_uV = (min), \ | ||
| 103 | .uV_step = (step), \ | ||
| 104 | .vsel_reg = (base), \ | ||
| 105 | .vsel_mask = MAX8907_MASK_VBBATTCV, \ | ||
| 106 | } | ||
| 107 | |||
| 108 | #define LDO_750_50(id, supply, base) REG_LDO(id, supply, (base), \ | ||
| 109 | 750000, 3900000, 50000) | ||
| 110 | #define LDO_650_25(id, supply, base) REG_LDO(id, supply, (base), \ | ||
| 111 | 650000, 2225000, 25000) | ||
| 112 | |||
| 113 | static struct regulator_ops max8907_mbatt_ops = { | ||
| 114 | }; | ||
| 115 | |||
| 116 | static struct regulator_ops max8907_ldo_ops = { | ||
| 117 | .list_voltage = regulator_list_voltage_linear, | ||
| 118 | .set_voltage_sel = regulator_set_voltage_sel_regmap, | ||
| 119 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | ||
| 120 | .enable = regulator_enable_regmap, | ||
| 121 | .disable = regulator_disable_regmap, | ||
| 122 | .is_enabled = regulator_is_enabled_regmap, | ||
| 123 | }; | ||
| 124 | |||
| 125 | static struct regulator_ops max8907_ldo_hwctl_ops = { | ||
| 126 | .list_voltage = regulator_list_voltage_linear, | ||
| 127 | .set_voltage_sel = regulator_set_voltage_sel_regmap, | ||
| 128 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | ||
| 129 | }; | ||
| 130 | |||
| 131 | static struct regulator_ops max8907_fixed_ops = { | ||
| 132 | .list_voltage = regulator_list_voltage_linear, | ||
| 133 | }; | ||
| 134 | |||
| 135 | static struct regulator_ops max8907_out5v_ops = { | ||
| 136 | .list_voltage = regulator_list_voltage_linear, | ||
| 137 | .enable = regulator_enable_regmap, | ||
| 138 | .disable = regulator_disable_regmap, | ||
| 139 | .is_enabled = regulator_is_enabled_regmap, | ||
| 140 | }; | ||
| 141 | |||
| 142 | static struct regulator_ops max8907_out5v_hwctl_ops = { | ||
| 143 | .list_voltage = regulator_list_voltage_linear, | ||
| 144 | }; | ||
| 145 | |||
| 146 | static struct regulator_ops max8907_bbat_ops = { | ||
| 147 | .list_voltage = regulator_list_voltage_linear, | ||
| 148 | .set_voltage_sel = regulator_set_voltage_sel_regmap, | ||
| 149 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | ||
| 150 | }; | ||
| 151 | |||
| 152 | static struct regulator_desc max8907_regulators[] = { | ||
| 153 | REG_MBATT(), | ||
| 154 | REG_LDO(SD1, "in-v1", MAX8907_REG_SDCTL1, 650000, 2225000, 25000), | ||
| 155 | REG_LDO(SD2, "in-v2", MAX8907_REG_SDCTL2, 637500, 1425000, 12500), | ||
| 156 | REG_LDO(SD3, "in-v3", MAX8907_REG_SDCTL3, 750000, 3900000, 50000), | ||
| 157 | LDO_750_50(LDO1, "in1", MAX8907_REG_LDOCTL1), | ||
| 158 | LDO_650_25(LDO2, "in2", MAX8907_REG_LDOCTL2), | ||
| 159 | LDO_650_25(LDO3, "in3", MAX8907_REG_LDOCTL3), | ||
| 160 | LDO_750_50(LDO4, "in4", MAX8907_REG_LDOCTL4), | ||
| 161 | LDO_750_50(LDO5, "in5", MAX8907_REG_LDOCTL5), | ||
| 162 | LDO_750_50(LDO6, "in6", MAX8907_REG_LDOCTL6), | ||
| 163 | LDO_750_50(LDO7, "in7", MAX8907_REG_LDOCTL7), | ||
| 164 | LDO_750_50(LDO8, "in8", MAX8907_REG_LDOCTL8), | ||
| 165 | LDO_750_50(LDO9, "in9", MAX8907_REG_LDOCTL9), | ||
| 166 | LDO_750_50(LDO10, "in10", MAX8907_REG_LDOCTL10), | ||
| 167 | LDO_750_50(LDO11, "in11", MAX8907_REG_LDOCTL11), | ||
| 168 | LDO_750_50(LDO12, "in12", MAX8907_REG_LDOCTL12), | ||
| 169 | LDO_750_50(LDO13, "in13", MAX8907_REG_LDOCTL13), | ||
| 170 | LDO_750_50(LDO14, "in14", MAX8907_REG_LDOCTL14), | ||
| 171 | LDO_750_50(LDO15, "in15", MAX8907_REG_LDOCTL15), | ||
| 172 | LDO_750_50(LDO16, "in16", MAX8907_REG_LDOCTL16), | ||
| 173 | LDO_650_25(LDO17, "in17", MAX8907_REG_LDOCTL17), | ||
| 174 | LDO_650_25(LDO18, "in18", MAX8907_REG_LDOCTL18), | ||
| 175 | LDO_750_50(LDO19, "in19", MAX8907_REG_LDOCTL19), | ||
| 176 | LDO_750_50(LDO20, "in20", MAX8907_REG_LDOCTL20), | ||
| 177 | REG_OUT5V(OUT5V, "mbatt", MAX8907_REG_OUT5VEN, 5000000), | ||
| 178 | REG_OUT5V(OUT33V, "mbatt", MAX8907_REG_OUT33VEN, 3300000), | ||
| 179 | REG_BBAT(BBAT, "MBATT", MAX8907_REG_BBAT_CNFG, | ||
| 180 | 2400000, 3000000, 200000), | ||
| 181 | REG_FIXED(SDBY, "MBATT", 1200000), | ||
| 182 | REG_FIXED(VRTC, "MBATT", 3300000), | ||
| 183 | }; | ||
| 184 | |||
| 185 | #ifdef CONFIG_OF | ||
| 186 | |||
| 187 | #define MATCH(_name, _id) \ | ||
| 188 | [MAX8907_##_id] = { \ | ||
| 189 | .name = #_name, \ | ||
| 190 | .driver_data = (void *)&max8907_regulators[MAX8907_##_id], \ | ||
| 191 | } | ||
| 192 | |||
| 193 | static struct of_regulator_match max8907_matches[] = { | ||
| 194 | MATCH(mbatt, MBATT), | ||
| 195 | MATCH(sd1, SD1), | ||
| 196 | MATCH(sd2, SD2), | ||
| 197 | MATCH(sd3, SD3), | ||
| 198 | MATCH(ldo1, LDO1), | ||
| 199 | MATCH(ldo2, LDO2), | ||
| 200 | MATCH(ldo3, LDO3), | ||
| 201 | MATCH(ldo4, LDO4), | ||
| 202 | MATCH(ldo5, LDO5), | ||
| 203 | MATCH(ldo6, LDO6), | ||
| 204 | MATCH(ldo7, LDO7), | ||
| 205 | MATCH(ldo8, LDO8), | ||
| 206 | MATCH(ldo9, LDO9), | ||
| 207 | MATCH(ldo10, LDO10), | ||
| 208 | MATCH(ldo11, LDO11), | ||
| 209 | MATCH(ldo12, LDO12), | ||
| 210 | MATCH(ldo13, LDO13), | ||
| 211 | MATCH(ldo14, LDO14), | ||
| 212 | MATCH(ldo15, LDO15), | ||
| 213 | MATCH(ldo16, LDO16), | ||
| 214 | MATCH(ldo17, LDO17), | ||
| 215 | MATCH(ldo18, LDO18), | ||
| 216 | MATCH(ldo19, LDO19), | ||
| 217 | MATCH(ldo20, LDO20), | ||
| 218 | MATCH(out5v, OUT5V), | ||
| 219 | MATCH(out33v, OUT33V), | ||
| 220 | MATCH(bbat, BBAT), | ||
| 221 | MATCH(sdby, SDBY), | ||
| 222 | MATCH(vrtc, VRTC), | ||
| 223 | }; | ||
| 224 | |||
| 225 | static int max8907_regulator_parse_dt(struct platform_device *pdev) | ||
| 226 | { | ||
| 227 | struct device_node *np = pdev->dev.parent->of_node; | ||
| 228 | struct device_node *regulators; | ||
| 229 | int ret; | ||
| 230 | |||
| 231 | if (!pdev->dev.parent->of_node) | ||
| 232 | return 0; | ||
| 233 | |||
| 234 | regulators = of_find_node_by_name(np, "regulators"); | ||
| 235 | if (!regulators) { | ||
| 236 | dev_err(&pdev->dev, "regulators node not found\n"); | ||
| 237 | return -EINVAL; | ||
| 238 | } | ||
| 239 | |||
| 240 | ret = of_regulator_match(pdev->dev.parent, regulators, | ||
| 241 | max8907_matches, | ||
| 242 | ARRAY_SIZE(max8907_matches)); | ||
| 243 | if (ret < 0) { | ||
| 244 | dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", | ||
| 245 | ret); | ||
| 246 | return ret; | ||
| 247 | } | ||
| 248 | |||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | |||
| 252 | static inline struct regulator_init_data *match_init_data(int index) | ||
| 253 | { | ||
| 254 | return max8907_matches[index].init_data; | ||
| 255 | } | ||
| 256 | |||
| 257 | static inline struct device_node *match_of_node(int index) | ||
| 258 | { | ||
| 259 | return max8907_matches[index].of_node; | ||
| 260 | } | ||
| 261 | #else | ||
| 262 | static int max8907_regulator_parse_dt(struct platform_device *pdev) | ||
| 263 | { | ||
| 264 | return 0; | ||
| 265 | } | ||
| 266 | |||
| 267 | static inline struct regulator_init_data *match_init_data(int index) | ||
| 268 | { | ||
| 269 | return NULL; | ||
| 270 | } | ||
| 271 | |||
| 272 | static inline struct device_node *match_of_node(int index) | ||
| 273 | { | ||
| 274 | return NULL; | ||
| 275 | } | ||
| 276 | #endif | ||
| 277 | |||
| 278 | static __devinit int max8907_regulator_probe(struct platform_device *pdev) | ||
| 279 | { | ||
| 280 | struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent); | ||
| 281 | struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev); | ||
| 282 | int ret; | ||
| 283 | struct max8907_regulator *pmic; | ||
| 284 | unsigned int val; | ||
| 285 | int i; | ||
| 286 | struct regulator_config config = {}; | ||
| 287 | struct regulator_init_data *idata; | ||
| 288 | const char *mbatt_rail_name = NULL; | ||
| 289 | |||
| 290 | ret = max8907_regulator_parse_dt(pdev); | ||
| 291 | if (ret) | ||
| 292 | return ret; | ||
| 293 | |||
| 294 | pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); | ||
| 295 | if (!pmic) { | ||
| 296 | dev_err(&pdev->dev, "Failed to alloc pmic\n"); | ||
| 297 | return -ENOMEM; | ||
| 298 | } | ||
| 299 | platform_set_drvdata(pdev, pmic); | ||
| 300 | |||
| 301 | memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc)); | ||
| 302 | |||
| 303 | /* Backwards compatibility with MAX8907B; SD1 uses different voltages */ | ||
| 304 | regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val); | ||
| 305 | if ((val & MAX8907_II2RR_VERSION_MASK) == | ||
| 306 | MAX8907_II2RR_VERSION_REV_B) { | ||
| 307 | pmic->desc[MAX8907_SD1].min_uV = 637500; | ||
| 308 | pmic->desc[MAX8907_SD1].uV_step = 12500; | ||
| 309 | pmic->desc[MAX8907_SD1].n_voltages = | ||
| 310 | (1425000 - 637500) / 12500 + 1; | ||
| 311 | } | ||
| 312 | |||
| 313 | for (i = 0; i < MAX8907_NUM_REGULATORS; i++) { | ||
| 314 | config.dev = pdev->dev.parent; | ||
| 315 | if (pdata) | ||
| 316 | idata = pdata->init_data[i]; | ||
| 317 | else | ||
| 318 | idata = match_init_data(i); | ||
| 319 | config.init_data = idata; | ||
| 320 | config.driver_data = pmic; | ||
| 321 | config.regmap = max8907->regmap_gen; | ||
| 322 | config.of_node = match_of_node(i); | ||
| 323 | |||
| 324 | switch (pmic->desc[i].id) { | ||
| 325 | case MAX8907_MBATT: | ||
| 326 | if (idata && idata->constraints.name) | ||
| 327 | mbatt_rail_name = idata->constraints.name; | ||
| 328 | else | ||
| 329 | mbatt_rail_name = pmic->desc[i].name; | ||
| 330 | break; | ||
| 331 | case MAX8907_BBAT: | ||
| 332 | case MAX8907_SDBY: | ||
| 333 | case MAX8907_VRTC: | ||
| 334 | idata->supply_regulator = mbatt_rail_name; | ||
| 335 | break; | ||
| 336 | } | ||
| 337 | |||
| 338 | if (pmic->desc[i].ops == &max8907_ldo_ops) { | ||
| 339 | regmap_read(config.regmap, pmic->desc[i].enable_reg, | ||
| 340 | &val); | ||
| 341 | if ((val & MAX8907_MASK_LDO_SEQ) != | ||
| 342 | MAX8907_MASK_LDO_SEQ) | ||
| 343 | pmic->desc[i].ops = &max8907_ldo_hwctl_ops; | ||
| 344 | } else if (pmic->desc[i].ops == &max8907_out5v_ops) { | ||
| 345 | regmap_read(config.regmap, pmic->desc[i].enable_reg, | ||
| 346 | &val); | ||
| 347 | if ((val & (MAX8907_MASK_OUT5V_VINEN | | ||
| 348 | MAX8907_MASK_OUT5V_ENSRC)) != | ||
| 349 | MAX8907_MASK_OUT5V_ENSRC) | ||
| 350 | pmic->desc[i].ops = &max8907_out5v_hwctl_ops; | ||
| 351 | } | ||
| 352 | |||
| 353 | pmic->rdev[i] = regulator_register(&pmic->desc[i], &config); | ||
| 354 | if (IS_ERR(pmic->rdev[i])) { | ||
| 355 | dev_err(&pdev->dev, | ||
| 356 | "failed to register %s regulator\n", | ||
| 357 | pmic->desc[i].name); | ||
| 358 | ret = PTR_ERR(pmic->rdev[i]); | ||
| 359 | goto err_unregister_regulator; | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | return 0; | ||
| 364 | |||
| 365 | err_unregister_regulator: | ||
| 366 | while (--i >= 0) | ||
| 367 | regulator_unregister(pmic->rdev[i]); | ||
| 368 | return ret; | ||
| 369 | } | ||
| 370 | |||
| 371 | static __devexit int max8907_regulator_remove(struct platform_device *pdev) | ||
| 372 | { | ||
| 373 | struct max8907_regulator *pmic = platform_get_drvdata(pdev); | ||
| 374 | int i; | ||
| 375 | |||
| 376 | for (i = 0; i < MAX8907_NUM_REGULATORS; i++) | ||
| 377 | regulator_unregister(pmic->rdev[i]); | ||
| 378 | |||
| 379 | return 0; | ||
| 380 | } | ||
| 381 | |||
| 382 | static struct platform_driver max8907_regulator_driver = { | ||
| 383 | .driver = { | ||
| 384 | .name = "max8907-regulator", | ||
| 385 | .owner = THIS_MODULE, | ||
| 386 | }, | ||
| 387 | .probe = max8907_regulator_probe, | ||
| 388 | .remove = __devexit_p(max8907_regulator_remove), | ||
| 389 | }; | ||
| 390 | |||
| 391 | static int __init max8907_regulator_init(void) | ||
| 392 | { | ||
| 393 | return platform_driver_register(&max8907_regulator_driver); | ||
| 394 | } | ||
| 395 | |||
| 396 | subsys_initcall(max8907_regulator_init); | ||
| 397 | |||
| 398 | static void __exit max8907_reg_exit(void) | ||
| 399 | { | ||
| 400 | platform_driver_unregister(&max8907_regulator_driver); | ||
| 401 | } | ||
| 402 | |||
| 403 | module_exit(max8907_reg_exit); | ||
| 404 | |||
| 405 | MODULE_DESCRIPTION("MAX8907 regulator driver"); | ||
| 406 | MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>"); | ||
| 407 | MODULE_LICENSE("GPL v2"); | ||
| 408 | MODULE_ALIAS("platform:max8907-regulator"); | ||
diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 4932e3449fe1..0801a6d0c122 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c | |||
| @@ -21,6 +21,30 @@ | |||
| 21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 22 | #include "mc13xxx.h" | 22 | #include "mc13xxx.h" |
| 23 | 23 | ||
| 24 | #define MC13783_REG_SWITCHERS0 24 | ||
| 25 | /* Enable does not exist for SW1A */ | ||
| 26 | #define MC13783_REG_SWITCHERS0_SW1AEN 0 | ||
| 27 | #define MC13783_REG_SWITCHERS0_SW1AVSEL 0 | ||
| 28 | #define MC13783_REG_SWITCHERS0_SW1AVSEL_M (63 << 0) | ||
| 29 | |||
| 30 | #define MC13783_REG_SWITCHERS1 25 | ||
| 31 | /* Enable does not exist for SW1B */ | ||
| 32 | #define MC13783_REG_SWITCHERS1_SW1BEN 0 | ||
| 33 | #define MC13783_REG_SWITCHERS1_SW1BVSEL 0 | ||
| 34 | #define MC13783_REG_SWITCHERS1_SW1BVSEL_M (63 << 0) | ||
| 35 | |||
| 36 | #define MC13783_REG_SWITCHERS2 26 | ||
| 37 | /* Enable does not exist for SW2A */ | ||
| 38 | #define MC13783_REG_SWITCHERS2_SW2AEN 0 | ||
| 39 | #define MC13783_REG_SWITCHERS2_SW2AVSEL 0 | ||
| 40 | #define MC13783_REG_SWITCHERS2_SW2AVSEL_M (63 << 0) | ||
| 41 | |||
| 42 | #define MC13783_REG_SWITCHERS3 27 | ||
| 43 | /* Enable does not exist for SW2B */ | ||
| 44 | #define MC13783_REG_SWITCHERS3_SW2BEN 0 | ||
| 45 | #define MC13783_REG_SWITCHERS3_SW2BVSEL 0 | ||
| 46 | #define MC13783_REG_SWITCHERS3_SW2BVSEL_M (63 << 0) | ||
| 47 | |||
| 24 | #define MC13783_REG_SWITCHERS5 29 | 48 | #define MC13783_REG_SWITCHERS5 29 |
| 25 | #define MC13783_REG_SWITCHERS5_SW3EN (1 << 20) | 49 | #define MC13783_REG_SWITCHERS5_SW3EN (1 << 20) |
| 26 | #define MC13783_REG_SWITCHERS5_SW3VSEL 18 | 50 | #define MC13783_REG_SWITCHERS5_SW3VSEL 18 |
| @@ -93,6 +117,44 @@ | |||
| 93 | 117 | ||
| 94 | 118 | ||
| 95 | /* Voltage Values */ | 119 | /* Voltage Values */ |
| 120 | static const int mc13783_sw1x_val[] = { | ||
| 121 | 900000, 925000, 950000, 975000, | ||
| 122 | 1000000, 1025000, 1050000, 1075000, | ||
| 123 | 1100000, 1125000, 1150000, 1175000, | ||
| 124 | 1200000, 1225000, 1250000, 1275000, | ||
| 125 | 1300000, 1325000, 1350000, 1375000, | ||
| 126 | 1400000, 1425000, 1450000, 1475000, | ||
| 127 | 1500000, 1525000, 1550000, 1575000, | ||
| 128 | 1600000, 1625000, 1650000, 1675000, | ||
| 129 | 1700000, 1700000, 1700000, 1700000, | ||
| 130 | 1800000, 1800000, 1800000, 1800000, | ||
| 131 | 1850000, 1850000, 1850000, 1850000, | ||
| 132 | 2000000, 2000000, 2000000, 2000000, | ||
| 133 | 2100000, 2100000, 2100000, 2100000, | ||
| 134 | 2200000, 2200000, 2200000, 2200000, | ||
| 135 | 2200000, 2200000, 2200000, 2200000, | ||
| 136 | 2200000, 2200000, 2200000, 2200000, | ||
| 137 | }; | ||
| 138 | |||
| 139 | static const int mc13783_sw2x_val[] = { | ||
| 140 | 900000, 925000, 950000, 975000, | ||
| 141 | 1000000, 1025000, 1050000, 1075000, | ||
| 142 | 1100000, 1125000, 1150000, 1175000, | ||
| 143 | 1200000, 1225000, 1250000, 1275000, | ||
| 144 | 1300000, 1325000, 1350000, 1375000, | ||
| 145 | 1400000, 1425000, 1450000, 1475000, | ||
| 146 | 1500000, 1525000, 1550000, 1575000, | ||
| 147 | 1600000, 1625000, 1650000, 1675000, | ||
| 148 | 1700000, 1700000, 1700000, 1700000, | ||
| 149 | 1800000, 1800000, 1800000, 1800000, | ||
| 150 | 1900000, 1900000, 1900000, 1900000, | ||
| 151 | 2000000, 2000000, 2000000, 2000000, | ||
| 152 | 2100000, 2100000, 2100000, 2100000, | ||
| 153 | 2200000, 2200000, 2200000, 2200000, | ||
| 154 | 2200000, 2200000, 2200000, 2200000, | ||
| 155 | 2200000, 2200000, 2200000, 2200000, | ||
| 156 | }; | ||
| 157 | |||
| 96 | static const unsigned int mc13783_sw3_val[] = { | 158 | static const unsigned int mc13783_sw3_val[] = { |
| 97 | 5000000, 5000000, 5000000, 5500000, | 159 | 5000000, 5000000, 5000000, 5500000, |
| 98 | }; | 160 | }; |
| @@ -188,6 +250,10 @@ static struct regulator_ops mc13783_gpo_regulator_ops; | |||
| 188 | MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages) | 250 | MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages) |
| 189 | 251 | ||
| 190 | static struct mc13xxx_regulator mc13783_regulators[] = { | 252 | static struct mc13xxx_regulator mc13783_regulators[] = { |
| 253 | MC13783_DEFINE_SW(SW1A, SWITCHERS0, SWITCHERS0, mc13783_sw1x_val), | ||
| 254 | MC13783_DEFINE_SW(SW1B, SWITCHERS1, SWITCHERS1, mc13783_sw1x_val), | ||
| 255 | MC13783_DEFINE_SW(SW2A, SWITCHERS2, SWITCHERS2, mc13783_sw2x_val), | ||
| 256 | MC13783_DEFINE_SW(SW2B, SWITCHERS3, SWITCHERS3, mc13783_sw2x_val), | ||
| 191 | MC13783_DEFINE_SW(SW3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val), | 257 | MC13783_DEFINE_SW(SW3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val), |
| 192 | 258 | ||
| 193 | MC13783_FIXED_DEFINE(REG, VAUDIO, REGULATORMODE0, mc13783_vaudio_val), | 259 | MC13783_FIXED_DEFINE(REG, VAUDIO, REGULATORMODE0, mc13783_vaudio_val), |
| @@ -238,9 +304,10 @@ static int mc13783_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, | |||
| 238 | 304 | ||
| 239 | BUG_ON(val & ~mask); | 305 | BUG_ON(val & ~mask); |
| 240 | 306 | ||
| 307 | mc13xxx_lock(priv->mc13xxx); | ||
| 241 | ret = mc13xxx_reg_read(mc13783, MC13783_REG_POWERMISC, &valread); | 308 | ret = mc13xxx_reg_read(mc13783, MC13783_REG_POWERMISC, &valread); |
| 242 | if (ret) | 309 | if (ret) |
| 243 | return ret; | 310 | goto out; |
| 244 | 311 | ||
| 245 | /* Update the stored state for Power Gates. */ | 312 | /* Update the stored state for Power Gates. */ |
| 246 | priv->powermisc_pwgt_state = | 313 | priv->powermisc_pwgt_state = |
| @@ -253,7 +320,10 @@ static int mc13783_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, | |||
| 253 | valread = (valread & ~MC13783_REG_POWERMISC_PWGTSPI_M) | | 320 | valread = (valread & ~MC13783_REG_POWERMISC_PWGTSPI_M) | |
| 254 | priv->powermisc_pwgt_state; | 321 | priv->powermisc_pwgt_state; |
| 255 | 322 | ||
| 256 | return mc13xxx_reg_write(mc13783, MC13783_REG_POWERMISC, valread); | 323 | ret = mc13xxx_reg_write(mc13783, MC13783_REG_POWERMISC, valread); |
| 324 | out: | ||
| 325 | mc13xxx_unlock(priv->mc13xxx); | ||
| 326 | return ret; | ||
| 257 | } | 327 | } |
| 258 | 328 | ||
| 259 | static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev) | 329 | static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev) |
| @@ -261,7 +331,6 @@ static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev) | |||
| 261 | struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); | 331 | struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); |
| 262 | struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; | 332 | struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; |
| 263 | int id = rdev_get_id(rdev); | 333 | int id = rdev_get_id(rdev); |
| 264 | int ret; | ||
| 265 | u32 en_val = mc13xxx_regulators[id].enable_bit; | 334 | u32 en_val = mc13xxx_regulators[id].enable_bit; |
| 266 | 335 | ||
| 267 | dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); | 336 | dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); |
| @@ -271,12 +340,8 @@ static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev) | |||
| 271 | id == MC13783_REG_PWGT2SPI) | 340 | id == MC13783_REG_PWGT2SPI) |
| 272 | en_val = 0; | 341 | en_val = 0; |
| 273 | 342 | ||
| 274 | mc13xxx_lock(priv->mc13xxx); | 343 | return mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit, |
| 275 | ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit, | ||
| 276 | en_val); | 344 | en_val); |
| 277 | mc13xxx_unlock(priv->mc13xxx); | ||
| 278 | |||
| 279 | return ret; | ||
| 280 | } | 345 | } |
| 281 | 346 | ||
| 282 | static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev) | 347 | static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev) |
| @@ -284,7 +349,6 @@ static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev) | |||
| 284 | struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); | 349 | struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); |
| 285 | struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; | 350 | struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; |
| 286 | int id = rdev_get_id(rdev); | 351 | int id = rdev_get_id(rdev); |
| 287 | int ret; | ||
| 288 | u32 dis_val = 0; | 352 | u32 dis_val = 0; |
| 289 | 353 | ||
| 290 | dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); | 354 | dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); |
| @@ -294,12 +358,8 @@ static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev) | |||
| 294 | id == MC13783_REG_PWGT2SPI) | 358 | id == MC13783_REG_PWGT2SPI) |
| 295 | dis_val = mc13xxx_regulators[id].enable_bit; | 359 | dis_val = mc13xxx_regulators[id].enable_bit; |
| 296 | 360 | ||
| 297 | mc13xxx_lock(priv->mc13xxx); | 361 | return mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit, |
| 298 | ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit, | ||
| 299 | dis_val); | 362 | dis_val); |
| 300 | mc13xxx_unlock(priv->mc13xxx); | ||
| 301 | |||
| 302 | return ret; | ||
| 303 | } | 363 | } |
| 304 | 364 | ||
| 305 | static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev) | 365 | static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev) |
| @@ -330,7 +390,6 @@ static struct regulator_ops mc13783_gpo_regulator_ops = { | |||
| 330 | .is_enabled = mc13783_gpo_regulator_is_enabled, | 390 | .is_enabled = mc13783_gpo_regulator_is_enabled, |
| 331 | .list_voltage = regulator_list_voltage_table, | 391 | .list_voltage = regulator_list_voltage_table, |
| 332 | .set_voltage = mc13xxx_fixed_regulator_set_voltage, | 392 | .set_voltage = mc13xxx_fixed_regulator_set_voltage, |
| 333 | .get_voltage = mc13xxx_fixed_regulator_get_voltage, | ||
| 334 | }; | 393 | }; |
| 335 | 394 | ||
| 336 | static int __devinit mc13783_regulator_probe(struct platform_device *pdev) | 395 | static int __devinit mc13783_regulator_probe(struct platform_device *pdev) |
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index b388b746452e..1fa63812f7ac 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c | |||
| @@ -305,9 +305,10 @@ static int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, | |||
| 305 | 305 | ||
| 306 | BUG_ON(val & ~mask); | 306 | BUG_ON(val & ~mask); |
| 307 | 307 | ||
| 308 | mc13xxx_lock(priv->mc13xxx); | ||
| 308 | ret = mc13xxx_reg_read(mc13892, MC13892_POWERMISC, &valread); | 309 | ret = mc13xxx_reg_read(mc13892, MC13892_POWERMISC, &valread); |
| 309 | if (ret) | 310 | if (ret) |
| 310 | return ret; | 311 | goto out; |
| 311 | 312 | ||
| 312 | /* Update the stored state for Power Gates. */ | 313 | /* Update the stored state for Power Gates. */ |
| 313 | priv->powermisc_pwgt_state = | 314 | priv->powermisc_pwgt_state = |
| @@ -320,14 +321,16 @@ static int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, | |||
| 320 | valread = (valread & ~MC13892_POWERMISC_PWGTSPI_M) | | 321 | valread = (valread & ~MC13892_POWERMISC_PWGTSPI_M) | |
| 321 | priv->powermisc_pwgt_state; | 322 | priv->powermisc_pwgt_state; |
| 322 | 323 | ||
| 323 | return mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread); | 324 | ret = mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread); |
| 325 | out: | ||
| 326 | mc13xxx_unlock(priv->mc13xxx); | ||
| 327 | return ret; | ||
| 324 | } | 328 | } |
| 325 | 329 | ||
| 326 | static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev) | 330 | static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev) |
| 327 | { | 331 | { |
| 328 | struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); | 332 | struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); |
| 329 | int id = rdev_get_id(rdev); | 333 | int id = rdev_get_id(rdev); |
| 330 | int ret; | ||
| 331 | u32 en_val = mc13892_regulators[id].enable_bit; | 334 | u32 en_val = mc13892_regulators[id].enable_bit; |
| 332 | u32 mask = mc13892_regulators[id].enable_bit; | 335 | u32 mask = mc13892_regulators[id].enable_bit; |
| 333 | 336 | ||
| @@ -340,18 +343,13 @@ static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev) | |||
| 340 | if (id == MC13892_GPO4) | 343 | if (id == MC13892_GPO4) |
| 341 | mask |= MC13892_POWERMISC_GPO4ADINEN; | 344 | mask |= MC13892_POWERMISC_GPO4ADINEN; |
| 342 | 345 | ||
| 343 | mc13xxx_lock(priv->mc13xxx); | 346 | return mc13892_powermisc_rmw(priv, mask, en_val); |
| 344 | ret = mc13892_powermisc_rmw(priv, mask, en_val); | ||
| 345 | mc13xxx_unlock(priv->mc13xxx); | ||
| 346 | |||
| 347 | return ret; | ||
| 348 | } | 347 | } |
| 349 | 348 | ||
| 350 | static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev) | 349 | static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev) |
| 351 | { | 350 | { |
| 352 | struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); | 351 | struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); |
| 353 | int id = rdev_get_id(rdev); | 352 | int id = rdev_get_id(rdev); |
| 354 | int ret; | ||
| 355 | u32 dis_val = 0; | 353 | u32 dis_val = 0; |
| 356 | 354 | ||
| 357 | dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); | 355 | dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); |
| @@ -360,12 +358,8 @@ static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev) | |||
| 360 | if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI) | 358 | if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI) |
| 361 | dis_val = mc13892_regulators[id].enable_bit; | 359 | dis_val = mc13892_regulators[id].enable_bit; |
| 362 | 360 | ||
| 363 | mc13xxx_lock(priv->mc13xxx); | 361 | return mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit, |
| 364 | ret = mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit, | ||
| 365 | dis_val); | 362 | dis_val); |
| 366 | mc13xxx_unlock(priv->mc13xxx); | ||
| 367 | |||
| 368 | return ret; | ||
| 369 | } | 363 | } |
| 370 | 364 | ||
| 371 | static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev) | 365 | static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev) |
| @@ -396,14 +390,13 @@ static struct regulator_ops mc13892_gpo_regulator_ops = { | |||
| 396 | .is_enabled = mc13892_gpo_regulator_is_enabled, | 390 | .is_enabled = mc13892_gpo_regulator_is_enabled, |
| 397 | .list_voltage = regulator_list_voltage_table, | 391 | .list_voltage = regulator_list_voltage_table, |
| 398 | .set_voltage = mc13xxx_fixed_regulator_set_voltage, | 392 | .set_voltage = mc13xxx_fixed_regulator_set_voltage, |
| 399 | .get_voltage = mc13xxx_fixed_regulator_get_voltage, | ||
| 400 | }; | 393 | }; |
| 401 | 394 | ||
| 402 | static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev) | 395 | static int mc13892_sw_regulator_get_voltage_sel(struct regulator_dev *rdev) |
| 403 | { | 396 | { |
| 404 | struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); | 397 | struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); |
| 405 | int ret, id = rdev_get_id(rdev); | 398 | int ret, id = rdev_get_id(rdev); |
| 406 | unsigned int val, hi; | 399 | unsigned int val; |
| 407 | 400 | ||
| 408 | dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); | 401 | dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); |
| 409 | 402 | ||
| @@ -414,17 +407,11 @@ static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev) | |||
| 414 | if (ret) | 407 | if (ret) |
| 415 | return ret; | 408 | return ret; |
| 416 | 409 | ||
| 417 | hi = val & MC13892_SWITCHERS0_SWxHI; | ||
| 418 | val = (val & mc13892_regulators[id].vsel_mask) | 410 | val = (val & mc13892_regulators[id].vsel_mask) |
| 419 | >> mc13892_regulators[id].vsel_shift; | 411 | >> mc13892_regulators[id].vsel_shift; |
| 420 | 412 | ||
| 421 | dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); | 413 | dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); |
| 422 | 414 | ||
| 423 | if (hi) | ||
| 424 | val = (25000 * val) + 1100000; | ||
| 425 | else | ||
| 426 | val = (25000 * val) + 600000; | ||
| 427 | |||
| 428 | return val; | 415 | return val; |
| 429 | } | 416 | } |
| 430 | 417 | ||
| @@ -432,37 +419,25 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev, | |||
| 432 | unsigned selector) | 419 | unsigned selector) |
| 433 | { | 420 | { |
| 434 | struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); | 421 | struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); |
| 435 | int hi, value, mask, id = rdev_get_id(rdev); | 422 | int volt, mask, id = rdev_get_id(rdev); |
| 436 | u32 valread; | 423 | u32 reg_value; |
| 437 | int ret; | 424 | int ret; |
| 438 | 425 | ||
| 439 | value = rdev->desc->volt_table[selector]; | 426 | volt = rdev->desc->volt_table[selector]; |
| 427 | mask = mc13892_regulators[id].vsel_mask; | ||
| 428 | reg_value = selector << mc13892_regulators[id].vsel_shift; | ||
| 429 | |||
| 430 | if (volt > 1375000) { | ||
| 431 | mask |= MC13892_SWITCHERS0_SWxHI; | ||
| 432 | reg_value |= MC13892_SWITCHERS0_SWxHI; | ||
| 433 | } else if (volt < 1100000) { | ||
| 434 | mask |= MC13892_SWITCHERS0_SWxHI; | ||
| 435 | reg_value &= ~MC13892_SWITCHERS0_SWxHI; | ||
| 436 | } | ||
| 440 | 437 | ||
| 441 | mc13xxx_lock(priv->mc13xxx); | 438 | mc13xxx_lock(priv->mc13xxx); |
| 442 | ret = mc13xxx_reg_read(priv->mc13xxx, | 439 | ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg, mask, |
| 443 | mc13892_regulators[id].vsel_reg, &valread); | 440 | reg_value); |
| 444 | if (ret) | ||
| 445 | goto err; | ||
| 446 | |||
| 447 | if (value > 1375000) | ||
| 448 | hi = 1; | ||
| 449 | else if (value < 1100000) | ||
| 450 | hi = 0; | ||
| 451 | else | ||
| 452 | hi = valread & MC13892_SWITCHERS0_SWxHI; | ||
| 453 | |||
| 454 | if (hi) { | ||
| 455 | value = (value - 1100000) / 25000; | ||
| 456 | value |= MC13892_SWITCHERS0_SWxHI; | ||
| 457 | } else | ||
| 458 | value = (value - 600000) / 25000; | ||
| 459 | |||
| 460 | mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI; | ||
| 461 | valread = (valread & ~mask) | | ||
| 462 | (value << mc13892_regulators[id].vsel_shift); | ||
| 463 | ret = mc13xxx_reg_write(priv->mc13xxx, mc13892_regulators[id].vsel_reg, | ||
| 464 | valread); | ||
| 465 | err: | ||
| 466 | mc13xxx_unlock(priv->mc13xxx); | 441 | mc13xxx_unlock(priv->mc13xxx); |
| 467 | 442 | ||
| 468 | return ret; | 443 | return ret; |
| @@ -471,7 +446,7 @@ err: | |||
| 471 | static struct regulator_ops mc13892_sw_regulator_ops = { | 446 | static struct regulator_ops mc13892_sw_regulator_ops = { |
| 472 | .list_voltage = regulator_list_voltage_table, | 447 | .list_voltage = regulator_list_voltage_table, |
| 473 | .set_voltage_sel = mc13892_sw_regulator_set_voltage_sel, | 448 | .set_voltage_sel = mc13892_sw_regulator_set_voltage_sel, |
| 474 | .get_voltage = mc13892_sw_regulator_get_voltage, | 449 | .get_voltage_sel = mc13892_sw_regulator_get_voltage_sel, |
| 475 | }; | 450 | }; |
| 476 | 451 | ||
| 477 | static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode) | 452 | static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode) |
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index d6eda28ca5d0..88cbb832d555 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c | |||
| @@ -143,30 +143,21 @@ int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, | |||
| 143 | __func__, id, min_uV, max_uV); | 143 | __func__, id, min_uV, max_uV); |
| 144 | 144 | ||
| 145 | if (min_uV <= rdev->desc->volt_table[0] && | 145 | if (min_uV <= rdev->desc->volt_table[0] && |
| 146 | rdev->desc->volt_table[0] <= max_uV) | 146 | rdev->desc->volt_table[0] <= max_uV) { |
| 147 | *selector = 0; | ||
| 147 | return 0; | 148 | return 0; |
| 148 | else | 149 | } else { |
| 149 | return -EINVAL; | 150 | return -EINVAL; |
| 151 | } | ||
| 150 | } | 152 | } |
| 151 | EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_set_voltage); | 153 | EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_set_voltage); |
| 152 | 154 | ||
| 153 | int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev) | ||
| 154 | { | ||
| 155 | int id = rdev_get_id(rdev); | ||
| 156 | |||
| 157 | dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); | ||
| 158 | |||
| 159 | return rdev->desc->volt_table[0]; | ||
| 160 | } | ||
| 161 | EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_get_voltage); | ||
| 162 | |||
| 163 | struct regulator_ops mc13xxx_fixed_regulator_ops = { | 155 | struct regulator_ops mc13xxx_fixed_regulator_ops = { |
| 164 | .enable = mc13xxx_regulator_enable, | 156 | .enable = mc13xxx_regulator_enable, |
| 165 | .disable = mc13xxx_regulator_disable, | 157 | .disable = mc13xxx_regulator_disable, |
| 166 | .is_enabled = mc13xxx_regulator_is_enabled, | 158 | .is_enabled = mc13xxx_regulator_is_enabled, |
| 167 | .list_voltage = regulator_list_voltage_table, | 159 | .list_voltage = regulator_list_voltage_table, |
| 168 | .set_voltage = mc13xxx_fixed_regulator_set_voltage, | 160 | .set_voltage = mc13xxx_fixed_regulator_set_voltage, |
| 169 | .get_voltage = mc13xxx_fixed_regulator_get_voltage, | ||
| 170 | }; | 161 | }; |
| 171 | EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops); | 162 | EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops); |
| 172 | 163 | ||
diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h index eaff5510b6df..06c8903f182a 100644 --- a/drivers/regulator/mc13xxx.h +++ b/drivers/regulator/mc13xxx.h | |||
| @@ -34,7 +34,6 @@ struct mc13xxx_regulator_priv { | |||
| 34 | 34 | ||
| 35 | extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, | 35 | extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, |
| 36 | int min_uV, int max_uV, unsigned *selector); | 36 | int min_uV, int max_uV, unsigned *selector); |
| 37 | extern int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev); | ||
| 38 | 37 | ||
| 39 | #ifdef CONFIG_OF | 38 | #ifdef CONFIG_OF |
| 40 | extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev); | 39 | extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev); |
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 3e4106f2bda9..6f684916fd79 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c | |||
| @@ -92,16 +92,18 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, | |||
| 92 | EXPORT_SYMBOL_GPL(of_get_regulator_init_data); | 92 | EXPORT_SYMBOL_GPL(of_get_regulator_init_data); |
| 93 | 93 | ||
| 94 | /** | 94 | /** |
| 95 | * of_regulator_match - extract regulator init data when node | 95 | * of_regulator_match - extract multiple regulator init data from device tree. |
| 96 | * property "regulator-compatible" matches with the regulator name. | ||
| 97 | * @dev: device requesting the data | 96 | * @dev: device requesting the data |
| 98 | * @node: parent device node of the regulators | 97 | * @node: parent device node of the regulators |
| 99 | * @matches: match table for the regulators | 98 | * @matches: match table for the regulators |
| 100 | * @num_matches: number of entries in match table | 99 | * @num_matches: number of entries in match table |
| 101 | * | 100 | * |
| 102 | * This function uses a match table specified by the regulator driver and | 101 | * This function uses a match table specified by the regulator driver to |
| 103 | * looks up the corresponding init data in the device tree if | 102 | * parse regulator init data from the device tree. @node is expected to |
| 104 | * regulator-compatible matches. Note that the match table is modified | 103 | * contain a set of child nodes, each providing the init data for one |
| 104 | * regulator. The data parsed from a child node will be matched to a regulator | ||
| 105 | * based on either the deprecated property regulator-compatible if present, | ||
| 106 | * or otherwise the child node's name. Note that the match table is modified | ||
| 105 | * in place. | 107 | * in place. |
| 106 | * | 108 | * |
| 107 | * Returns the number of matches found or a negative error code on failure. | 109 | * Returns the number of matches found or a negative error code on failure. |
| @@ -112,26 +114,23 @@ int of_regulator_match(struct device *dev, struct device_node *node, | |||
| 112 | { | 114 | { |
| 113 | unsigned int count = 0; | 115 | unsigned int count = 0; |
| 114 | unsigned int i; | 116 | unsigned int i; |
| 115 | const char *regulator_comp; | 117 | const char *name; |
| 116 | struct device_node *child; | 118 | struct device_node *child; |
| 117 | 119 | ||
| 118 | if (!dev || !node) | 120 | if (!dev || !node) |
| 119 | return -EINVAL; | 121 | return -EINVAL; |
| 120 | 122 | ||
| 121 | for_each_child_of_node(node, child) { | 123 | for_each_child_of_node(node, child) { |
| 122 | regulator_comp = of_get_property(child, | 124 | name = of_get_property(child, |
| 123 | "regulator-compatible", NULL); | 125 | "regulator-compatible", NULL); |
| 124 | if (!regulator_comp) { | 126 | if (!name) |
| 125 | dev_err(dev, "regulator-compatible is missing for node %s\n", | 127 | name = child->name; |
| 126 | child->name); | ||
| 127 | continue; | ||
| 128 | } | ||
| 129 | for (i = 0; i < num_matches; i++) { | 128 | for (i = 0; i < num_matches; i++) { |
| 130 | struct of_regulator_match *match = &matches[i]; | 129 | struct of_regulator_match *match = &matches[i]; |
| 131 | if (match->of_node) | 130 | if (match->of_node) |
| 132 | continue; | 131 | continue; |
| 133 | 132 | ||
| 134 | if (strcmp(match->name, regulator_comp)) | 133 | if (strcmp(match->name, name)) |
| 135 | continue; | 134 | continue; |
| 136 | 135 | ||
| 137 | match->init_data = | 136 | match->init_data = |
diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 46c7e88f8381..2ba7502fa3b2 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c | |||
| @@ -443,44 +443,6 @@ static int palmas_list_voltage_ldo(struct regulator_dev *dev, | |||
| 443 | return 850000 + (selector * 50000); | 443 | return 850000 + (selector * 50000); |
| 444 | } | 444 | } |
| 445 | 445 | ||
| 446 | static int palmas_get_voltage_ldo_sel(struct regulator_dev *dev) | ||
| 447 | { | ||
| 448 | struct palmas_pmic *pmic = rdev_get_drvdata(dev); | ||
| 449 | int id = rdev_get_id(dev); | ||
| 450 | int selector; | ||
| 451 | unsigned int reg; | ||
| 452 | unsigned int addr; | ||
| 453 | |||
| 454 | addr = palmas_regs_info[id].vsel_addr; | ||
| 455 | |||
| 456 | palmas_ldo_read(pmic->palmas, addr, ®); | ||
| 457 | |||
| 458 | selector = reg & PALMAS_LDO1_VOLTAGE_VSEL_MASK; | ||
| 459 | |||
| 460 | /* Adjust selector to match list_voltage ranges */ | ||
| 461 | if (selector > 49) | ||
| 462 | selector = 49; | ||
| 463 | |||
| 464 | return selector; | ||
| 465 | } | ||
| 466 | |||
| 467 | static int palmas_set_voltage_ldo_sel(struct regulator_dev *dev, | ||
| 468 | unsigned selector) | ||
| 469 | { | ||
| 470 | struct palmas_pmic *pmic = rdev_get_drvdata(dev); | ||
| 471 | int id = rdev_get_id(dev); | ||
| 472 | unsigned int reg = 0; | ||
| 473 | unsigned int addr; | ||
| 474 | |||
| 475 | addr = palmas_regs_info[id].vsel_addr; | ||
| 476 | |||
| 477 | reg = selector; | ||
| 478 | |||
| 479 | palmas_ldo_write(pmic->palmas, addr, reg); | ||
| 480 | |||
| 481 | return 0; | ||
| 482 | } | ||
| 483 | |||
| 484 | static int palmas_map_voltage_ldo(struct regulator_dev *rdev, | 446 | static int palmas_map_voltage_ldo(struct regulator_dev *rdev, |
| 485 | int min_uV, int max_uV) | 447 | int min_uV, int max_uV) |
| 486 | { | 448 | { |
| @@ -505,8 +467,8 @@ static struct regulator_ops palmas_ops_ldo = { | |||
| 505 | .is_enabled = palmas_is_enabled_ldo, | 467 | .is_enabled = palmas_is_enabled_ldo, |
| 506 | .enable = regulator_enable_regmap, | 468 | .enable = regulator_enable_regmap, |
| 507 | .disable = regulator_disable_regmap, | 469 | .disable = regulator_disable_regmap, |
| 508 | .get_voltage_sel = palmas_get_voltage_ldo_sel, | 470 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
| 509 | .set_voltage_sel = palmas_set_voltage_ldo_sel, | 471 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
| 510 | .list_voltage = palmas_list_voltage_ldo, | 472 | .list_voltage = palmas_list_voltage_ldo, |
| 511 | .map_voltage = palmas_map_voltage_ldo, | 473 | .map_voltage = palmas_map_voltage_ldo, |
| 512 | }; | 474 | }; |
| @@ -757,6 +719,9 @@ static __devinit int palmas_probe(struct platform_device *pdev) | |||
| 757 | 719 | ||
| 758 | pmic->desc[id].type = REGULATOR_VOLTAGE; | 720 | pmic->desc[id].type = REGULATOR_VOLTAGE; |
| 759 | pmic->desc[id].owner = THIS_MODULE; | 721 | pmic->desc[id].owner = THIS_MODULE; |
| 722 | pmic->desc[id].vsel_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, | ||
| 723 | palmas_regs_info[id].vsel_addr); | ||
| 724 | pmic->desc[id].vsel_mask = PALMAS_LDO1_VOLTAGE_VSEL_MASK; | ||
| 760 | pmic->desc[id].enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, | 725 | pmic->desc[id].enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, |
| 761 | palmas_regs_info[id].ctrl_addr); | 726 | palmas_regs_info[id].ctrl_addr); |
| 762 | pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE; | 727 | pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE; |
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 4669dc9ac74a..926f9c8f2fac 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c | |||
| @@ -24,7 +24,7 @@ | |||
| 24 | #include <linux/mfd/samsung/s2mps11.h> | 24 | #include <linux/mfd/samsung/s2mps11.h> |
| 25 | 25 | ||
| 26 | struct s2mps11_info { | 26 | struct s2mps11_info { |
| 27 | struct regulator_dev **rdev; | 27 | struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX]; |
| 28 | 28 | ||
| 29 | int ramp_delay2; | 29 | int ramp_delay2; |
| 30 | int ramp_delay34; | 30 | int ramp_delay34; |
| @@ -236,9 +236,8 @@ static __devinit int s2mps11_pmic_probe(struct platform_device *pdev) | |||
| 236 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 236 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); |
| 237 | struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); | 237 | struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); |
| 238 | struct regulator_config config = { }; | 238 | struct regulator_config config = { }; |
| 239 | struct regulator_dev **rdev; | ||
| 240 | struct s2mps11_info *s2mps11; | 239 | struct s2mps11_info *s2mps11; |
| 241 | int i, ret, size; | 240 | int i, ret; |
| 242 | unsigned char ramp_enable, ramp_reg = 0; | 241 | unsigned char ramp_enable, ramp_reg = 0; |
| 243 | 242 | ||
| 244 | if (!pdata) { | 243 | if (!pdata) { |
| @@ -251,13 +250,6 @@ static __devinit int s2mps11_pmic_probe(struct platform_device *pdev) | |||
| 251 | if (!s2mps11) | 250 | if (!s2mps11) |
| 252 | return -ENOMEM; | 251 | return -ENOMEM; |
| 253 | 252 | ||
| 254 | size = sizeof(struct regulator_dev *) * S2MPS11_REGULATOR_MAX; | ||
| 255 | s2mps11->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); | ||
| 256 | if (!s2mps11->rdev) { | ||
| 257 | return -ENOMEM; | ||
| 258 | } | ||
| 259 | |||
| 260 | rdev = s2mps11->rdev; | ||
| 261 | platform_set_drvdata(pdev, s2mps11); | 253 | platform_set_drvdata(pdev, s2mps11); |
| 262 | 254 | ||
| 263 | s2mps11->ramp_delay2 = pdata->buck2_ramp_delay; | 255 | s2mps11->ramp_delay2 = pdata->buck2_ramp_delay; |
| @@ -297,12 +289,12 @@ static __devinit int s2mps11_pmic_probe(struct platform_device *pdev) | |||
| 297 | config.init_data = pdata->regulators[i].initdata; | 289 | config.init_data = pdata->regulators[i].initdata; |
| 298 | config.driver_data = s2mps11; | 290 | config.driver_data = s2mps11; |
| 299 | 291 | ||
| 300 | rdev[i] = regulator_register(®ulators[i], &config); | 292 | s2mps11->rdev[i] = regulator_register(®ulators[i], &config); |
| 301 | if (IS_ERR(rdev[i])) { | 293 | if (IS_ERR(s2mps11->rdev[i])) { |
| 302 | ret = PTR_ERR(rdev[i]); | 294 | ret = PTR_ERR(s2mps11->rdev[i]); |
| 303 | dev_err(&pdev->dev, "regulator init failed for %d\n", | 295 | dev_err(&pdev->dev, "regulator init failed for %d\n", |
| 304 | i); | 296 | i); |
| 305 | rdev[i] = NULL; | 297 | s2mps11->rdev[i] = NULL; |
| 306 | goto err; | 298 | goto err; |
| 307 | } | 299 | } |
| 308 | } | 300 | } |
| @@ -310,8 +302,7 @@ static __devinit int s2mps11_pmic_probe(struct platform_device *pdev) | |||
| 310 | return 0; | 302 | return 0; |
| 311 | err: | 303 | err: |
| 312 | for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) | 304 | for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) |
| 313 | if (rdev[i]) | 305 | regulator_unregister(s2mps11->rdev[i]); |
| 314 | regulator_unregister(rdev[i]); | ||
| 315 | 306 | ||
| 316 | return ret; | 307 | return ret; |
| 317 | } | 308 | } |
| @@ -319,12 +310,10 @@ err: | |||
| 319 | static int __devexit s2mps11_pmic_remove(struct platform_device *pdev) | 310 | static int __devexit s2mps11_pmic_remove(struct platform_device *pdev) |
| 320 | { | 311 | { |
| 321 | struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev); | 312 | struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev); |
| 322 | struct regulator_dev **rdev = s2mps11->rdev; | ||
| 323 | int i; | 313 | int i; |
| 324 | 314 | ||
| 325 | for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) | 315 | for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) |
| 326 | if (rdev[i]) | 316 | regulator_unregister(s2mps11->rdev[i]); |
| 327 | regulator_unregister(rdev[i]); | ||
| 328 | 317 | ||
| 329 | return 0; | 318 | return 0; |
| 330 | } | 319 | } |
diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 6caa222af77a..ab00cab905b7 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/err.h> | 22 | #include <linux/err.h> |
| 23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
| 24 | 24 | ||
| 25 | #include <linux/regulator/of_regulator.h> | ||
| 25 | #include <linux/regulator/driver.h> | 26 | #include <linux/regulator/driver.h> |
| 26 | #include <linux/regulator/machine.h> | 27 | #include <linux/regulator/machine.h> |
| 27 | #include <linux/mfd/tps65217.h> | 28 | #include <linux/mfd/tps65217.h> |
| @@ -281,37 +282,130 @@ static const struct regulator_desc regulators[] = { | |||
| 281 | NULL), | 282 | NULL), |
| 282 | }; | 283 | }; |
| 283 | 284 | ||
| 285 | #ifdef CONFIG_OF | ||
| 286 | static struct of_regulator_match reg_matches[] = { | ||
| 287 | { .name = "dcdc1", .driver_data = (void *)TPS65217_DCDC_1 }, | ||
| 288 | { .name = "dcdc2", .driver_data = (void *)TPS65217_DCDC_2 }, | ||
| 289 | { .name = "dcdc3", .driver_data = (void *)TPS65217_DCDC_3 }, | ||
| 290 | { .name = "ldo1", .driver_data = (void *)TPS65217_LDO_1 }, | ||
| 291 | { .name = "ldo2", .driver_data = (void *)TPS65217_LDO_2 }, | ||
| 292 | { .name = "ldo3", .driver_data = (void *)TPS65217_LDO_3 }, | ||
| 293 | { .name = "ldo4", .driver_data = (void *)TPS65217_LDO_4 }, | ||
| 294 | }; | ||
| 295 | |||
| 296 | static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev) | ||
| 297 | { | ||
| 298 | struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); | ||
| 299 | struct device_node *node = tps->dev->of_node; | ||
| 300 | struct tps65217_board *pdata; | ||
| 301 | struct device_node *regs; | ||
| 302 | int i, count; | ||
| 303 | |||
| 304 | regs = of_find_node_by_name(node, "regulators"); | ||
| 305 | if (!regs) | ||
| 306 | return NULL; | ||
| 307 | |||
| 308 | count = of_regulator_match(pdev->dev.parent, regs, | ||
| 309 | reg_matches, TPS65217_NUM_REGULATOR); | ||
| 310 | of_node_put(regs); | ||
| 311 | if ((count < 0) || (count > TPS65217_NUM_REGULATOR)) | ||
| 312 | return NULL; | ||
| 313 | |||
| 314 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
| 315 | if (!pdata) | ||
| 316 | return NULL; | ||
| 317 | |||
| 318 | for (i = 0; i < count; i++) { | ||
| 319 | if (!reg_matches[i].init_data || !reg_matches[i].of_node) | ||
| 320 | continue; | ||
| 321 | |||
| 322 | pdata->tps65217_init_data[i] = reg_matches[i].init_data; | ||
| 323 | pdata->of_node[i] = reg_matches[i].of_node; | ||
| 324 | } | ||
| 325 | |||
| 326 | return pdata; | ||
| 327 | } | ||
| 328 | #else | ||
| 329 | static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev) | ||
| 330 | { | ||
| 331 | return NULL; | ||
| 332 | } | ||
| 333 | #endif | ||
| 334 | |||
| 284 | static int __devinit tps65217_regulator_probe(struct platform_device *pdev) | 335 | static int __devinit tps65217_regulator_probe(struct platform_device *pdev) |
| 285 | { | 336 | { |
| 337 | struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); | ||
| 338 | struct tps65217_board *pdata = dev_get_platdata(tps->dev); | ||
| 339 | struct regulator_init_data *reg_data; | ||
| 286 | struct regulator_dev *rdev; | 340 | struct regulator_dev *rdev; |
| 287 | struct tps65217 *tps; | ||
| 288 | struct tps_info *info = &tps65217_pmic_regs[pdev->id]; | ||
| 289 | struct regulator_config config = { }; | 341 | struct regulator_config config = { }; |
| 342 | int i, ret; | ||
| 290 | 343 | ||
| 291 | /* Already set by core driver */ | 344 | if (tps->dev->of_node) |
| 292 | tps = dev_to_tps65217(pdev->dev.parent); | 345 | pdata = tps65217_parse_dt(pdev); |
| 293 | tps->info[pdev->id] = info; | ||
| 294 | 346 | ||
| 295 | config.dev = &pdev->dev; | 347 | if (!pdata) { |
| 296 | config.of_node = pdev->dev.of_node; | 348 | dev_err(&pdev->dev, "Platform data not found\n"); |
| 297 | config.init_data = pdev->dev.platform_data; | 349 | return -EINVAL; |
| 298 | config.driver_data = tps; | 350 | } |
| 299 | 351 | ||
| 300 | rdev = regulator_register(®ulators[pdev->id], &config); | 352 | if (tps65217_chip_id(tps) != TPS65217) { |
| 301 | if (IS_ERR(rdev)) | 353 | dev_err(&pdev->dev, "Invalid tps chip version\n"); |
| 302 | return PTR_ERR(rdev); | 354 | return -ENODEV; |
| 355 | } | ||
| 303 | 356 | ||
| 304 | platform_set_drvdata(pdev, rdev); | 357 | platform_set_drvdata(pdev, tps); |
| 305 | 358 | ||
| 359 | for (i = 0; i < TPS65217_NUM_REGULATOR; i++) { | ||
| 360 | |||
| 361 | reg_data = pdata->tps65217_init_data[i]; | ||
| 362 | |||
| 363 | /* | ||
| 364 | * Regulator API handles empty constraints but not NULL | ||
| 365 | * constraints | ||
| 366 | */ | ||
| 367 | if (!reg_data) | ||
| 368 | continue; | ||
| 369 | |||
| 370 | /* Register the regulators */ | ||
| 371 | tps->info[i] = &tps65217_pmic_regs[i]; | ||
| 372 | |||
| 373 | config.dev = tps->dev; | ||
| 374 | config.init_data = reg_data; | ||
| 375 | config.driver_data = tps; | ||
| 376 | config.regmap = tps->regmap; | ||
| 377 | if (tps->dev->of_node) | ||
| 378 | config.of_node = pdata->of_node[i]; | ||
| 379 | |||
| 380 | rdev = regulator_register(®ulators[i], &config); | ||
| 381 | if (IS_ERR(rdev)) { | ||
| 382 | dev_err(tps->dev, "failed to register %s regulator\n", | ||
| 383 | pdev->name); | ||
| 384 | ret = PTR_ERR(rdev); | ||
| 385 | goto err_unregister_regulator; | ||
| 386 | } | ||
| 387 | |||
| 388 | /* Save regulator for cleanup */ | ||
| 389 | tps->rdev[i] = rdev; | ||
| 390 | } | ||
| 306 | return 0; | 391 | return 0; |
| 392 | |||
| 393 | err_unregister_regulator: | ||
| 394 | while (--i >= 0) | ||
| 395 | regulator_unregister(tps->rdev[i]); | ||
| 396 | |||
| 397 | return ret; | ||
| 307 | } | 398 | } |
| 308 | 399 | ||
| 309 | static int __devexit tps65217_regulator_remove(struct platform_device *pdev) | 400 | static int __devexit tps65217_regulator_remove(struct platform_device *pdev) |
| 310 | { | 401 | { |
| 311 | struct regulator_dev *rdev = platform_get_drvdata(pdev); | 402 | struct tps65217 *tps = platform_get_drvdata(pdev); |
| 403 | unsigned int i; | ||
| 404 | |||
| 405 | for (i = 0; i < TPS65217_NUM_REGULATOR; i++) | ||
| 406 | regulator_unregister(tps->rdev[i]); | ||
| 312 | 407 | ||
| 313 | platform_set_drvdata(pdev, NULL); | 408 | platform_set_drvdata(pdev, NULL); |
| 314 | regulator_unregister(rdev); | ||
| 315 | 409 | ||
| 316 | return 0; | 410 | return 0; |
| 317 | } | 411 | } |
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 947ece933d90..058d2f2675e9 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c | |||
| @@ -502,15 +502,13 @@ static int set_current_limit(struct regulator_dev *rdev, int min_uA, | |||
| 502 | if (info->n_ilimsels == 1) | 502 | if (info->n_ilimsels == 1) |
| 503 | return -EINVAL; | 503 | return -EINVAL; |
| 504 | 504 | ||
| 505 | for (i = 0; i < info->n_ilimsels; i++) | 505 | for (i = info->n_ilimsels - 1; i >= 0; i--) { |
| 506 | if (min_uA <= info->ilimsels[i] && | 506 | if (min_uA <= info->ilimsels[i] && |
| 507 | max_uA >= info->ilimsels[i]) | 507 | max_uA >= info->ilimsels[i]) |
| 508 | break; | 508 | return write_field(hw, &info->ilimsel, i); |
| 509 | 509 | } | |
| 510 | if (i >= info->n_ilimsels) | ||
| 511 | return -EINVAL; | ||
| 512 | 510 | ||
| 513 | return write_field(hw, &info->ilimsel, i); | 511 | return -EINVAL; |
| 514 | } | 512 | } |
| 515 | 513 | ||
| 516 | static int get_current_limit(struct regulator_dev *rdev) | 514 | static int get_current_limit(struct regulator_dev *rdev) |
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 19241fc30050..ce1e7cb8d513 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c | |||
| @@ -57,9 +57,6 @@ | |||
| 57 | struct tps6586x_regulator { | 57 | struct tps6586x_regulator { |
| 58 | struct regulator_desc desc; | 58 | struct regulator_desc desc; |
| 59 | 59 | ||
| 60 | int volt_reg; | ||
| 61 | int volt_shift; | ||
| 62 | int volt_nbits; | ||
| 63 | int enable_bit[2]; | 60 | int enable_bit[2]; |
| 64 | int enable_reg[2]; | 61 | int enable_reg[2]; |
| 65 | 62 | ||
| @@ -81,10 +78,10 @@ static int tps6586x_set_voltage_sel(struct regulator_dev *rdev, | |||
| 81 | int ret, val, rid = rdev_get_id(rdev); | 78 | int ret, val, rid = rdev_get_id(rdev); |
| 82 | uint8_t mask; | 79 | uint8_t mask; |
| 83 | 80 | ||
| 84 | val = selector << ri->volt_shift; | 81 | val = selector << (ffs(rdev->desc->vsel_mask) - 1); |
| 85 | mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift; | 82 | mask = rdev->desc->vsel_mask; |
| 86 | 83 | ||
| 87 | ret = tps6586x_update(parent, ri->volt_reg, val, mask); | 84 | ret = tps6586x_update(parent, rdev->desc->vsel_reg, val, mask); |
| 88 | if (ret) | 85 | if (ret) |
| 89 | return ret; | 86 | return ret; |
| 90 | 87 | ||
| @@ -100,66 +97,17 @@ static int tps6586x_set_voltage_sel(struct regulator_dev *rdev, | |||
| 100 | return ret; | 97 | return ret; |
| 101 | } | 98 | } |
| 102 | 99 | ||
| 103 | static int tps6586x_get_voltage_sel(struct regulator_dev *rdev) | ||
| 104 | { | ||
| 105 | struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); | ||
| 106 | struct device *parent = to_tps6586x_dev(rdev); | ||
| 107 | uint8_t val, mask; | ||
| 108 | int ret; | ||
| 109 | |||
| 110 | ret = tps6586x_read(parent, ri->volt_reg, &val); | ||
| 111 | if (ret) | ||
| 112 | return ret; | ||
| 113 | |||
| 114 | mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift; | ||
| 115 | val = (val & mask) >> ri->volt_shift; | ||
| 116 | |||
| 117 | if (val >= ri->desc.n_voltages) | ||
| 118 | BUG(); | ||
| 119 | |||
| 120 | return val; | ||
| 121 | } | ||
| 122 | |||
| 123 | static int tps6586x_regulator_enable(struct regulator_dev *rdev) | ||
| 124 | { | ||
| 125 | struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); | ||
| 126 | struct device *parent = to_tps6586x_dev(rdev); | ||
| 127 | |||
| 128 | return tps6586x_set_bits(parent, ri->enable_reg[0], | ||
| 129 | 1 << ri->enable_bit[0]); | ||
| 130 | } | ||
| 131 | |||
| 132 | static int tps6586x_regulator_disable(struct regulator_dev *rdev) | ||
| 133 | { | ||
| 134 | struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); | ||
| 135 | struct device *parent = to_tps6586x_dev(rdev); | ||
| 136 | |||
| 137 | return tps6586x_clr_bits(parent, ri->enable_reg[0], | ||
| 138 | 1 << ri->enable_bit[0]); | ||
| 139 | } | ||
| 140 | |||
| 141 | static int tps6586x_regulator_is_enabled(struct regulator_dev *rdev) | ||
| 142 | { | ||
| 143 | struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); | ||
| 144 | struct device *parent = to_tps6586x_dev(rdev); | ||
| 145 | uint8_t reg_val; | ||
| 146 | int ret; | ||
| 147 | |||
| 148 | ret = tps6586x_read(parent, ri->enable_reg[0], ®_val); | ||
| 149 | if (ret) | ||
| 150 | return ret; | ||
| 151 | |||
| 152 | return !!(reg_val & (1 << ri->enable_bit[0])); | ||
| 153 | } | ||
| 154 | |||
| 155 | static struct regulator_ops tps6586x_regulator_ops = { | 100 | static struct regulator_ops tps6586x_regulator_ops = { |
| 156 | .list_voltage = regulator_list_voltage_table, | 101 | .list_voltage = regulator_list_voltage_table, |
| 157 | .get_voltage_sel = tps6586x_get_voltage_sel, | 102 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
| 158 | .set_voltage_sel = tps6586x_set_voltage_sel, | 103 | .set_voltage_sel = tps6586x_set_voltage_sel, |
| 159 | 104 | ||
| 160 | .is_enabled = tps6586x_regulator_is_enabled, | 105 | .is_enabled = regulator_is_enabled_regmap, |
| 161 | .enable = tps6586x_regulator_enable, | 106 | .enable = regulator_enable_regmap, |
| 162 | .disable = tps6586x_regulator_disable, | 107 | .disable = regulator_disable_regmap, |
| 108 | }; | ||
| 109 | |||
| 110 | static struct regulator_ops tps6586x_sys_regulator_ops = { | ||
| 163 | }; | 111 | }; |
| 164 | 112 | ||
| 165 | static const unsigned int tps6586x_ldo0_voltages[] = { | 113 | static const unsigned int tps6586x_ldo0_voltages[] = { |
| @@ -202,10 +150,11 @@ static const unsigned int tps6586x_dvm_voltages[] = { | |||
| 202 | .n_voltages = ARRAY_SIZE(tps6586x_##vdata##_voltages), \ | 150 | .n_voltages = ARRAY_SIZE(tps6586x_##vdata##_voltages), \ |
| 203 | .volt_table = tps6586x_##vdata##_voltages, \ | 151 | .volt_table = tps6586x_##vdata##_voltages, \ |
| 204 | .owner = THIS_MODULE, \ | 152 | .owner = THIS_MODULE, \ |
| 153 | .enable_reg = TPS6586X_SUPPLY##ereg0, \ | ||
| 154 | .enable_mask = 1 << (ebit0), \ | ||
| 155 | .vsel_reg = TPS6586X_##vreg, \ | ||
| 156 | .vsel_mask = ((1 << (nbits)) - 1) << (shift), \ | ||
| 205 | }, \ | 157 | }, \ |
| 206 | .volt_reg = TPS6586X_##vreg, \ | ||
| 207 | .volt_shift = (shift), \ | ||
| 208 | .volt_nbits = (nbits), \ | ||
| 209 | .enable_reg[0] = TPS6586X_SUPPLY##ereg0, \ | 158 | .enable_reg[0] = TPS6586X_SUPPLY##ereg0, \ |
| 210 | .enable_bit[0] = (ebit0), \ | 159 | .enable_bit[0] = (ebit0), \ |
| 211 | .enable_reg[1] = TPS6586X_SUPPLY##ereg1, \ | 160 | .enable_reg[1] = TPS6586X_SUPPLY##ereg1, \ |
| @@ -230,15 +179,28 @@ static const unsigned int tps6586x_dvm_voltages[] = { | |||
| 230 | TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ | 179 | TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ |
| 231 | } | 180 | } |
| 232 | 181 | ||
| 182 | #define TPS6586X_SYS_REGULATOR() \ | ||
| 183 | { \ | ||
| 184 | .desc = { \ | ||
| 185 | .supply_name = "sys", \ | ||
| 186 | .name = "REG-SYS", \ | ||
| 187 | .ops = &tps6586x_sys_regulator_ops, \ | ||
| 188 | .type = REGULATOR_VOLTAGE, \ | ||
| 189 | .id = TPS6586X_ID_SYS, \ | ||
| 190 | .owner = THIS_MODULE, \ | ||
| 191 | }, \ | ||
| 192 | } | ||
| 193 | |||
| 233 | static struct tps6586x_regulator tps6586x_regulator[] = { | 194 | static struct tps6586x_regulator tps6586x_regulator[] = { |
| 195 | TPS6586X_SYS_REGULATOR(), | ||
| 234 | TPS6586X_LDO(LDO_0, "vinldo01", ldo0, SUPPLYV1, 5, 3, ENC, 0, END, 0), | 196 | TPS6586X_LDO(LDO_0, "vinldo01", ldo0, SUPPLYV1, 5, 3, ENC, 0, END, 0), |
| 235 | TPS6586X_LDO(LDO_3, "vinldo23", ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2), | 197 | TPS6586X_LDO(LDO_3, "vinldo23", ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2), |
| 236 | TPS6586X_LDO(LDO_5, NULL, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6), | 198 | TPS6586X_LDO(LDO_5, "REG-SYS", ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6), |
| 237 | TPS6586X_LDO(LDO_6, "vinldo678", ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4), | 199 | TPS6586X_LDO(LDO_6, "vinldo678", ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4), |
| 238 | TPS6586X_LDO(LDO_7, "vinldo678", ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5), | 200 | TPS6586X_LDO(LDO_7, "vinldo678", ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5), |
| 239 | TPS6586X_LDO(LDO_8, "vinldo678", ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6), | 201 | TPS6586X_LDO(LDO_8, "vinldo678", ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6), |
| 240 | TPS6586X_LDO(LDO_9, "vinldo9", ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7), | 202 | TPS6586X_LDO(LDO_9, "vinldo9", ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7), |
| 241 | TPS6586X_LDO(LDO_RTC, NULL, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7), | 203 | TPS6586X_LDO(LDO_RTC, "REG-SYS", ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7), |
| 242 | TPS6586X_LDO(LDO_1, "vinldo01", dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1), | 204 | TPS6586X_LDO(LDO_1, "vinldo01", dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1), |
| 243 | TPS6586X_LDO(SM_2, "vin-sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7), | 205 | TPS6586X_LDO(SM_2, "vin-sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7), |
| 244 | 206 | ||
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 77a71a5c17c3..7eb986a40746 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c | |||
| @@ -10,6 +10,8 @@ | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/string.h> | ||
| 14 | #include <linux/slab.h> | ||
| 13 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 14 | #include <linux/err.h> | 16 | #include <linux/err.h> |
| 15 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
| @@ -624,18 +626,9 @@ static int twlfixed_list_voltage(struct regulator_dev *rdev, unsigned index) | |||
| 624 | return info->min_mV * 1000; | 626 | return info->min_mV * 1000; |
| 625 | } | 627 | } |
| 626 | 628 | ||
| 627 | static int twlfixed_get_voltage(struct regulator_dev *rdev) | ||
| 628 | { | ||
| 629 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
| 630 | |||
| 631 | return info->min_mV * 1000; | ||
| 632 | } | ||
| 633 | |||
| 634 | static struct regulator_ops twl4030fixed_ops = { | 629 | static struct regulator_ops twl4030fixed_ops = { |
| 635 | .list_voltage = twlfixed_list_voltage, | 630 | .list_voltage = twlfixed_list_voltage, |
| 636 | 631 | ||
| 637 | .get_voltage = twlfixed_get_voltage, | ||
| 638 | |||
| 639 | .enable = twl4030reg_enable, | 632 | .enable = twl4030reg_enable, |
| 640 | .disable = twl4030reg_disable, | 633 | .disable = twl4030reg_disable, |
| 641 | .is_enabled = twl4030reg_is_enabled, | 634 | .is_enabled = twl4030reg_is_enabled, |
| @@ -648,8 +641,6 @@ static struct regulator_ops twl4030fixed_ops = { | |||
| 648 | static struct regulator_ops twl6030fixed_ops = { | 641 | static struct regulator_ops twl6030fixed_ops = { |
| 649 | .list_voltage = twlfixed_list_voltage, | 642 | .list_voltage = twlfixed_list_voltage, |
| 650 | 643 | ||
| 651 | .get_voltage = twlfixed_get_voltage, | ||
| 652 | |||
| 653 | .enable = twl6030reg_enable, | 644 | .enable = twl6030reg_enable, |
| 654 | .disable = twl6030reg_disable, | 645 | .disable = twl6030reg_disable, |
| 655 | .is_enabled = twl6030reg_is_enabled, | 646 | .is_enabled = twl6030reg_is_enabled, |
| @@ -659,13 +650,6 @@ static struct regulator_ops twl6030fixed_ops = { | |||
| 659 | .get_status = twl6030reg_get_status, | 650 | .get_status = twl6030reg_get_status, |
| 660 | }; | 651 | }; |
| 661 | 652 | ||
| 662 | static struct regulator_ops twl6030_fixed_resource = { | ||
| 663 | .enable = twl6030reg_enable, | ||
| 664 | .disable = twl6030reg_disable, | ||
| 665 | .is_enabled = twl6030reg_is_enabled, | ||
| 666 | .get_status = twl6030reg_get_status, | ||
| 667 | }; | ||
| 668 | |||
| 669 | /* | 653 | /* |
| 670 | * SMPS status and control | 654 | * SMPS status and control |
| 671 | */ | 655 | */ |
| @@ -757,37 +741,32 @@ static int twl6030smps_list_voltage(struct regulator_dev *rdev, unsigned index) | |||
| 757 | return voltage; | 741 | return voltage; |
| 758 | } | 742 | } |
| 759 | 743 | ||
| 760 | static int | 744 | static int twl6030smps_map_voltage(struct regulator_dev *rdev, int min_uV, |
| 761 | twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, | 745 | int max_uV) |
| 762 | unsigned int *selector) | ||
| 763 | { | 746 | { |
| 764 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 747 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
| 765 | int vsel = 0; | 748 | int vsel = 0; |
| 766 | 749 | ||
| 767 | switch (info->flags) { | 750 | switch (info->flags) { |
| 768 | case 0: | 751 | case 0: |
| 769 | if (min_uV == 0) | 752 | if (min_uV == 0) |
| 770 | vsel = 0; | 753 | vsel = 0; |
| 771 | else if ((min_uV >= 600000) && (min_uV <= 1300000)) { | 754 | else if ((min_uV >= 600000) && (min_uV <= 1300000)) { |
| 772 | int calc_uV; | ||
| 773 | vsel = DIV_ROUND_UP(min_uV - 600000, 12500); | 755 | vsel = DIV_ROUND_UP(min_uV - 600000, 12500); |
| 774 | vsel++; | 756 | vsel++; |
| 775 | calc_uV = twl6030smps_list_voltage(rdev, vsel); | ||
| 776 | if (calc_uV > max_uV) | ||
| 777 | return -EINVAL; | ||
| 778 | } | 757 | } |
| 779 | /* Values 1..57 for vsel are linear and can be calculated | 758 | /* Values 1..57 for vsel are linear and can be calculated |
| 780 | * values 58..62 are non linear. | 759 | * values 58..62 are non linear. |
| 781 | */ | 760 | */ |
| 782 | else if ((min_uV > 1900000) && (max_uV >= 2100000)) | 761 | else if ((min_uV > 1900000) && (min_uV <= 2100000)) |
| 783 | vsel = 62; | 762 | vsel = 62; |
| 784 | else if ((min_uV > 1800000) && (max_uV >= 1900000)) | 763 | else if ((min_uV > 1800000) && (min_uV <= 1900000)) |
| 785 | vsel = 61; | 764 | vsel = 61; |
| 786 | else if ((min_uV > 1500000) && (max_uV >= 1800000)) | 765 | else if ((min_uV > 1500000) && (min_uV <= 1800000)) |
| 787 | vsel = 60; | 766 | vsel = 60; |
| 788 | else if ((min_uV > 1350000) && (max_uV >= 1500000)) | 767 | else if ((min_uV > 1350000) && (min_uV <= 1500000)) |
| 789 | vsel = 59; | 768 | vsel = 59; |
| 790 | else if ((min_uV > 1300000) && (max_uV >= 1350000)) | 769 | else if ((min_uV > 1300000) && (min_uV <= 1350000)) |
| 791 | vsel = 58; | 770 | vsel = 58; |
| 792 | else | 771 | else |
| 793 | return -EINVAL; | 772 | return -EINVAL; |
| @@ -796,25 +775,21 @@ twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, | |||
| 796 | if (min_uV == 0) | 775 | if (min_uV == 0) |
| 797 | vsel = 0; | 776 | vsel = 0; |
| 798 | else if ((min_uV >= 700000) && (min_uV <= 1420000)) { | 777 | else if ((min_uV >= 700000) && (min_uV <= 1420000)) { |
| 799 | int calc_uV; | ||
| 800 | vsel = DIV_ROUND_UP(min_uV - 700000, 12500); | 778 | vsel = DIV_ROUND_UP(min_uV - 700000, 12500); |
| 801 | vsel++; | 779 | vsel++; |
| 802 | calc_uV = twl6030smps_list_voltage(rdev, vsel); | ||
| 803 | if (calc_uV > max_uV) | ||
| 804 | return -EINVAL; | ||
| 805 | } | 780 | } |
| 806 | /* Values 1..57 for vsel are linear and can be calculated | 781 | /* Values 1..57 for vsel are linear and can be calculated |
| 807 | * values 58..62 are non linear. | 782 | * values 58..62 are non linear. |
| 808 | */ | 783 | */ |
| 809 | else if ((min_uV > 1900000) && (max_uV >= 2100000)) | 784 | else if ((min_uV > 1900000) && (min_uV <= 2100000)) |
| 810 | vsel = 62; | 785 | vsel = 62; |
| 811 | else if ((min_uV > 1800000) && (max_uV >= 1900000)) | 786 | else if ((min_uV > 1800000) && (min_uV <= 1900000)) |
| 812 | vsel = 61; | 787 | vsel = 61; |
| 813 | else if ((min_uV > 1350000) && (max_uV >= 1800000)) | 788 | else if ((min_uV > 1350000) && (min_uV <= 1800000)) |
| 814 | vsel = 60; | 789 | vsel = 60; |
| 815 | else if ((min_uV > 1350000) && (max_uV >= 1500000)) | 790 | else if ((min_uV > 1350000) && (min_uV <= 1500000)) |
| 816 | vsel = 59; | 791 | vsel = 59; |
| 817 | else if ((min_uV > 1300000) && (max_uV >= 1350000)) | 792 | else if ((min_uV > 1300000) && (min_uV <= 1350000)) |
| 818 | vsel = 58; | 793 | vsel = 58; |
| 819 | else | 794 | else |
| 820 | return -EINVAL; | 795 | return -EINVAL; |
| @@ -830,17 +805,23 @@ twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, | |||
| 830 | case SMPS_OFFSET_EN|SMPS_EXTENDED_EN: | 805 | case SMPS_OFFSET_EN|SMPS_EXTENDED_EN: |
| 831 | if (min_uV == 0) { | 806 | if (min_uV == 0) { |
| 832 | vsel = 0; | 807 | vsel = 0; |
| 833 | } else if ((min_uV >= 2161000) && (max_uV <= 4321000)) { | 808 | } else if ((min_uV >= 2161000) && (min_uV <= 4321000)) { |
| 834 | vsel = DIV_ROUND_UP(min_uV - 2161000, 38600); | 809 | vsel = DIV_ROUND_UP(min_uV - 2161000, 38600); |
| 835 | vsel++; | 810 | vsel++; |
| 836 | } | 811 | } |
| 837 | break; | 812 | break; |
| 838 | } | 813 | } |
| 839 | 814 | ||
| 840 | *selector = vsel; | 815 | return vsel; |
| 816 | } | ||
| 817 | |||
| 818 | static int twl6030smps_set_voltage_sel(struct regulator_dev *rdev, | ||
| 819 | unsigned int selector) | ||
| 820 | { | ||
| 821 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
| 841 | 822 | ||
| 842 | return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS, | 823 | return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS, |
| 843 | vsel); | 824 | selector); |
| 844 | } | 825 | } |
| 845 | 826 | ||
| 846 | static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev) | 827 | static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev) |
| @@ -852,8 +833,9 @@ static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev) | |||
| 852 | 833 | ||
| 853 | static struct regulator_ops twlsmps_ops = { | 834 | static struct regulator_ops twlsmps_ops = { |
| 854 | .list_voltage = twl6030smps_list_voltage, | 835 | .list_voltage = twl6030smps_list_voltage, |
| 836 | .map_voltage = twl6030smps_map_voltage, | ||
| 855 | 837 | ||
| 856 | .set_voltage = twl6030smps_set_voltage, | 838 | .set_voltage_sel = twl6030smps_set_voltage_sel, |
| 857 | .get_voltage_sel = twl6030smps_get_voltage_sel, | 839 | .get_voltage_sel = twl6030smps_get_voltage_sel, |
| 858 | 840 | ||
| 859 | .enable = twl6030reg_enable, | 841 | .enable = twl6030reg_enable, |
| @@ -876,7 +858,7 @@ static struct regulator_ops twlsmps_ops = { | |||
| 876 | 0x0, TWL6030, twl6030fixed_ops) | 858 | 0x0, TWL6030, twl6030fixed_ops) |
| 877 | 859 | ||
| 878 | #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \ | 860 | #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \ |
| 879 | static struct twlreg_info TWL4030_INFO_##label = { \ | 861 | static const struct twlreg_info TWL4030_INFO_##label = { \ |
| 880 | .base = offset, \ | 862 | .base = offset, \ |
| 881 | .id = num, \ | 863 | .id = num, \ |
| 882 | .table_len = ARRAY_SIZE(label##_VSEL_table), \ | 864 | .table_len = ARRAY_SIZE(label##_VSEL_table), \ |
| @@ -894,7 +876,7 @@ static struct twlreg_info TWL4030_INFO_##label = { \ | |||
| 894 | } | 876 | } |
| 895 | 877 | ||
| 896 | #define TWL4030_ADJUSTABLE_SMPS(label, offset, num, turnon_delay, remap_conf) \ | 878 | #define TWL4030_ADJUSTABLE_SMPS(label, offset, num, turnon_delay, remap_conf) \ |
| 897 | static struct twlreg_info TWL4030_INFO_##label = { \ | 879 | static const struct twlreg_info TWL4030_INFO_##label = { \ |
| 898 | .base = offset, \ | 880 | .base = offset, \ |
| 899 | .id = num, \ | 881 | .id = num, \ |
| 900 | .remap = remap_conf, \ | 882 | .remap = remap_conf, \ |
| @@ -909,7 +891,7 @@ static struct twlreg_info TWL4030_INFO_##label = { \ | |||
| 909 | } | 891 | } |
| 910 | 892 | ||
| 911 | #define TWL6030_ADJUSTABLE_SMPS(label) \ | 893 | #define TWL6030_ADJUSTABLE_SMPS(label) \ |
| 912 | static struct twlreg_info TWL6030_INFO_##label = { \ | 894 | static const struct twlreg_info TWL6030_INFO_##label = { \ |
| 913 | .desc = { \ | 895 | .desc = { \ |
| 914 | .name = #label, \ | 896 | .name = #label, \ |
| 915 | .id = TWL6030_REG_##label, \ | 897 | .id = TWL6030_REG_##label, \ |
| @@ -920,7 +902,7 @@ static struct twlreg_info TWL6030_INFO_##label = { \ | |||
| 920 | } | 902 | } |
| 921 | 903 | ||
| 922 | #define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \ | 904 | #define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \ |
| 923 | static struct twlreg_info TWL6030_INFO_##label = { \ | 905 | static const struct twlreg_info TWL6030_INFO_##label = { \ |
| 924 | .base = offset, \ | 906 | .base = offset, \ |
| 925 | .min_mV = min_mVolts, \ | 907 | .min_mV = min_mVolts, \ |
| 926 | .max_mV = max_mVolts, \ | 908 | .max_mV = max_mVolts, \ |
| @@ -935,7 +917,7 @@ static struct twlreg_info TWL6030_INFO_##label = { \ | |||
| 935 | } | 917 | } |
| 936 | 918 | ||
| 937 | #define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \ | 919 | #define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \ |
| 938 | static struct twlreg_info TWL6025_INFO_##label = { \ | 920 | static const struct twlreg_info TWL6025_INFO_##label = { \ |
| 939 | .base = offset, \ | 921 | .base = offset, \ |
| 940 | .min_mV = min_mVolts, \ | 922 | .min_mV = min_mVolts, \ |
| 941 | .max_mV = max_mVolts, \ | 923 | .max_mV = max_mVolts, \ |
| @@ -951,7 +933,7 @@ static struct twlreg_info TWL6025_INFO_##label = { \ | |||
| 951 | 933 | ||
| 952 | #define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \ | 934 | #define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \ |
| 953 | family, operations) \ | 935 | family, operations) \ |
| 954 | static struct twlreg_info TWLFIXED_INFO_##label = { \ | 936 | static const struct twlreg_info TWLFIXED_INFO_##label = { \ |
| 955 | .base = offset, \ | 937 | .base = offset, \ |
| 956 | .id = num, \ | 938 | .id = num, \ |
| 957 | .min_mV = mVolts, \ | 939 | .min_mV = mVolts, \ |
| @@ -981,7 +963,7 @@ static struct twlreg_info TWLRES_INFO_##label = { \ | |||
| 981 | } | 963 | } |
| 982 | 964 | ||
| 983 | #define TWL6025_ADJUSTABLE_SMPS(label, offset) \ | 965 | #define TWL6025_ADJUSTABLE_SMPS(label, offset) \ |
| 984 | static struct twlreg_info TWLSMPS_INFO_##label = { \ | 966 | static const struct twlreg_info TWLSMPS_INFO_##label = { \ |
| 985 | .base = offset, \ | 967 | .base = offset, \ |
| 986 | .min_mV = 600, \ | 968 | .min_mV = 600, \ |
| 987 | .max_mV = 2100, \ | 969 | .max_mV = 2100, \ |
| @@ -1138,6 +1120,7 @@ static int __devinit twlreg_probe(struct platform_device *pdev) | |||
| 1138 | { | 1120 | { |
| 1139 | int i, id; | 1121 | int i, id; |
| 1140 | struct twlreg_info *info; | 1122 | struct twlreg_info *info; |
| 1123 | const struct twlreg_info *template; | ||
| 1141 | struct regulator_init_data *initdata; | 1124 | struct regulator_init_data *initdata; |
| 1142 | struct regulation_constraints *c; | 1125 | struct regulation_constraints *c; |
| 1143 | struct regulator_dev *rdev; | 1126 | struct regulator_dev *rdev; |
| @@ -1147,17 +1130,17 @@ static int __devinit twlreg_probe(struct platform_device *pdev) | |||
| 1147 | 1130 | ||
| 1148 | match = of_match_device(twl_of_match, &pdev->dev); | 1131 | match = of_match_device(twl_of_match, &pdev->dev); |
| 1149 | if (match) { | 1132 | if (match) { |
| 1150 | info = match->data; | 1133 | template = match->data; |
| 1151 | id = info->desc.id; | 1134 | id = template->desc.id; |
| 1152 | initdata = of_get_regulator_init_data(&pdev->dev, | 1135 | initdata = of_get_regulator_init_data(&pdev->dev, |
| 1153 | pdev->dev.of_node); | 1136 | pdev->dev.of_node); |
| 1154 | drvdata = NULL; | 1137 | drvdata = NULL; |
| 1155 | } else { | 1138 | } else { |
| 1156 | id = pdev->id; | 1139 | id = pdev->id; |
| 1157 | initdata = pdev->dev.platform_data; | 1140 | initdata = pdev->dev.platform_data; |
| 1158 | for (i = 0, info = NULL; i < ARRAY_SIZE(twl_of_match); i++) { | 1141 | for (i = 0, template = NULL; i < ARRAY_SIZE(twl_of_match); i++) { |
| 1159 | info = twl_of_match[i].data; | 1142 | template = twl_of_match[i].data; |
| 1160 | if (info && info->desc.id == id) | 1143 | if (template && template->desc.id == id) |
| 1161 | break; | 1144 | break; |
| 1162 | } | 1145 | } |
| 1163 | if (i == ARRAY_SIZE(twl_of_match)) | 1146 | if (i == ARRAY_SIZE(twl_of_match)) |
| @@ -1168,12 +1151,16 @@ static int __devinit twlreg_probe(struct platform_device *pdev) | |||
| 1168 | return -EINVAL; | 1151 | return -EINVAL; |
| 1169 | } | 1152 | } |
| 1170 | 1153 | ||
| 1171 | if (!info) | 1154 | if (!template) |
| 1172 | return -ENODEV; | 1155 | return -ENODEV; |
| 1173 | 1156 | ||
| 1174 | if (!initdata) | 1157 | if (!initdata) |
| 1175 | return -EINVAL; | 1158 | return -EINVAL; |
| 1176 | 1159 | ||
| 1160 | info = kmemdup(template, sizeof (*info), GFP_KERNEL); | ||
| 1161 | if (!info) | ||
| 1162 | return -ENOMEM; | ||
| 1163 | |||
| 1177 | if (drvdata) { | 1164 | if (drvdata) { |
| 1178 | /* copy the driver data into regulator data */ | 1165 | /* copy the driver data into regulator data */ |
| 1179 | info->features = drvdata->features; | 1166 | info->features = drvdata->features; |
| @@ -1234,6 +1221,7 @@ static int __devinit twlreg_probe(struct platform_device *pdev) | |||
| 1234 | if (IS_ERR(rdev)) { | 1221 | if (IS_ERR(rdev)) { |
| 1235 | dev_err(&pdev->dev, "can't register %s, %ld\n", | 1222 | dev_err(&pdev->dev, "can't register %s, %ld\n", |
| 1236 | info->desc.name, PTR_ERR(rdev)); | 1223 | info->desc.name, PTR_ERR(rdev)); |
| 1224 | kfree(info); | ||
| 1237 | return PTR_ERR(rdev); | 1225 | return PTR_ERR(rdev); |
| 1238 | } | 1226 | } |
| 1239 | platform_set_drvdata(pdev, rdev); | 1227 | platform_set_drvdata(pdev, rdev); |
| @@ -1255,7 +1243,11 @@ static int __devinit twlreg_probe(struct platform_device *pdev) | |||
| 1255 | 1243 | ||
| 1256 | static int __devexit twlreg_remove(struct platform_device *pdev) | 1244 | static int __devexit twlreg_remove(struct platform_device *pdev) |
| 1257 | { | 1245 | { |
| 1258 | regulator_unregister(platform_get_drvdata(pdev)); | 1246 | struct regulator_dev *rdev = platform_get_drvdata(pdev); |
| 1247 | struct twlreg_info *info = rdev->reg_data; | ||
| 1248 | |||
| 1249 | regulator_unregister(rdev); | ||
| 1250 | kfree(info); | ||
| 1259 | return 0; | 1251 | return 0; |
| 1260 | } | 1252 | } |
| 1261 | 1253 | ||
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 7413885be01b..90cbcc683704 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c | |||
| @@ -339,16 +339,15 @@ static int wm831x_buckv_set_current_limit(struct regulator_dev *rdev, | |||
| 339 | u16 reg = dcdc->base + WM831X_DCDC_CONTROL_2; | 339 | u16 reg = dcdc->base + WM831X_DCDC_CONTROL_2; |
| 340 | int i; | 340 | int i; |
| 341 | 341 | ||
| 342 | for (i = 0; i < ARRAY_SIZE(wm831x_dcdc_ilim); i++) { | 342 | for (i = ARRAY_SIZE(wm831x_dcdc_ilim) - 1; i >= 0; i--) { |
| 343 | if ((min_uA <= wm831x_dcdc_ilim[i]) && | 343 | if ((min_uA <= wm831x_dcdc_ilim[i]) && |
| 344 | (wm831x_dcdc_ilim[i] <= max_uA)) | 344 | (wm831x_dcdc_ilim[i] <= max_uA)) |
| 345 | break; | 345 | return wm831x_set_bits(wm831x, reg, |
| 346 | WM831X_DC1_HC_THR_MASK, | ||
| 347 | i << WM831X_DC1_HC_THR_SHIFT); | ||
| 346 | } | 348 | } |
| 347 | if (i == ARRAY_SIZE(wm831x_dcdc_ilim)) | ||
| 348 | return -EINVAL; | ||
| 349 | 349 | ||
| 350 | return wm831x_set_bits(wm831x, reg, WM831X_DC1_HC_THR_MASK, | 350 | return -EINVAL; |
| 351 | i << WM831X_DC1_HC_THR_SHIFT); | ||
| 352 | } | 351 | } |
| 353 | 352 | ||
| 354 | static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev) | 353 | static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev) |
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 5cb70ca1e98d..9af512672be1 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c | |||
| @@ -205,6 +205,8 @@ static int wm831x_gp_ldo_get_status(struct regulator_dev *rdev) | |||
| 205 | 205 | ||
| 206 | /* Is it reporting under voltage? */ | 206 | /* Is it reporting under voltage? */ |
| 207 | ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS); | 207 | ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS); |
| 208 | if (ret < 0) | ||
| 209 | return ret; | ||
| 208 | if (ret & mask) | 210 | if (ret & mask) |
| 209 | return REGULATOR_STATUS_ERROR; | 211 | return REGULATOR_STATUS_ERROR; |
| 210 | 212 | ||
| @@ -237,6 +239,8 @@ static struct regulator_ops wm831x_gp_ldo_ops = { | |||
| 237 | .set_mode = wm831x_gp_ldo_set_mode, | 239 | .set_mode = wm831x_gp_ldo_set_mode, |
| 238 | .get_status = wm831x_gp_ldo_get_status, | 240 | .get_status = wm831x_gp_ldo_get_status, |
| 239 | .get_optimum_mode = wm831x_gp_ldo_get_optimum_mode, | 241 | .get_optimum_mode = wm831x_gp_ldo_get_optimum_mode, |
| 242 | .get_bypass = regulator_get_bypass_regmap, | ||
| 243 | .set_bypass = regulator_set_bypass_regmap, | ||
| 240 | 244 | ||
| 241 | .is_enabled = regulator_is_enabled_regmap, | 245 | .is_enabled = regulator_is_enabled_regmap, |
| 242 | .enable = regulator_enable_regmap, | 246 | .enable = regulator_enable_regmap, |
| @@ -293,6 +297,8 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) | |||
| 293 | ldo->desc.vsel_mask = WM831X_LDO1_ON_VSEL_MASK; | 297 | ldo->desc.vsel_mask = WM831X_LDO1_ON_VSEL_MASK; |
| 294 | ldo->desc.enable_reg = WM831X_LDO_ENABLE; | 298 | ldo->desc.enable_reg = WM831X_LDO_ENABLE; |
| 295 | ldo->desc.enable_mask = 1 << id; | 299 | ldo->desc.enable_mask = 1 << id; |
| 300 | ldo->desc.bypass_reg = ldo->base; | ||
| 301 | ldo->desc.bypass_mask = WM831X_LDO1_SWI; | ||
| 296 | 302 | ||
| 297 | config.dev = pdev->dev.parent; | 303 | config.dev = pdev->dev.parent; |
| 298 | if (pdata) | 304 | if (pdata) |
| @@ -469,6 +475,8 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev) | |||
| 469 | 475 | ||
| 470 | /* Is it reporting under voltage? */ | 476 | /* Is it reporting under voltage? */ |
| 471 | ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS); | 477 | ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS); |
| 478 | if (ret < 0) | ||
| 479 | return ret; | ||
| 472 | if (ret & mask) | 480 | if (ret & mask) |
| 473 | return REGULATOR_STATUS_ERROR; | 481 | return REGULATOR_STATUS_ERROR; |
| 474 | 482 | ||
| @@ -488,6 +496,8 @@ static struct regulator_ops wm831x_aldo_ops = { | |||
| 488 | .get_mode = wm831x_aldo_get_mode, | 496 | .get_mode = wm831x_aldo_get_mode, |
| 489 | .set_mode = wm831x_aldo_set_mode, | 497 | .set_mode = wm831x_aldo_set_mode, |
| 490 | .get_status = wm831x_aldo_get_status, | 498 | .get_status = wm831x_aldo_get_status, |
| 499 | .set_bypass = regulator_set_bypass_regmap, | ||
| 500 | .get_bypass = regulator_get_bypass_regmap, | ||
| 491 | 501 | ||
| 492 | .is_enabled = regulator_is_enabled_regmap, | 502 | .is_enabled = regulator_is_enabled_regmap, |
| 493 | .enable = regulator_enable_regmap, | 503 | .enable = regulator_enable_regmap, |
| @@ -544,6 +554,8 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev) | |||
| 544 | ldo->desc.vsel_mask = WM831X_LDO7_ON_VSEL_MASK; | 554 | ldo->desc.vsel_mask = WM831X_LDO7_ON_VSEL_MASK; |
| 545 | ldo->desc.enable_reg = WM831X_LDO_ENABLE; | 555 | ldo->desc.enable_reg = WM831X_LDO_ENABLE; |
| 546 | ldo->desc.enable_mask = 1 << id; | 556 | ldo->desc.enable_mask = 1 << id; |
| 557 | ldo->desc.bypass_reg = ldo->base; | ||
| 558 | ldo->desc.bypass_mask = WM831X_LDO7_SWI; | ||
| 547 | 559 | ||
| 548 | config.dev = pdev->dev.parent; | 560 | config.dev = pdev->dev.parent; |
| 549 | if (pdata) | 561 | if (pdata) |
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 9035dd053611..27c746ef0636 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c | |||
| @@ -120,13 +120,8 @@ static int wm8400_dcdc_set_mode(struct regulator_dev *dev, unsigned int mode) | |||
| 120 | 120 | ||
| 121 | case REGULATOR_MODE_IDLE: | 121 | case REGULATOR_MODE_IDLE: |
| 122 | /* Datasheet: standby */ | 122 | /* Datasheet: standby */ |
| 123 | ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset, | ||
| 124 | WM8400_DC1_ACTIVE, 0); | ||
| 125 | if (ret != 0) | ||
| 126 | return ret; | ||
| 127 | return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset, | 123 | return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset, |
| 128 | WM8400_DC1_SLEEP, 0); | 124 | WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP, 0); |
| 129 | |||
| 130 | default: | 125 | default: |
| 131 | return -EINVAL; | 126 | return -EINVAL; |
| 132 | } | 127 | } |
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 590cfafc7c17..1859f71372e2 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c | |||
| @@ -1008,8 +1008,8 @@ static int rpmsg_probe(struct virtio_device *vdev) | |||
| 1008 | return 0; | 1008 | return 0; |
| 1009 | 1009 | ||
| 1010 | free_coherent: | 1010 | free_coherent: |
| 1011 | dma_free_coherent(vdev->dev.parent, RPMSG_TOTAL_BUF_SPACE, bufs_va, | 1011 | dma_free_coherent(vdev->dev.parent->parent, RPMSG_TOTAL_BUF_SPACE, |
| 1012 | vrp->bufs_dma); | 1012 | bufs_va, vrp->bufs_dma); |
| 1013 | vqs_del: | 1013 | vqs_del: |
| 1014 | vdev->config->del_vqs(vrp->vdev); | 1014 | vdev->config->del_vqs(vrp->vdev); |
| 1015 | free_vrp: | 1015 | free_vrp: |
| @@ -1043,7 +1043,7 @@ static void __devexit rpmsg_remove(struct virtio_device *vdev) | |||
| 1043 | 1043 | ||
| 1044 | vdev->config->del_vqs(vrp->vdev); | 1044 | vdev->config->del_vqs(vrp->vdev); |
| 1045 | 1045 | ||
| 1046 | dma_free_coherent(vdev->dev.parent, RPMSG_TOTAL_BUF_SPACE, | 1046 | dma_free_coherent(vdev->dev.parent->parent, RPMSG_TOTAL_BUF_SPACE, |
| 1047 | vrp->rbufs, vrp->bufs_dma); | 1047 | vrp->rbufs, vrp->bufs_dma); |
| 1048 | 1048 | ||
| 1049 | kfree(vrp); | 1049 | kfree(vrp); |
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index c5d06fe83bba..9277d945bf48 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c | |||
| @@ -495,6 +495,11 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev) | |||
| 495 | if (ret < 0) | 495 | if (ret < 0) |
| 496 | goto out1; | 496 | goto out1; |
| 497 | 497 | ||
| 498 | /* ensure interrupts are disabled, bootloaders can be strange */ | ||
| 499 | ret = twl_rtc_write_u8(0, REG_RTC_INTERRUPTS_REG); | ||
| 500 | if (ret < 0) | ||
| 501 | dev_warn(&pdev->dev, "unable to disable interrupt\n"); | ||
| 502 | |||
| 498 | /* init cached IRQ enable bits */ | 503 | /* init cached IRQ enable bits */ |
| 499 | ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG); | 504 | ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG); |
| 500 | if (ret < 0) | 505 | if (ret < 0) |
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig index 8e477bb1f3f6..4a3b62326183 100644 --- a/drivers/s390/block/Kconfig +++ b/drivers/s390/block/Kconfig | |||
| @@ -70,3 +70,21 @@ config DASD_EER | |||
| 70 | This driver provides a character device interface to the | 70 | This driver provides a character device interface to the |
| 71 | DASD extended error reporting. This is only needed if you want to | 71 | DASD extended error reporting. This is only needed if you want to |
| 72 | use applications written for the EER facility. | 72 | use applications written for the EER facility. |
| 73 | |||
| 74 | config SCM_BLOCK | ||
| 75 | def_tristate m | ||
| 76 | prompt "Support for Storage Class Memory" | ||
| 77 | depends on S390 && BLOCK && EADM_SCH && SCM_BUS | ||
| 78 | help | ||
| 79 | Block device driver for Storage Class Memory (SCM). This driver | ||
| 80 | provides a block device interface for each available SCM increment. | ||
| 81 | |||
| 82 | To compile this driver as a module, choose M here: the | ||
| 83 | module will be called scm_block. | ||
| 84 | |||
| 85 | config SCM_BLOCK_CLUSTER_WRITE | ||
| 86 | def_bool y | ||
| 87 | prompt "SCM force cluster writes" | ||
| 88 | depends on SCM_BLOCK | ||
| 89 | help | ||
| 90 | Force writes to Storage Class Memory (SCM) to be in done in clusters. | ||
diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile index 0a89e080b389..c2f4e673e031 100644 --- a/drivers/s390/block/Makefile +++ b/drivers/s390/block/Makefile | |||
| @@ -17,3 +17,9 @@ obj-$(CONFIG_DASD_ECKD) += dasd_eckd_mod.o | |||
| 17 | obj-$(CONFIG_DASD_FBA) += dasd_fba_mod.o | 17 | obj-$(CONFIG_DASD_FBA) += dasd_fba_mod.o |
| 18 | obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o | 18 | obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o |
| 19 | obj-$(CONFIG_DCSSBLK) += dcssblk.o | 19 | obj-$(CONFIG_DCSSBLK) += dcssblk.o |
| 20 | |||
| 21 | scm_block-objs := scm_drv.o scm_blk.o | ||
| 22 | ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE | ||
| 23 | scm_block-objs += scm_blk_cluster.o | ||
| 24 | endif | ||
| 25 | obj-$(CONFIG_SCM_BLOCK) += scm_block.o | ||
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 15370a2c5ff0..0595c763dafd 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
| @@ -534,11 +534,11 @@ static void dasd_change_state(struct dasd_device *device) | |||
| 534 | if (rc) | 534 | if (rc) |
| 535 | device->target = device->state; | 535 | device->target = device->state; |
| 536 | 536 | ||
| 537 | if (device->state == device->target) | ||
| 538 | wake_up(&dasd_init_waitq); | ||
| 539 | |||
| 540 | /* let user-space know that the device status changed */ | 537 | /* let user-space know that the device status changed */ |
| 541 | kobject_uevent(&device->cdev->dev.kobj, KOBJ_CHANGE); | 538 | kobject_uevent(&device->cdev->dev.kobj, KOBJ_CHANGE); |
| 539 | |||
| 540 | if (device->state == device->target) | ||
| 541 | wake_up(&dasd_init_waitq); | ||
| 542 | } | 542 | } |
| 543 | 543 | ||
| 544 | /* | 544 | /* |
| @@ -2157,6 +2157,7 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible) | |||
| 2157 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && | 2157 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && |
| 2158 | (!dasd_eer_enabled(device))) { | 2158 | (!dasd_eer_enabled(device))) { |
| 2159 | cqr->status = DASD_CQR_FAILED; | 2159 | cqr->status = DASD_CQR_FAILED; |
| 2160 | cqr->intrc = -EAGAIN; | ||
| 2160 | continue; | 2161 | continue; |
| 2161 | } | 2162 | } |
| 2162 | /* Don't try to start requests if device is stopped */ | 2163 | /* Don't try to start requests if device is stopped */ |
| @@ -3270,6 +3271,16 @@ void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) | |||
| 3270 | dasd_schedule_device_bh(device); | 3271 | dasd_schedule_device_bh(device); |
| 3271 | } | 3272 | } |
| 3272 | if (path_event[chp] & PE_PATHGROUP_ESTABLISHED) { | 3273 | if (path_event[chp] & PE_PATHGROUP_ESTABLISHED) { |
| 3274 | if (!(device->path_data.opm & eventlpm) && | ||
| 3275 | !(device->path_data.tbvpm & eventlpm)) { | ||
| 3276 | /* | ||
| 3277 | * we can not establish a pathgroup on an | ||
| 3278 | * unavailable path, so trigger a path | ||
| 3279 | * verification first | ||
| 3280 | */ | ||
| 3281 | device->path_data.tbvpm |= eventlpm; | ||
| 3282 | dasd_schedule_device_bh(device); | ||
| 3283 | } | ||
| 3273 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | 3284 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
| 3274 | "Pathgroup re-established\n"); | 3285 | "Pathgroup re-established\n"); |
| 3275 | if (device->discipline->kick_validate) | 3286 | if (device->discipline->kick_validate) |
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 157defe5e069..6b556995bb33 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c | |||
| @@ -384,6 +384,29 @@ static void _remove_device_from_lcu(struct alias_lcu *lcu, | |||
| 384 | group->next = NULL; | 384 | group->next = NULL; |
| 385 | }; | 385 | }; |
| 386 | 386 | ||
| 387 | static int | ||
| 388 | suborder_not_supported(struct dasd_ccw_req *cqr) | ||
| 389 | { | ||
| 390 | char *sense; | ||
| 391 | char reason; | ||
| 392 | char msg_format; | ||
| 393 | char msg_no; | ||
| 394 | |||
| 395 | sense = dasd_get_sense(&cqr->irb); | ||
| 396 | if (!sense) | ||
| 397 | return 0; | ||
| 398 | |||
| 399 | reason = sense[0]; | ||
| 400 | msg_format = (sense[7] & 0xF0); | ||
| 401 | msg_no = (sense[7] & 0x0F); | ||
| 402 | |||
| 403 | /* command reject, Format 0 MSG 4 - invalid parameter */ | ||
| 404 | if ((reason == 0x80) && (msg_format == 0x00) && (msg_no == 0x04)) | ||
| 405 | return 1; | ||
| 406 | |||
| 407 | return 0; | ||
| 408 | } | ||
| 409 | |||
| 387 | static int read_unit_address_configuration(struct dasd_device *device, | 410 | static int read_unit_address_configuration(struct dasd_device *device, |
| 388 | struct alias_lcu *lcu) | 411 | struct alias_lcu *lcu) |
| 389 | { | 412 | { |
| @@ -435,6 +458,8 @@ static int read_unit_address_configuration(struct dasd_device *device, | |||
| 435 | 458 | ||
| 436 | do { | 459 | do { |
| 437 | rc = dasd_sleep_on(cqr); | 460 | rc = dasd_sleep_on(cqr); |
| 461 | if (rc && suborder_not_supported(cqr)) | ||
| 462 | return -EOPNOTSUPP; | ||
| 438 | } while (rc && (cqr->retries > 0)); | 463 | } while (rc && (cqr->retries > 0)); |
| 439 | if (rc) { | 464 | if (rc) { |
| 440 | spin_lock_irqsave(&lcu->lock, flags); | 465 | spin_lock_irqsave(&lcu->lock, flags); |
| @@ -521,7 +546,7 @@ static void lcu_update_work(struct work_struct *work) | |||
| 521 | * processing the data | 546 | * processing the data |
| 522 | */ | 547 | */ |
| 523 | spin_lock_irqsave(&lcu->lock, flags); | 548 | spin_lock_irqsave(&lcu->lock, flags); |
| 524 | if (rc || (lcu->flags & NEED_UAC_UPDATE)) { | 549 | if ((rc && (rc != -EOPNOTSUPP)) || (lcu->flags & NEED_UAC_UPDATE)) { |
| 525 | DBF_DEV_EVENT(DBF_WARNING, device, "could not update" | 550 | DBF_DEV_EVENT(DBF_WARNING, device, "could not update" |
| 526 | " alias data in lcu (rc = %d), retry later", rc); | 551 | " alias data in lcu (rc = %d), retry later", rc); |
| 527 | schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ); | 552 | schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ); |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 2fb2b9ea97ec..108332b44d98 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/compat.h> | 20 | #include <linux/compat.h> |
| 21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
| 22 | 22 | ||
| 23 | #include <asm/css_chars.h> | ||
| 23 | #include <asm/debug.h> | 24 | #include <asm/debug.h> |
| 24 | #include <asm/idals.h> | 25 | #include <asm/idals.h> |
| 25 | #include <asm/ebcdic.h> | 26 | #include <asm/ebcdic.h> |
| @@ -31,8 +32,6 @@ | |||
| 31 | 32 | ||
| 32 | #include "dasd_int.h" | 33 | #include "dasd_int.h" |
| 33 | #include "dasd_eckd.h" | 34 | #include "dasd_eckd.h" |
| 34 | #include "../cio/chsc.h" | ||
| 35 | |||
| 36 | 35 | ||
| 37 | #ifdef PRINTK_HEADER | 36 | #ifdef PRINTK_HEADER |
| 38 | #undef PRINTK_HEADER | 37 | #undef PRINTK_HEADER |
| @@ -140,6 +139,10 @@ dasd_eckd_set_online(struct ccw_device *cdev) | |||
| 140 | static const int sizes_trk0[] = { 28, 148, 84 }; | 139 | static const int sizes_trk0[] = { 28, 148, 84 }; |
| 141 | #define LABEL_SIZE 140 | 140 | #define LABEL_SIZE 140 |
| 142 | 141 | ||
| 142 | /* head and record addresses of count_area read in analysis ccw */ | ||
| 143 | static const int count_area_head[] = { 0, 0, 0, 0, 2 }; | ||
| 144 | static const int count_area_rec[] = { 1, 2, 3, 4, 1 }; | ||
| 145 | |||
| 143 | static inline unsigned int | 146 | static inline unsigned int |
| 144 | round_up_multiple(unsigned int no, unsigned int mult) | 147 | round_up_multiple(unsigned int no, unsigned int mult) |
| 145 | { | 148 | { |
| @@ -212,7 +215,7 @@ check_XRC (struct ccw1 *de_ccw, | |||
| 212 | 215 | ||
| 213 | rc = get_sync_clock(&data->ep_sys_time); | 216 | rc = get_sync_clock(&data->ep_sys_time); |
| 214 | /* Ignore return code if sync clock is switched off. */ | 217 | /* Ignore return code if sync clock is switched off. */ |
| 215 | if (rc == -ENOSYS || rc == -EACCES) | 218 | if (rc == -EOPNOTSUPP || rc == -EACCES) |
| 216 | rc = 0; | 219 | rc = 0; |
| 217 | 220 | ||
| 218 | de_ccw->count = sizeof(struct DE_eckd_data); | 221 | de_ccw->count = sizeof(struct DE_eckd_data); |
| @@ -323,7 +326,7 @@ static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata, | |||
| 323 | 326 | ||
| 324 | rc = get_sync_clock(&pfxdata->define_extent.ep_sys_time); | 327 | rc = get_sync_clock(&pfxdata->define_extent.ep_sys_time); |
| 325 | /* Ignore return code if sync clock is switched off. */ | 328 | /* Ignore return code if sync clock is switched off. */ |
| 326 | if (rc == -ENOSYS || rc == -EACCES) | 329 | if (rc == -EOPNOTSUPP || rc == -EACCES) |
| 327 | rc = 0; | 330 | rc = 0; |
| 328 | return rc; | 331 | return rc; |
| 329 | } | 332 | } |
| @@ -1507,7 +1510,8 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device, | |||
| 1507 | * call might change behaviour of DASD devices. | 1510 | * call might change behaviour of DASD devices. |
| 1508 | */ | 1511 | */ |
| 1509 | static int | 1512 | static int |
| 1510 | dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav) | 1513 | dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav, |
| 1514 | unsigned long flags) | ||
| 1511 | { | 1515 | { |
| 1512 | struct dasd_ccw_req *cqr; | 1516 | struct dasd_ccw_req *cqr; |
| 1513 | int rc; | 1517 | int rc; |
| @@ -1516,10 +1520,19 @@ dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav) | |||
| 1516 | if (IS_ERR(cqr)) | 1520 | if (IS_ERR(cqr)) |
| 1517 | return PTR_ERR(cqr); | 1521 | return PTR_ERR(cqr); |
| 1518 | 1522 | ||
| 1523 | /* | ||
| 1524 | * set flags e.g. turn on failfast, to prevent blocking | ||
| 1525 | * the calling function should handle failed requests | ||
| 1526 | */ | ||
| 1527 | cqr->flags |= flags; | ||
| 1528 | |||
| 1519 | rc = dasd_sleep_on(cqr); | 1529 | rc = dasd_sleep_on(cqr); |
| 1520 | if (!rc) | 1530 | if (!rc) |
| 1521 | /* trigger CIO to reprobe devices */ | 1531 | /* trigger CIO to reprobe devices */ |
| 1522 | css_schedule_reprobe(); | 1532 | css_schedule_reprobe(); |
| 1533 | else if (cqr->intrc == -EAGAIN) | ||
| 1534 | rc = -EAGAIN; | ||
| 1535 | |||
| 1523 | dasd_sfree_request(cqr, cqr->memdev); | 1536 | dasd_sfree_request(cqr, cqr->memdev); |
| 1524 | return rc; | 1537 | return rc; |
| 1525 | } | 1538 | } |
| @@ -1527,7 +1540,8 @@ dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav) | |||
| 1527 | /* | 1540 | /* |
| 1528 | * Valide storage server of current device. | 1541 | * Valide storage server of current device. |
| 1529 | */ | 1542 | */ |
| 1530 | static void dasd_eckd_validate_server(struct dasd_device *device) | 1543 | static int dasd_eckd_validate_server(struct dasd_device *device, |
| 1544 | unsigned long flags) | ||
| 1531 | { | 1545 | { |
| 1532 | int rc; | 1546 | int rc; |
| 1533 | struct dasd_eckd_private *private; | 1547 | struct dasd_eckd_private *private; |
| @@ -1536,17 +1550,18 @@ static void dasd_eckd_validate_server(struct dasd_device *device) | |||
| 1536 | private = (struct dasd_eckd_private *) device->private; | 1550 | private = (struct dasd_eckd_private *) device->private; |
| 1537 | if (private->uid.type == UA_BASE_PAV_ALIAS || | 1551 | if (private->uid.type == UA_BASE_PAV_ALIAS || |
| 1538 | private->uid.type == UA_HYPER_PAV_ALIAS) | 1552 | private->uid.type == UA_HYPER_PAV_ALIAS) |
| 1539 | return; | 1553 | return 0; |
| 1540 | if (dasd_nopav || MACHINE_IS_VM) | 1554 | if (dasd_nopav || MACHINE_IS_VM) |
| 1541 | enable_pav = 0; | 1555 | enable_pav = 0; |
| 1542 | else | 1556 | else |
| 1543 | enable_pav = 1; | 1557 | enable_pav = 1; |
| 1544 | rc = dasd_eckd_psf_ssc(device, enable_pav); | 1558 | rc = dasd_eckd_psf_ssc(device, enable_pav, flags); |
| 1545 | 1559 | ||
| 1546 | /* may be requested feature is not available on server, | 1560 | /* may be requested feature is not available on server, |
| 1547 | * therefore just report error and go ahead */ | 1561 | * therefore just report error and go ahead */ |
| 1548 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x " | 1562 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x " |
| 1549 | "returned rc=%d", private->uid.ssid, rc); | 1563 | "returned rc=%d", private->uid.ssid, rc); |
| 1564 | return rc; | ||
| 1550 | } | 1565 | } |
| 1551 | 1566 | ||
| 1552 | /* | 1567 | /* |
| @@ -1556,7 +1571,13 @@ static void dasd_eckd_do_validate_server(struct work_struct *work) | |||
| 1556 | { | 1571 | { |
| 1557 | struct dasd_device *device = container_of(work, struct dasd_device, | 1572 | struct dasd_device *device = container_of(work, struct dasd_device, |
| 1558 | kick_validate); | 1573 | kick_validate); |
| 1559 | dasd_eckd_validate_server(device); | 1574 | if (dasd_eckd_validate_server(device, DASD_CQR_FLAGS_FAILFAST) |
| 1575 | == -EAGAIN) { | ||
| 1576 | /* schedule worker again if failed */ | ||
| 1577 | schedule_work(&device->kick_validate); | ||
| 1578 | return; | ||
| 1579 | } | ||
| 1580 | |||
| 1560 | dasd_put_device(device); | 1581 | dasd_put_device(device); |
| 1561 | } | 1582 | } |
| 1562 | 1583 | ||
| @@ -1685,7 +1706,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
| 1685 | if (rc) | 1706 | if (rc) |
| 1686 | goto out_err2; | 1707 | goto out_err2; |
| 1687 | 1708 | ||
| 1688 | dasd_eckd_validate_server(device); | 1709 | dasd_eckd_validate_server(device, 0); |
| 1689 | 1710 | ||
| 1690 | /* device may report different configuration data after LCU setup */ | 1711 | /* device may report different configuration data after LCU setup */ |
| 1691 | rc = dasd_eckd_read_conf(device); | 1712 | rc = dasd_eckd_read_conf(device); |
| @@ -1922,7 +1943,10 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) | |||
| 1922 | count_area = NULL; | 1943 | count_area = NULL; |
| 1923 | for (i = 0; i < 3; i++) { | 1944 | for (i = 0; i < 3; i++) { |
| 1924 | if (private->count_area[i].kl != 4 || | 1945 | if (private->count_area[i].kl != 4 || |
| 1925 | private->count_area[i].dl != dasd_eckd_cdl_reclen(i) - 4) { | 1946 | private->count_area[i].dl != dasd_eckd_cdl_reclen(i) - 4 || |
| 1947 | private->count_area[i].cyl != 0 || | ||
| 1948 | private->count_area[i].head != count_area_head[i] || | ||
| 1949 | private->count_area[i].record != count_area_rec[i]) { | ||
| 1926 | private->uses_cdl = 0; | 1950 | private->uses_cdl = 0; |
| 1927 | break; | 1951 | break; |
| 1928 | } | 1952 | } |
| @@ -1934,7 +1958,10 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) | |||
| 1934 | for (i = 0; i < 5; i++) { | 1958 | for (i = 0; i < 5; i++) { |
| 1935 | if ((private->count_area[i].kl != 0) || | 1959 | if ((private->count_area[i].kl != 0) || |
| 1936 | (private->count_area[i].dl != | 1960 | (private->count_area[i].dl != |
| 1937 | private->count_area[0].dl)) | 1961 | private->count_area[0].dl) || |
| 1962 | private->count_area[i].cyl != 0 || | ||
| 1963 | private->count_area[i].head != count_area_head[i] || | ||
| 1964 | private->count_area[i].record != count_area_rec[i]) | ||
| 1938 | break; | 1965 | break; |
| 1939 | } | 1966 | } |
| 1940 | if (i == 5) | 1967 | if (i == 5) |
| @@ -4153,7 +4180,7 @@ static int dasd_eckd_restore_device(struct dasd_device *device) | |||
| 4153 | rc = dasd_alias_make_device_known_to_lcu(device); | 4180 | rc = dasd_alias_make_device_known_to_lcu(device); |
| 4154 | if (rc) | 4181 | if (rc) |
| 4155 | return rc; | 4182 | return rc; |
| 4156 | dasd_eckd_validate_server(device); | 4183 | dasd_eckd_validate_server(device, DASD_CQR_FLAGS_FAILFAST); |
| 4157 | 4184 | ||
| 4158 | /* RE-Read Configuration Data */ | 4185 | /* RE-Read Configuration Data */ |
| 4159 | rc = dasd_eckd_read_conf(device); | 4186 | rc = dasd_eckd_read_conf(device); |
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 654c6921a6d4..8252f37d04ed 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c | |||
| @@ -292,12 +292,12 @@ out: | |||
| 292 | #else | 292 | #else |
| 293 | static int dasd_ioctl_reset_profile(struct dasd_block *block) | 293 | static int dasd_ioctl_reset_profile(struct dasd_block *block) |
| 294 | { | 294 | { |
| 295 | return -ENOSYS; | 295 | return -ENOTTY; |
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp) | 298 | static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp) |
| 299 | { | 299 | { |
| 300 | return -ENOSYS; | 300 | return -ENOTTY; |
| 301 | } | 301 | } |
| 302 | #endif | 302 | #endif |
| 303 | 303 | ||
diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c new file mode 100644 index 000000000000..9978ad4433cb --- /dev/null +++ b/drivers/s390/block/scm_blk.c | |||
| @@ -0,0 +1,445 @@ | |||
| 1 | /* | ||
| 2 | * Block driver for s390 storage class memory. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #define KMSG_COMPONENT "scm_block" | ||
| 9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
| 10 | |||
| 11 | #include <linux/interrupt.h> | ||
| 12 | #include <linux/spinlock.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/blkdev.h> | ||
| 15 | #include <linux/genhd.h> | ||
| 16 | #include <linux/slab.h> | ||
| 17 | #include <linux/list.h> | ||
| 18 | #include <asm/eadm.h> | ||
| 19 | #include "scm_blk.h" | ||
| 20 | |||
| 21 | debug_info_t *scm_debug; | ||
| 22 | static int scm_major; | ||
| 23 | static DEFINE_SPINLOCK(list_lock); | ||
| 24 | static LIST_HEAD(inactive_requests); | ||
| 25 | static unsigned int nr_requests = 64; | ||
| 26 | static atomic_t nr_devices = ATOMIC_INIT(0); | ||
| 27 | module_param(nr_requests, uint, S_IRUGO); | ||
| 28 | MODULE_PARM_DESC(nr_requests, "Number of parallel requests."); | ||
| 29 | |||
| 30 | MODULE_DESCRIPTION("Block driver for s390 storage class memory."); | ||
| 31 | MODULE_LICENSE("GPL"); | ||
| 32 | MODULE_ALIAS("scm:scmdev*"); | ||
| 33 | |||
| 34 | static void __scm_free_rq(struct scm_request *scmrq) | ||
| 35 | { | ||
| 36 | struct aob_rq_header *aobrq = to_aobrq(scmrq); | ||
| 37 | |||
| 38 | free_page((unsigned long) scmrq->aob); | ||
| 39 | free_page((unsigned long) scmrq->aidaw); | ||
| 40 | __scm_free_rq_cluster(scmrq); | ||
| 41 | kfree(aobrq); | ||
| 42 | } | ||
| 43 | |||
| 44 | static void scm_free_rqs(void) | ||
| 45 | { | ||
| 46 | struct list_head *iter, *safe; | ||
| 47 | struct scm_request *scmrq; | ||
| 48 | |||
| 49 | spin_lock_irq(&list_lock); | ||
| 50 | list_for_each_safe(iter, safe, &inactive_requests) { | ||
| 51 | scmrq = list_entry(iter, struct scm_request, list); | ||
| 52 | list_del(&scmrq->list); | ||
| 53 | __scm_free_rq(scmrq); | ||
| 54 | } | ||
| 55 | spin_unlock_irq(&list_lock); | ||
| 56 | } | ||
| 57 | |||
| 58 | static int __scm_alloc_rq(void) | ||
| 59 | { | ||
| 60 | struct aob_rq_header *aobrq; | ||
| 61 | struct scm_request *scmrq; | ||
| 62 | |||
| 63 | aobrq = kzalloc(sizeof(*aobrq) + sizeof(*scmrq), GFP_KERNEL); | ||
| 64 | if (!aobrq) | ||
| 65 | return -ENOMEM; | ||
| 66 | |||
| 67 | scmrq = (void *) aobrq->data; | ||
| 68 | scmrq->aidaw = (void *) get_zeroed_page(GFP_DMA); | ||
| 69 | scmrq->aob = (void *) get_zeroed_page(GFP_DMA); | ||
| 70 | if (!scmrq->aob || !scmrq->aidaw) { | ||
| 71 | __scm_free_rq(scmrq); | ||
| 72 | return -ENOMEM; | ||
| 73 | } | ||
| 74 | |||
| 75 | if (__scm_alloc_rq_cluster(scmrq)) { | ||
| 76 | __scm_free_rq(scmrq); | ||
| 77 | return -ENOMEM; | ||
| 78 | } | ||
| 79 | |||
| 80 | INIT_LIST_HEAD(&scmrq->list); | ||
| 81 | spin_lock_irq(&list_lock); | ||
| 82 | list_add(&scmrq->list, &inactive_requests); | ||
| 83 | spin_unlock_irq(&list_lock); | ||
| 84 | |||
| 85 | return 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | static int scm_alloc_rqs(unsigned int nrqs) | ||
| 89 | { | ||
| 90 | int ret = 0; | ||
| 91 | |||
| 92 | while (nrqs-- && !ret) | ||
| 93 | ret = __scm_alloc_rq(); | ||
| 94 | |||
| 95 | return ret; | ||
| 96 | } | ||
| 97 | |||
| 98 | static struct scm_request *scm_request_fetch(void) | ||
| 99 | { | ||
| 100 | struct scm_request *scmrq = NULL; | ||
| 101 | |||
| 102 | spin_lock(&list_lock); | ||
| 103 | if (list_empty(&inactive_requests)) | ||
| 104 | goto out; | ||
| 105 | scmrq = list_first_entry(&inactive_requests, struct scm_request, list); | ||
| 106 | list_del(&scmrq->list); | ||
| 107 | out: | ||
| 108 | spin_unlock(&list_lock); | ||
| 109 | return scmrq; | ||
| 110 | } | ||
| 111 | |||
| 112 | static void scm_request_done(struct scm_request *scmrq) | ||
| 113 | { | ||
| 114 | unsigned long flags; | ||
| 115 | |||
| 116 | spin_lock_irqsave(&list_lock, flags); | ||
| 117 | list_add(&scmrq->list, &inactive_requests); | ||
| 118 | spin_unlock_irqrestore(&list_lock, flags); | ||
| 119 | } | ||
| 120 | |||
| 121 | static int scm_open(struct block_device *blkdev, fmode_t mode) | ||
| 122 | { | ||
| 123 | return scm_get_ref(); | ||
| 124 | } | ||
| 125 | |||
| 126 | static int scm_release(struct gendisk *gendisk, fmode_t mode) | ||
| 127 | { | ||
| 128 | scm_put_ref(); | ||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | static const struct block_device_operations scm_blk_devops = { | ||
| 133 | .owner = THIS_MODULE, | ||
| 134 | .open = scm_open, | ||
| 135 | .release = scm_release, | ||
| 136 | }; | ||
| 137 | |||
| 138 | static void scm_request_prepare(struct scm_request *scmrq) | ||
| 139 | { | ||
| 140 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
| 141 | struct scm_device *scmdev = bdev->gendisk->private_data; | ||
| 142 | struct aidaw *aidaw = scmrq->aidaw; | ||
| 143 | struct msb *msb = &scmrq->aob->msb[0]; | ||
| 144 | struct req_iterator iter; | ||
| 145 | struct bio_vec *bv; | ||
| 146 | |||
| 147 | msb->bs = MSB_BS_4K; | ||
| 148 | scmrq->aob->request.msb_count = 1; | ||
| 149 | msb->scm_addr = scmdev->address + | ||
| 150 | ((u64) blk_rq_pos(scmrq->request) << 9); | ||
| 151 | msb->oc = (rq_data_dir(scmrq->request) == READ) ? | ||
| 152 | MSB_OC_READ : MSB_OC_WRITE; | ||
| 153 | msb->flags |= MSB_FLAG_IDA; | ||
| 154 | msb->data_addr = (u64) aidaw; | ||
| 155 | |||
| 156 | rq_for_each_segment(bv, scmrq->request, iter) { | ||
| 157 | WARN_ON(bv->bv_offset); | ||
| 158 | msb->blk_count += bv->bv_len >> 12; | ||
| 159 | aidaw->data_addr = (u64) page_address(bv->bv_page); | ||
| 160 | aidaw++; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | static inline void scm_request_init(struct scm_blk_dev *bdev, | ||
| 165 | struct scm_request *scmrq, | ||
| 166 | struct request *req) | ||
| 167 | { | ||
| 168 | struct aob_rq_header *aobrq = to_aobrq(scmrq); | ||
| 169 | struct aob *aob = scmrq->aob; | ||
| 170 | |||
| 171 | memset(aob, 0, sizeof(*aob)); | ||
| 172 | memset(scmrq->aidaw, 0, PAGE_SIZE); | ||
| 173 | aobrq->scmdev = bdev->scmdev; | ||
| 174 | aob->request.cmd_code = ARQB_CMD_MOVE; | ||
| 175 | aob->request.data = (u64) aobrq; | ||
| 176 | scmrq->request = req; | ||
| 177 | scmrq->bdev = bdev; | ||
| 178 | scmrq->retries = 4; | ||
| 179 | scmrq->error = 0; | ||
| 180 | scm_request_cluster_init(scmrq); | ||
| 181 | } | ||
| 182 | |||
| 183 | static void scm_ensure_queue_restart(struct scm_blk_dev *bdev) | ||
| 184 | { | ||
| 185 | if (atomic_read(&bdev->queued_reqs)) { | ||
| 186 | /* Queue restart is triggered by the next interrupt. */ | ||
| 187 | return; | ||
| 188 | } | ||
| 189 | blk_delay_queue(bdev->rq, SCM_QUEUE_DELAY); | ||
| 190 | } | ||
| 191 | |||
| 192 | void scm_request_requeue(struct scm_request *scmrq) | ||
| 193 | { | ||
| 194 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
| 195 | |||
| 196 | scm_release_cluster(scmrq); | ||
| 197 | blk_requeue_request(bdev->rq, scmrq->request); | ||
| 198 | scm_request_done(scmrq); | ||
| 199 | scm_ensure_queue_restart(bdev); | ||
| 200 | } | ||
| 201 | |||
| 202 | void scm_request_finish(struct scm_request *scmrq) | ||
| 203 | { | ||
| 204 | scm_release_cluster(scmrq); | ||
| 205 | blk_end_request_all(scmrq->request, scmrq->error); | ||
| 206 | scm_request_done(scmrq); | ||
| 207 | } | ||
| 208 | |||
| 209 | static void scm_blk_request(struct request_queue *rq) | ||
| 210 | { | ||
| 211 | struct scm_device *scmdev = rq->queuedata; | ||
| 212 | struct scm_blk_dev *bdev = dev_get_drvdata(&scmdev->dev); | ||
| 213 | struct scm_request *scmrq; | ||
| 214 | struct request *req; | ||
| 215 | int ret; | ||
| 216 | |||
| 217 | while ((req = blk_peek_request(rq))) { | ||
| 218 | if (req->cmd_type != REQ_TYPE_FS) | ||
| 219 | continue; | ||
| 220 | |||
| 221 | scmrq = scm_request_fetch(); | ||
| 222 | if (!scmrq) { | ||
| 223 | SCM_LOG(5, "no request"); | ||
| 224 | scm_ensure_queue_restart(bdev); | ||
| 225 | return; | ||
| 226 | } | ||
| 227 | scm_request_init(bdev, scmrq, req); | ||
| 228 | if (!scm_reserve_cluster(scmrq)) { | ||
| 229 | SCM_LOG(5, "cluster busy"); | ||
| 230 | scm_request_done(scmrq); | ||
| 231 | return; | ||
| 232 | } | ||
| 233 | if (scm_need_cluster_request(scmrq)) { | ||
| 234 | blk_start_request(req); | ||
| 235 | scm_initiate_cluster_request(scmrq); | ||
| 236 | return; | ||
| 237 | } | ||
| 238 | scm_request_prepare(scmrq); | ||
| 239 | blk_start_request(req); | ||
| 240 | |||
| 241 | ret = scm_start_aob(scmrq->aob); | ||
| 242 | if (ret) { | ||
| 243 | SCM_LOG(5, "no subchannel"); | ||
| 244 | scm_request_requeue(scmrq); | ||
| 245 | return; | ||
| 246 | } | ||
| 247 | atomic_inc(&bdev->queued_reqs); | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | static void __scmrq_log_error(struct scm_request *scmrq) | ||
| 252 | { | ||
| 253 | struct aob *aob = scmrq->aob; | ||
| 254 | |||
| 255 | if (scmrq->error == -ETIMEDOUT) | ||
| 256 | SCM_LOG(1, "Request timeout"); | ||
| 257 | else { | ||
| 258 | SCM_LOG(1, "Request error"); | ||
| 259 | SCM_LOG_HEX(1, &aob->response, sizeof(aob->response)); | ||
| 260 | } | ||
| 261 | if (scmrq->retries) | ||
| 262 | SCM_LOG(1, "Retry request"); | ||
| 263 | else | ||
| 264 | pr_err("An I/O operation to SCM failed with rc=%d\n", | ||
| 265 | scmrq->error); | ||
| 266 | } | ||
| 267 | |||
| 268 | void scm_blk_irq(struct scm_device *scmdev, void *data, int error) | ||
| 269 | { | ||
| 270 | struct scm_request *scmrq = data; | ||
| 271 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
| 272 | |||
| 273 | scmrq->error = error; | ||
| 274 | if (error) | ||
| 275 | __scmrq_log_error(scmrq); | ||
| 276 | |||
| 277 | spin_lock(&bdev->lock); | ||
| 278 | list_add_tail(&scmrq->list, &bdev->finished_requests); | ||
| 279 | spin_unlock(&bdev->lock); | ||
| 280 | tasklet_hi_schedule(&bdev->tasklet); | ||
| 281 | } | ||
| 282 | |||
| 283 | static void scm_blk_tasklet(struct scm_blk_dev *bdev) | ||
| 284 | { | ||
| 285 | struct scm_request *scmrq; | ||
| 286 | unsigned long flags; | ||
| 287 | |||
| 288 | spin_lock_irqsave(&bdev->lock, flags); | ||
| 289 | while (!list_empty(&bdev->finished_requests)) { | ||
| 290 | scmrq = list_first_entry(&bdev->finished_requests, | ||
| 291 | struct scm_request, list); | ||
| 292 | list_del(&scmrq->list); | ||
| 293 | spin_unlock_irqrestore(&bdev->lock, flags); | ||
| 294 | |||
| 295 | if (scmrq->error && scmrq->retries-- > 0) { | ||
| 296 | if (scm_start_aob(scmrq->aob)) { | ||
| 297 | spin_lock_irqsave(&bdev->rq_lock, flags); | ||
| 298 | scm_request_requeue(scmrq); | ||
| 299 | spin_unlock_irqrestore(&bdev->rq_lock, flags); | ||
| 300 | } | ||
| 301 | /* Request restarted or requeued, handle next. */ | ||
| 302 | spin_lock_irqsave(&bdev->lock, flags); | ||
| 303 | continue; | ||
| 304 | } | ||
| 305 | |||
| 306 | if (scm_test_cluster_request(scmrq)) { | ||
| 307 | scm_cluster_request_irq(scmrq); | ||
| 308 | spin_lock_irqsave(&bdev->lock, flags); | ||
| 309 | continue; | ||
| 310 | } | ||
| 311 | |||
| 312 | scm_request_finish(scmrq); | ||
| 313 | atomic_dec(&bdev->queued_reqs); | ||
| 314 | spin_lock_irqsave(&bdev->lock, flags); | ||
| 315 | } | ||
| 316 | spin_unlock_irqrestore(&bdev->lock, flags); | ||
| 317 | /* Look out for more requests. */ | ||
| 318 | blk_run_queue(bdev->rq); | ||
| 319 | } | ||
| 320 | |||
| 321 | int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev) | ||
| 322 | { | ||
| 323 | struct request_queue *rq; | ||
| 324 | int len, ret = -ENOMEM; | ||
| 325 | unsigned int devindex, nr_max_blk; | ||
| 326 | |||
| 327 | devindex = atomic_inc_return(&nr_devices) - 1; | ||
| 328 | /* scma..scmz + scmaa..scmzz */ | ||
| 329 | if (devindex > 701) { | ||
| 330 | ret = -ENODEV; | ||
| 331 | goto out; | ||
| 332 | } | ||
| 333 | |||
| 334 | bdev->scmdev = scmdev; | ||
| 335 | spin_lock_init(&bdev->rq_lock); | ||
| 336 | spin_lock_init(&bdev->lock); | ||
| 337 | INIT_LIST_HEAD(&bdev->finished_requests); | ||
| 338 | atomic_set(&bdev->queued_reqs, 0); | ||
| 339 | tasklet_init(&bdev->tasklet, | ||
| 340 | (void (*)(unsigned long)) scm_blk_tasklet, | ||
| 341 | (unsigned long) bdev); | ||
| 342 | |||
| 343 | rq = blk_init_queue(scm_blk_request, &bdev->rq_lock); | ||
| 344 | if (!rq) | ||
| 345 | goto out; | ||
| 346 | |||
| 347 | bdev->rq = rq; | ||
| 348 | nr_max_blk = min(scmdev->nr_max_block, | ||
| 349 | (unsigned int) (PAGE_SIZE / sizeof(struct aidaw))); | ||
| 350 | |||
| 351 | blk_queue_logical_block_size(rq, 1 << 12); | ||
| 352 | blk_queue_max_hw_sectors(rq, nr_max_blk << 3); /* 8 * 512 = blk_size */ | ||
| 353 | blk_queue_max_segments(rq, nr_max_blk); | ||
| 354 | queue_flag_set_unlocked(QUEUE_FLAG_NONROT, rq); | ||
| 355 | scm_blk_dev_cluster_setup(bdev); | ||
| 356 | |||
| 357 | bdev->gendisk = alloc_disk(SCM_NR_PARTS); | ||
| 358 | if (!bdev->gendisk) | ||
| 359 | goto out_queue; | ||
| 360 | |||
| 361 | rq->queuedata = scmdev; | ||
| 362 | bdev->gendisk->driverfs_dev = &scmdev->dev; | ||
| 363 | bdev->gendisk->private_data = scmdev; | ||
| 364 | bdev->gendisk->fops = &scm_blk_devops; | ||
| 365 | bdev->gendisk->queue = rq; | ||
| 366 | bdev->gendisk->major = scm_major; | ||
| 367 | bdev->gendisk->first_minor = devindex * SCM_NR_PARTS; | ||
| 368 | |||
| 369 | len = snprintf(bdev->gendisk->disk_name, DISK_NAME_LEN, "scm"); | ||
| 370 | if (devindex > 25) { | ||
| 371 | len += snprintf(bdev->gendisk->disk_name + len, | ||
| 372 | DISK_NAME_LEN - len, "%c", | ||
| 373 | 'a' + (devindex / 26) - 1); | ||
| 374 | devindex = devindex % 26; | ||
| 375 | } | ||
| 376 | snprintf(bdev->gendisk->disk_name + len, DISK_NAME_LEN - len, "%c", | ||
| 377 | 'a' + devindex); | ||
| 378 | |||
| 379 | /* 512 byte sectors */ | ||
| 380 | set_capacity(bdev->gendisk, scmdev->size >> 9); | ||
| 381 | add_disk(bdev->gendisk); | ||
| 382 | return 0; | ||
| 383 | |||
| 384 | out_queue: | ||
| 385 | blk_cleanup_queue(rq); | ||
| 386 | out: | ||
| 387 | atomic_dec(&nr_devices); | ||
| 388 | return ret; | ||
| 389 | } | ||
| 390 | |||
| 391 | void scm_blk_dev_cleanup(struct scm_blk_dev *bdev) | ||
| 392 | { | ||
| 393 | tasklet_kill(&bdev->tasklet); | ||
| 394 | del_gendisk(bdev->gendisk); | ||
| 395 | blk_cleanup_queue(bdev->gendisk->queue); | ||
| 396 | put_disk(bdev->gendisk); | ||
| 397 | } | ||
| 398 | |||
| 399 | static int __init scm_blk_init(void) | ||
| 400 | { | ||
| 401 | int ret = -EINVAL; | ||
| 402 | |||
| 403 | if (!scm_cluster_size_valid()) | ||
| 404 | goto out; | ||
| 405 | |||
| 406 | ret = register_blkdev(0, "scm"); | ||
| 407 | if (ret < 0) | ||
| 408 | goto out; | ||
| 409 | |||
| 410 | scm_major = ret; | ||
| 411 | if (scm_alloc_rqs(nr_requests)) | ||
| 412 | goto out_unreg; | ||
| 413 | |||
| 414 | scm_debug = debug_register("scm_log", 16, 1, 16); | ||
| 415 | if (!scm_debug) | ||
| 416 | goto out_free; | ||
| 417 | |||
| 418 | debug_register_view(scm_debug, &debug_hex_ascii_view); | ||
| 419 | debug_set_level(scm_debug, 2); | ||
| 420 | |||
| 421 | ret = scm_drv_init(); | ||
| 422 | if (ret) | ||
| 423 | goto out_dbf; | ||
| 424 | |||
| 425 | return ret; | ||
| 426 | |||
| 427 | out_dbf: | ||
| 428 | debug_unregister(scm_debug); | ||
| 429 | out_free: | ||
| 430 | scm_free_rqs(); | ||
| 431 | out_unreg: | ||
| 432 | unregister_blkdev(scm_major, "scm"); | ||
| 433 | out: | ||
| 434 | return ret; | ||
| 435 | } | ||
| 436 | module_init(scm_blk_init); | ||
| 437 | |||
| 438 | static void __exit scm_blk_cleanup(void) | ||
| 439 | { | ||
| 440 | scm_drv_cleanup(); | ||
| 441 | debug_unregister(scm_debug); | ||
| 442 | scm_free_rqs(); | ||
| 443 | unregister_blkdev(scm_major, "scm"); | ||
| 444 | } | ||
| 445 | module_exit(scm_blk_cleanup); | ||
diff --git a/drivers/s390/block/scm_blk.h b/drivers/s390/block/scm_blk.h new file mode 100644 index 000000000000..7ac6bad919ef --- /dev/null +++ b/drivers/s390/block/scm_blk.h | |||
| @@ -0,0 +1,117 @@ | |||
| 1 | #ifndef SCM_BLK_H | ||
| 2 | #define SCM_BLK_H | ||
| 3 | |||
| 4 | #include <linux/interrupt.h> | ||
| 5 | #include <linux/spinlock.h> | ||
| 6 | #include <linux/blkdev.h> | ||
| 7 | #include <linux/genhd.h> | ||
| 8 | #include <linux/list.h> | ||
| 9 | |||
| 10 | #include <asm/debug.h> | ||
| 11 | #include <asm/eadm.h> | ||
| 12 | |||
| 13 | #define SCM_NR_PARTS 8 | ||
| 14 | #define SCM_QUEUE_DELAY 5 | ||
| 15 | |||
| 16 | struct scm_blk_dev { | ||
| 17 | struct tasklet_struct tasklet; | ||
| 18 | struct request_queue *rq; | ||
| 19 | struct gendisk *gendisk; | ||
| 20 | struct scm_device *scmdev; | ||
| 21 | spinlock_t rq_lock; /* guard the request queue */ | ||
| 22 | spinlock_t lock; /* guard the rest of the blockdev */ | ||
| 23 | atomic_t queued_reqs; | ||
| 24 | struct list_head finished_requests; | ||
| 25 | #ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE | ||
| 26 | struct list_head cluster_list; | ||
| 27 | #endif | ||
| 28 | }; | ||
| 29 | |||
| 30 | struct scm_request { | ||
| 31 | struct scm_blk_dev *bdev; | ||
| 32 | struct request *request; | ||
| 33 | struct aidaw *aidaw; | ||
| 34 | struct aob *aob; | ||
| 35 | struct list_head list; | ||
| 36 | u8 retries; | ||
| 37 | int error; | ||
| 38 | #ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE | ||
| 39 | struct { | ||
| 40 | enum {CLUSTER_NONE, CLUSTER_READ, CLUSTER_WRITE} state; | ||
| 41 | struct list_head list; | ||
| 42 | void **buf; | ||
| 43 | } cluster; | ||
| 44 | #endif | ||
| 45 | }; | ||
| 46 | |||
| 47 | #define to_aobrq(rq) container_of((void *) rq, struct aob_rq_header, data) | ||
| 48 | |||
| 49 | int scm_blk_dev_setup(struct scm_blk_dev *, struct scm_device *); | ||
| 50 | void scm_blk_dev_cleanup(struct scm_blk_dev *); | ||
| 51 | void scm_blk_irq(struct scm_device *, void *, int); | ||
| 52 | |||
| 53 | void scm_request_finish(struct scm_request *); | ||
| 54 | void scm_request_requeue(struct scm_request *); | ||
| 55 | |||
| 56 | int scm_drv_init(void); | ||
| 57 | void scm_drv_cleanup(void); | ||
| 58 | |||
| 59 | #ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE | ||
| 60 | void __scm_free_rq_cluster(struct scm_request *); | ||
| 61 | int __scm_alloc_rq_cluster(struct scm_request *); | ||
| 62 | void scm_request_cluster_init(struct scm_request *); | ||
| 63 | bool scm_reserve_cluster(struct scm_request *); | ||
| 64 | void scm_release_cluster(struct scm_request *); | ||
| 65 | void scm_blk_dev_cluster_setup(struct scm_blk_dev *); | ||
| 66 | bool scm_need_cluster_request(struct scm_request *); | ||
| 67 | void scm_initiate_cluster_request(struct scm_request *); | ||
| 68 | void scm_cluster_request_irq(struct scm_request *); | ||
| 69 | bool scm_test_cluster_request(struct scm_request *); | ||
| 70 | bool scm_cluster_size_valid(void); | ||
| 71 | #else | ||
| 72 | #define __scm_free_rq_cluster(scmrq) {} | ||
| 73 | #define __scm_alloc_rq_cluster(scmrq) 0 | ||
| 74 | #define scm_request_cluster_init(scmrq) {} | ||
| 75 | #define scm_reserve_cluster(scmrq) true | ||
| 76 | #define scm_release_cluster(scmrq) {} | ||
| 77 | #define scm_blk_dev_cluster_setup(bdev) {} | ||
| 78 | #define scm_need_cluster_request(scmrq) false | ||
| 79 | #define scm_initiate_cluster_request(scmrq) {} | ||
| 80 | #define scm_cluster_request_irq(scmrq) {} | ||
| 81 | #define scm_test_cluster_request(scmrq) false | ||
| 82 | #define scm_cluster_size_valid() true | ||
| 83 | #endif | ||
| 84 | |||
| 85 | extern debug_info_t *scm_debug; | ||
| 86 | |||
| 87 | #define SCM_LOG(imp, txt) do { \ | ||
| 88 | debug_text_event(scm_debug, imp, txt); \ | ||
| 89 | } while (0) | ||
| 90 | |||
| 91 | static inline void SCM_LOG_HEX(int level, void *data, int length) | ||
| 92 | { | ||
| 93 | if (level > scm_debug->level) | ||
| 94 | return; | ||
| 95 | while (length > 0) { | ||
| 96 | debug_event(scm_debug, level, data, length); | ||
| 97 | length -= scm_debug->buf_size; | ||
| 98 | data += scm_debug->buf_size; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | static inline void SCM_LOG_STATE(int level, struct scm_device *scmdev) | ||
| 103 | { | ||
| 104 | struct { | ||
| 105 | u64 address; | ||
| 106 | u8 oper_state; | ||
| 107 | u8 rank; | ||
| 108 | } __packed data = { | ||
| 109 | .address = scmdev->address, | ||
| 110 | .oper_state = scmdev->attrs.oper_state, | ||
| 111 | .rank = scmdev->attrs.rank, | ||
| 112 | }; | ||
| 113 | |||
| 114 | SCM_LOG_HEX(level, &data, sizeof(data)); | ||
| 115 | } | ||
| 116 | |||
| 117 | #endif /* SCM_BLK_H */ | ||
diff --git a/drivers/s390/block/scm_blk_cluster.c b/drivers/s390/block/scm_blk_cluster.c new file mode 100644 index 000000000000..f4bb61b0cea1 --- /dev/null +++ b/drivers/s390/block/scm_blk_cluster.c | |||
| @@ -0,0 +1,228 @@ | |||
| 1 | /* | ||
| 2 | * Block driver for s390 storage class memory. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/spinlock.h> | ||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/blkdev.h> | ||
| 11 | #include <linux/genhd.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/list.h> | ||
| 14 | #include <asm/eadm.h> | ||
| 15 | #include "scm_blk.h" | ||
| 16 | |||
| 17 | static unsigned int write_cluster_size = 64; | ||
| 18 | module_param(write_cluster_size, uint, S_IRUGO); | ||
| 19 | MODULE_PARM_DESC(write_cluster_size, | ||
| 20 | "Number of pages used for contiguous writes."); | ||
| 21 | |||
| 22 | #define CLUSTER_SIZE (write_cluster_size * PAGE_SIZE) | ||
| 23 | |||
| 24 | void __scm_free_rq_cluster(struct scm_request *scmrq) | ||
| 25 | { | ||
| 26 | int i; | ||
| 27 | |||
| 28 | if (!scmrq->cluster.buf) | ||
| 29 | return; | ||
| 30 | |||
| 31 | for (i = 0; i < 2 * write_cluster_size; i++) | ||
| 32 | free_page((unsigned long) scmrq->cluster.buf[i]); | ||
| 33 | |||
| 34 | kfree(scmrq->cluster.buf); | ||
| 35 | } | ||
| 36 | |||
| 37 | int __scm_alloc_rq_cluster(struct scm_request *scmrq) | ||
| 38 | { | ||
| 39 | int i; | ||
| 40 | |||
| 41 | scmrq->cluster.buf = kzalloc(sizeof(void *) * 2 * write_cluster_size, | ||
| 42 | GFP_KERNEL); | ||
| 43 | if (!scmrq->cluster.buf) | ||
| 44 | return -ENOMEM; | ||
| 45 | |||
| 46 | for (i = 0; i < 2 * write_cluster_size; i++) { | ||
| 47 | scmrq->cluster.buf[i] = (void *) get_zeroed_page(GFP_DMA); | ||
| 48 | if (!scmrq->cluster.buf[i]) | ||
| 49 | return -ENOMEM; | ||
| 50 | } | ||
| 51 | INIT_LIST_HEAD(&scmrq->cluster.list); | ||
| 52 | return 0; | ||
| 53 | } | ||
| 54 | |||
| 55 | void scm_request_cluster_init(struct scm_request *scmrq) | ||
| 56 | { | ||
| 57 | scmrq->cluster.state = CLUSTER_NONE; | ||
| 58 | } | ||
| 59 | |||
| 60 | static bool clusters_intersect(struct scm_request *A, struct scm_request *B) | ||
| 61 | { | ||
| 62 | unsigned long firstA, lastA, firstB, lastB; | ||
| 63 | |||
| 64 | firstA = ((u64) blk_rq_pos(A->request) << 9) / CLUSTER_SIZE; | ||
| 65 | lastA = (((u64) blk_rq_pos(A->request) << 9) + | ||
| 66 | blk_rq_bytes(A->request) - 1) / CLUSTER_SIZE; | ||
| 67 | |||
| 68 | firstB = ((u64) blk_rq_pos(B->request) << 9) / CLUSTER_SIZE; | ||
| 69 | lastB = (((u64) blk_rq_pos(B->request) << 9) + | ||
| 70 | blk_rq_bytes(B->request) - 1) / CLUSTER_SIZE; | ||
| 71 | |||
| 72 | return (firstB <= lastA && firstA <= lastB); | ||
| 73 | } | ||
| 74 | |||
| 75 | bool scm_reserve_cluster(struct scm_request *scmrq) | ||
| 76 | { | ||
| 77 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
| 78 | struct scm_request *iter; | ||
| 79 | |||
| 80 | if (write_cluster_size == 0) | ||
| 81 | return true; | ||
| 82 | |||
| 83 | spin_lock(&bdev->lock); | ||
| 84 | list_for_each_entry(iter, &bdev->cluster_list, cluster.list) { | ||
| 85 | if (clusters_intersect(scmrq, iter) && | ||
| 86 | (rq_data_dir(scmrq->request) == WRITE || | ||
| 87 | rq_data_dir(iter->request) == WRITE)) { | ||
| 88 | spin_unlock(&bdev->lock); | ||
| 89 | return false; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | list_add(&scmrq->cluster.list, &bdev->cluster_list); | ||
| 93 | spin_unlock(&bdev->lock); | ||
| 94 | |||
| 95 | return true; | ||
| 96 | } | ||
| 97 | |||
| 98 | void scm_release_cluster(struct scm_request *scmrq) | ||
| 99 | { | ||
| 100 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
| 101 | unsigned long flags; | ||
| 102 | |||
| 103 | if (write_cluster_size == 0) | ||
| 104 | return; | ||
| 105 | |||
| 106 | spin_lock_irqsave(&bdev->lock, flags); | ||
| 107 | list_del(&scmrq->cluster.list); | ||
| 108 | spin_unlock_irqrestore(&bdev->lock, flags); | ||
| 109 | } | ||
| 110 | |||
| 111 | void scm_blk_dev_cluster_setup(struct scm_blk_dev *bdev) | ||
| 112 | { | ||
| 113 | INIT_LIST_HEAD(&bdev->cluster_list); | ||
| 114 | blk_queue_io_opt(bdev->rq, CLUSTER_SIZE); | ||
| 115 | } | ||
| 116 | |||
| 117 | static void scm_prepare_cluster_request(struct scm_request *scmrq) | ||
| 118 | { | ||
| 119 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
| 120 | struct scm_device *scmdev = bdev->gendisk->private_data; | ||
| 121 | struct request *req = scmrq->request; | ||
| 122 | struct aidaw *aidaw = scmrq->aidaw; | ||
| 123 | struct msb *msb = &scmrq->aob->msb[0]; | ||
| 124 | struct req_iterator iter; | ||
| 125 | struct bio_vec *bv; | ||
| 126 | int i = 0; | ||
| 127 | u64 addr; | ||
| 128 | |||
| 129 | switch (scmrq->cluster.state) { | ||
| 130 | case CLUSTER_NONE: | ||
| 131 | scmrq->cluster.state = CLUSTER_READ; | ||
| 132 | /* fall through */ | ||
| 133 | case CLUSTER_READ: | ||
| 134 | scmrq->aob->request.msb_count = 1; | ||
| 135 | msb->bs = MSB_BS_4K; | ||
| 136 | msb->oc = MSB_OC_READ; | ||
| 137 | msb->flags = MSB_FLAG_IDA; | ||
| 138 | msb->data_addr = (u64) aidaw; | ||
| 139 | msb->blk_count = write_cluster_size; | ||
| 140 | |||
| 141 | addr = scmdev->address + ((u64) blk_rq_pos(req) << 9); | ||
| 142 | msb->scm_addr = round_down(addr, CLUSTER_SIZE); | ||
| 143 | |||
| 144 | if (msb->scm_addr != | ||
| 145 | round_down(addr + (u64) blk_rq_bytes(req) - 1, | ||
| 146 | CLUSTER_SIZE)) | ||
| 147 | msb->blk_count = 2 * write_cluster_size; | ||
| 148 | |||
| 149 | for (i = 0; i < msb->blk_count; i++) { | ||
| 150 | aidaw->data_addr = (u64) scmrq->cluster.buf[i]; | ||
| 151 | aidaw++; | ||
| 152 | } | ||
| 153 | |||
| 154 | break; | ||
| 155 | case CLUSTER_WRITE: | ||
| 156 | msb->oc = MSB_OC_WRITE; | ||
| 157 | |||
| 158 | for (addr = msb->scm_addr; | ||
| 159 | addr < scmdev->address + ((u64) blk_rq_pos(req) << 9); | ||
| 160 | addr += PAGE_SIZE) { | ||
| 161 | aidaw->data_addr = (u64) scmrq->cluster.buf[i]; | ||
| 162 | aidaw++; | ||
| 163 | i++; | ||
| 164 | } | ||
| 165 | rq_for_each_segment(bv, req, iter) { | ||
| 166 | aidaw->data_addr = (u64) page_address(bv->bv_page); | ||
| 167 | aidaw++; | ||
| 168 | i++; | ||
| 169 | } | ||
| 170 | for (; i < msb->blk_count; i++) { | ||
| 171 | aidaw->data_addr = (u64) scmrq->cluster.buf[i]; | ||
| 172 | aidaw++; | ||
| 173 | } | ||
| 174 | break; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | bool scm_need_cluster_request(struct scm_request *scmrq) | ||
| 179 | { | ||
| 180 | if (rq_data_dir(scmrq->request) == READ) | ||
| 181 | return false; | ||
| 182 | |||
| 183 | return blk_rq_bytes(scmrq->request) < CLUSTER_SIZE; | ||
| 184 | } | ||
| 185 | |||
| 186 | /* Called with queue lock held. */ | ||
| 187 | void scm_initiate_cluster_request(struct scm_request *scmrq) | ||
| 188 | { | ||
| 189 | scm_prepare_cluster_request(scmrq); | ||
| 190 | if (scm_start_aob(scmrq->aob)) | ||
| 191 | scm_request_requeue(scmrq); | ||
| 192 | } | ||
| 193 | |||
| 194 | bool scm_test_cluster_request(struct scm_request *scmrq) | ||
| 195 | { | ||
| 196 | return scmrq->cluster.state != CLUSTER_NONE; | ||
| 197 | } | ||
| 198 | |||
| 199 | void scm_cluster_request_irq(struct scm_request *scmrq) | ||
| 200 | { | ||
| 201 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
| 202 | unsigned long flags; | ||
| 203 | |||
| 204 | switch (scmrq->cluster.state) { | ||
| 205 | case CLUSTER_NONE: | ||
| 206 | BUG(); | ||
| 207 | break; | ||
| 208 | case CLUSTER_READ: | ||
| 209 | if (scmrq->error) { | ||
| 210 | scm_request_finish(scmrq); | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | scmrq->cluster.state = CLUSTER_WRITE; | ||
| 214 | spin_lock_irqsave(&bdev->rq_lock, flags); | ||
| 215 | scm_initiate_cluster_request(scmrq); | ||
| 216 | spin_unlock_irqrestore(&bdev->rq_lock, flags); | ||
| 217 | break; | ||
| 218 | case CLUSTER_WRITE: | ||
| 219 | scm_request_finish(scmrq); | ||
| 220 | break; | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | bool scm_cluster_size_valid(void) | ||
| 225 | { | ||
| 226 | return write_cluster_size == 0 || write_cluster_size == 32 || | ||
| 227 | write_cluster_size == 64 || write_cluster_size == 128; | ||
| 228 | } | ||
diff --git a/drivers/s390/block/scm_drv.c b/drivers/s390/block/scm_drv.c new file mode 100644 index 000000000000..9fa0a908607b --- /dev/null +++ b/drivers/s390/block/scm_drv.c | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | /* | ||
| 2 | * Device driver for s390 storage class memory. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #define KMSG_COMPONENT "scm_block" | ||
| 9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
| 10 | |||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <asm/eadm.h> | ||
| 14 | #include "scm_blk.h" | ||
| 15 | |||
| 16 | static void notify(struct scm_device *scmdev) | ||
| 17 | { | ||
| 18 | pr_info("%lu: The capabilities of the SCM increment changed\n", | ||
| 19 | (unsigned long) scmdev->address); | ||
| 20 | SCM_LOG(2, "State changed"); | ||
| 21 | SCM_LOG_STATE(2, scmdev); | ||
| 22 | } | ||
| 23 | |||
| 24 | static int scm_probe(struct scm_device *scmdev) | ||
| 25 | { | ||
| 26 | struct scm_blk_dev *bdev; | ||
| 27 | int ret; | ||
| 28 | |||
| 29 | SCM_LOG(2, "probe"); | ||
| 30 | SCM_LOG_STATE(2, scmdev); | ||
| 31 | |||
| 32 | if (scmdev->attrs.oper_state != OP_STATE_GOOD) | ||
| 33 | return -EINVAL; | ||
| 34 | |||
| 35 | bdev = kzalloc(sizeof(*bdev), GFP_KERNEL); | ||
| 36 | if (!bdev) | ||
| 37 | return -ENOMEM; | ||
| 38 | |||
| 39 | dev_set_drvdata(&scmdev->dev, bdev); | ||
| 40 | ret = scm_blk_dev_setup(bdev, scmdev); | ||
| 41 | if (ret) { | ||
| 42 | dev_set_drvdata(&scmdev->dev, NULL); | ||
| 43 | kfree(bdev); | ||
| 44 | goto out; | ||
| 45 | } | ||
| 46 | |||
| 47 | out: | ||
| 48 | return ret; | ||
| 49 | } | ||
| 50 | |||
| 51 | static int scm_remove(struct scm_device *scmdev) | ||
| 52 | { | ||
| 53 | struct scm_blk_dev *bdev = dev_get_drvdata(&scmdev->dev); | ||
| 54 | |||
| 55 | scm_blk_dev_cleanup(bdev); | ||
| 56 | dev_set_drvdata(&scmdev->dev, NULL); | ||
| 57 | kfree(bdev); | ||
| 58 | |||
| 59 | return 0; | ||
| 60 | } | ||
| 61 | |||
| 62 | static struct scm_driver scm_drv = { | ||
| 63 | .drv = { | ||
| 64 | .name = "scm_block", | ||
| 65 | .owner = THIS_MODULE, | ||
| 66 | }, | ||
| 67 | .notify = notify, | ||
| 68 | .probe = scm_probe, | ||
| 69 | .remove = scm_remove, | ||
| 70 | .handler = scm_blk_irq, | ||
| 71 | }; | ||
| 72 | |||
| 73 | int __init scm_drv_init(void) | ||
| 74 | { | ||
| 75 | return scm_driver_register(&scm_drv); | ||
| 76 | } | ||
| 77 | |||
| 78 | void scm_drv_cleanup(void) | ||
| 79 | { | ||
| 80 | scm_driver_unregister(&scm_drv); | ||
| 81 | } | ||
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index bb07577e8fd4..699fd3e363df 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c | |||
| @@ -35,7 +35,6 @@ static struct raw3270_fn con3270_fn; | |||
| 35 | */ | 35 | */ |
| 36 | struct con3270 { | 36 | struct con3270 { |
| 37 | struct raw3270_view view; | 37 | struct raw3270_view view; |
| 38 | spinlock_t lock; | ||
| 39 | struct list_head freemem; /* list of free memory for strings. */ | 38 | struct list_head freemem; /* list of free memory for strings. */ |
| 40 | 39 | ||
| 41 | /* Output stuff. */ | 40 | /* Output stuff. */ |
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 5b8b8592d311..f4ff515db251 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c | |||
| @@ -571,8 +571,11 @@ static int __init mon_init(void) | |||
| 571 | if (rc) | 571 | if (rc) |
| 572 | goto out_iucv; | 572 | goto out_iucv; |
| 573 | monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL); | 573 | monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL); |
| 574 | if (!monreader_device) | 574 | if (!monreader_device) { |
| 575 | rc = -ENOMEM; | ||
| 575 | goto out_driver; | 576 | goto out_driver; |
| 577 | } | ||
| 578 | |||
| 576 | dev_set_name(monreader_device, "monreader-dev"); | 579 | dev_set_name(monreader_device, "monreader-dev"); |
| 577 | monreader_device->bus = &iucv_bus; | 580 | monreader_device->bus = &iucv_bus; |
| 578 | monreader_device->parent = iucv_root; | 581 | monreader_device->parent = iucv_root; |
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 3fcc000efc53..4fa21f7e2308 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c | |||
| @@ -334,7 +334,7 @@ sclp_dispatch_evbufs(struct sccb_header *sccb) | |||
| 334 | reg->receiver_fn(evbuf); | 334 | reg->receiver_fn(evbuf); |
| 335 | spin_lock_irqsave(&sclp_lock, flags); | 335 | spin_lock_irqsave(&sclp_lock, flags); |
| 336 | } else if (reg == NULL) | 336 | } else if (reg == NULL) |
| 337 | rc = -ENOSYS; | 337 | rc = -EOPNOTSUPP; |
| 338 | } | 338 | } |
| 339 | spin_unlock_irqrestore(&sclp_lock, flags); | 339 | spin_unlock_irqrestore(&sclp_lock, flags); |
| 340 | return rc; | 340 | return rc; |
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c index 4be63be73445..3b13d58fe87b 100644 --- a/drivers/s390/char/sclp_rw.c +++ b/drivers/s390/char/sclp_rw.c | |||
| @@ -463,7 +463,7 @@ sclp_emit_buffer(struct sclp_buffer *buffer, | |||
| 463 | /* Use write priority message */ | 463 | /* Use write priority message */ |
| 464 | sccb->msg_buf.header.type = EVTYP_PMSGCMD; | 464 | sccb->msg_buf.header.type = EVTYP_PMSGCMD; |
| 465 | else | 465 | else |
| 466 | return -ENOSYS; | 466 | return -EOPNOTSUPP; |
| 467 | buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA; | 467 | buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA; |
| 468 | buffer->request.status = SCLP_REQ_FILLED; | 468 | buffer->request.status = SCLP_REQ_FILLED; |
| 469 | buffer->request.callback = sclp_writedata_callback; | 469 | buffer->request.callback = sclp_writedata_callback; |
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index c06be6cc2fc3..ea664dd4f56d 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h | |||
| @@ -15,7 +15,6 @@ | |||
| 15 | #include <asm/ccwdev.h> | 15 | #include <asm/ccwdev.h> |
| 16 | #include <asm/debug.h> | 16 | #include <asm/debug.h> |
| 17 | #include <asm/idals.h> | 17 | #include <asm/idals.h> |
| 18 | #include <linux/blkdev.h> | ||
| 19 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| 20 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 21 | #include <linux/mtio.h> | 20 | #include <linux/mtio.h> |
diff --git a/drivers/s390/char/tape_std.h b/drivers/s390/char/tape_std.h index c5816ad9ed7d..8c760c036832 100644 --- a/drivers/s390/char/tape_std.h +++ b/drivers/s390/char/tape_std.h | |||
| @@ -100,11 +100,7 @@ struct tape_request *tape_std_read_block(struct tape_device *, size_t); | |||
| 100 | void tape_std_read_backward(struct tape_device *device, | 100 | void tape_std_read_backward(struct tape_device *device, |
| 101 | struct tape_request *request); | 101 | struct tape_request *request); |
| 102 | struct tape_request *tape_std_write_block(struct tape_device *, size_t); | 102 | struct tape_request *tape_std_write_block(struct tape_device *, size_t); |
| 103 | struct tape_request *tape_std_bread(struct tape_device *, struct request *); | ||
| 104 | void tape_std_free_bread(struct tape_request *); | ||
| 105 | void tape_std_check_locate(struct tape_device *, struct tape_request *); | 103 | void tape_std_check_locate(struct tape_device *, struct tape_request *); |
| 106 | struct tape_request *tape_std_bwrite(struct request *, | ||
| 107 | struct tape_device *, int); | ||
| 108 | 104 | ||
| 109 | /* Some non-mtop commands. */ | 105 | /* Some non-mtop commands. */ |
| 110 | int tape_std_assign(struct tape_device *); | 106 | int tape_std_assign(struct tape_device *); |
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index c131bc40f962..9b3a24e8d3a0 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c | |||
| @@ -321,7 +321,7 @@ static int vmlogrdr_open (struct inode *inode, struct file *filp) | |||
| 321 | * only allow for blocking reads to be open | 321 | * only allow for blocking reads to be open |
| 322 | */ | 322 | */ |
| 323 | if (filp->f_flags & O_NONBLOCK) | 323 | if (filp->f_flags & O_NONBLOCK) |
| 324 | return -ENOSYS; | 324 | return -EOPNOTSUPP; |
| 325 | 325 | ||
| 326 | /* Besure this device hasn't already been opened */ | 326 | /* Besure this device hasn't already been opened */ |
| 327 | spin_lock_bh(&logptr->priv_lock); | 327 | spin_lock_bh(&logptr->priv_lock); |
diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile index e1b700a19648..8c4a386e97f6 100644 --- a/drivers/s390/cio/Makefile +++ b/drivers/s390/cio/Makefile | |||
| @@ -8,6 +8,8 @@ ccw_device-objs += device.o device_fsm.o device_ops.o | |||
| 8 | ccw_device-objs += device_id.o device_pgid.o device_status.o | 8 | ccw_device-objs += device_id.o device_pgid.o device_status.o |
| 9 | obj-y += ccw_device.o cmf.o | 9 | obj-y += ccw_device.o cmf.o |
| 10 | obj-$(CONFIG_CHSC_SCH) += chsc_sch.o | 10 | obj-$(CONFIG_CHSC_SCH) += chsc_sch.o |
| 11 | obj-$(CONFIG_EADM_SCH) += eadm_sch.o | ||
| 12 | obj-$(CONFIG_SCM_BUS) += scm.o | ||
| 11 | obj-$(CONFIG_CCWGROUP) += ccwgroup.o | 13 | obj-$(CONFIG_CCWGROUP) += ccwgroup.o |
| 12 | 14 | ||
| 13 | qdio-objs := qdio_main.o qdio_thinint.o qdio_debug.o qdio_setup.o | 15 | qdio-objs := qdio_main.o qdio_thinint.o qdio_debug.o qdio_setup.o |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index cfe0c087fe5c..4d51a7c4eb8b 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
| @@ -52,6 +52,11 @@ int chsc_error_from_response(int response) | |||
| 52 | return -EINVAL; | 52 | return -EINVAL; |
| 53 | case 0x0004: | 53 | case 0x0004: |
| 54 | return -EOPNOTSUPP; | 54 | return -EOPNOTSUPP; |
| 55 | case 0x000b: | ||
| 56 | return -EBUSY; | ||
| 57 | case 0x0100: | ||
| 58 | case 0x0102: | ||
| 59 | return -ENOMEM; | ||
| 55 | default: | 60 | default: |
| 56 | return -EIO; | 61 | return -EIO; |
| 57 | } | 62 | } |
| @@ -393,6 +398,20 @@ static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) | |||
| 393 | } | 398 | } |
| 394 | } | 399 | } |
| 395 | 400 | ||
| 401 | static void chsc_process_sei_scm_change(struct chsc_sei_area *sei_area) | ||
| 402 | { | ||
| 403 | int ret; | ||
| 404 | |||
| 405 | CIO_CRW_EVENT(4, "chsc: scm change notification\n"); | ||
| 406 | if (sei_area->rs != 7) | ||
| 407 | return; | ||
| 408 | |||
| 409 | ret = scm_update_information(); | ||
| 410 | if (ret) | ||
| 411 | CIO_CRW_EVENT(0, "chsc: updating change notification" | ||
| 412 | " failed (rc=%d).\n", ret); | ||
| 413 | } | ||
| 414 | |||
| 396 | static void chsc_process_sei(struct chsc_sei_area *sei_area) | 415 | static void chsc_process_sei(struct chsc_sei_area *sei_area) |
| 397 | { | 416 | { |
| 398 | /* Check if we might have lost some information. */ | 417 | /* Check if we might have lost some information. */ |
| @@ -414,6 +433,9 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area) | |||
| 414 | case 8: /* channel-path-configuration notification */ | 433 | case 8: /* channel-path-configuration notification */ |
| 415 | chsc_process_sei_chp_config(sei_area); | 434 | chsc_process_sei_chp_config(sei_area); |
| 416 | break; | 435 | break; |
| 436 | case 12: /* scm change notification */ | ||
| 437 | chsc_process_sei_scm_change(sei_area); | ||
| 438 | break; | ||
| 417 | default: /* other stuff */ | 439 | default: /* other stuff */ |
| 418 | CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n", | 440 | CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n", |
| 419 | sei_area->cc); | 441 | sei_area->cc); |
| @@ -1047,3 +1069,33 @@ out: | |||
| 1047 | return rc; | 1069 | return rc; |
| 1048 | } | 1070 | } |
| 1049 | EXPORT_SYMBOL_GPL(chsc_siosl); | 1071 | EXPORT_SYMBOL_GPL(chsc_siosl); |
| 1072 | |||
| 1073 | /** | ||
| 1074 | * chsc_scm_info() - store SCM information (SSI) | ||
| 1075 | * @scm_area: request and response block for SSI | ||
| 1076 | * @token: continuation token | ||
| 1077 | * | ||
| 1078 | * Returns 0 on success. | ||
| 1079 | */ | ||
| 1080 | int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token) | ||
| 1081 | { | ||
| 1082 | int ccode, ret; | ||
| 1083 | |||
| 1084 | memset(scm_area, 0, sizeof(*scm_area)); | ||
| 1085 | scm_area->request.length = 0x0020; | ||
| 1086 | scm_area->request.code = 0x004C; | ||
| 1087 | scm_area->reqtok = token; | ||
| 1088 | |||
| 1089 | ccode = chsc(scm_area); | ||
| 1090 | if (ccode > 0) { | ||
| 1091 | ret = (ccode == 3) ? -ENODEV : -EBUSY; | ||
| 1092 | goto out; | ||
| 1093 | } | ||
| 1094 | ret = chsc_error_from_response(scm_area->response.code); | ||
| 1095 | if (ret != 0) | ||
| 1096 | CIO_MSG_EVENT(2, "chsc: scm info failed (rc=%04x)\n", | ||
| 1097 | scm_area->response.code); | ||
| 1098 | out: | ||
| 1099 | return ret; | ||
| 1100 | } | ||
| 1101 | EXPORT_SYMBOL_GPL(chsc_scm_info); | ||
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 3f15b2aaeaea..662dab4b93e6 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
| 5 | #include <linux/device.h> | 5 | #include <linux/device.h> |
| 6 | #include <asm/css_chars.h> | ||
| 6 | #include <asm/chpid.h> | 7 | #include <asm/chpid.h> |
| 7 | #include <asm/chsc.h> | 8 | #include <asm/chsc.h> |
| 8 | #include <asm/schid.h> | 9 | #include <asm/schid.h> |
| @@ -118,4 +119,46 @@ int chsc_error_from_response(int response); | |||
| 118 | 119 | ||
| 119 | int chsc_siosl(struct subchannel_id schid); | 120 | int chsc_siosl(struct subchannel_id schid); |
| 120 | 121 | ||
| 122 | /* Functions and definitions to query storage-class memory. */ | ||
| 123 | struct sale { | ||
| 124 | u64 sa; | ||
| 125 | u32 p:4; | ||
| 126 | u32 op_state:4; | ||
| 127 | u32 data_state:4; | ||
| 128 | u32 rank:4; | ||
| 129 | u32 r:1; | ||
| 130 | u32:7; | ||
| 131 | u32 rid:8; | ||
| 132 | u32:32; | ||
| 133 | } __packed; | ||
| 134 | |||
| 135 | struct chsc_scm_info { | ||
| 136 | struct chsc_header request; | ||
| 137 | u32:32; | ||
| 138 | u64 reqtok; | ||
| 139 | u32 reserved1[4]; | ||
| 140 | struct chsc_header response; | ||
| 141 | u64:56; | ||
| 142 | u8 rq; | ||
| 143 | u32 mbc; | ||
| 144 | u64 msa; | ||
| 145 | u16 is; | ||
| 146 | u16 mmc; | ||
| 147 | u32 mci; | ||
| 148 | u64 nr_scm_ini; | ||
| 149 | u64 nr_scm_unini; | ||
| 150 | u32 reserved2[10]; | ||
| 151 | u64 restok; | ||
| 152 | struct sale scmal[248]; | ||
| 153 | } __packed; | ||
| 154 | |||
| 155 | int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token); | ||
| 156 | |||
| 157 | #ifdef CONFIG_SCM_BUS | ||
| 158 | int scm_update_information(void); | ||
| 159 | #else /* CONFIG_SCM_BUS */ | ||
| 160 | #define scm_update_information() 0 | ||
| 161 | #endif /* CONFIG_SCM_BUS */ | ||
| 162 | |||
| 163 | |||
| 121 | #endif | 164 | #endif |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 33d1ef703593..8e927b9f285f 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
| @@ -1029,7 +1029,7 @@ extern void do_reipl_asm(__u32 schid); | |||
| 1029 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ | 1029 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ |
| 1030 | void reipl_ccw_dev(struct ccw_dev_id *devid) | 1030 | void reipl_ccw_dev(struct ccw_dev_id *devid) |
| 1031 | { | 1031 | { |
| 1032 | struct subchannel_id schid; | 1032 | struct subchannel_id uninitialized_var(schid); |
| 1033 | 1033 | ||
| 1034 | s390_reset_system(NULL, NULL); | 1034 | s390_reset_system(NULL, NULL); |
| 1035 | if (reipl_find_schid(devid, &schid) != 0) | 1035 | if (reipl_find_schid(devid, &schid) != 0) |
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 21908e67bf67..b4d572f65f07 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
| @@ -445,6 +445,7 @@ void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo) | |||
| 445 | put_device(&sch->dev); | 445 | put_device(&sch->dev); |
| 446 | } | 446 | } |
| 447 | } | 447 | } |
| 448 | EXPORT_SYMBOL_GPL(css_sched_sch_todo); | ||
| 448 | 449 | ||
| 449 | static void css_sch_todo(struct work_struct *work) | 450 | static void css_sch_todo(struct work_struct *work) |
| 450 | { | 451 | { |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index ed25c8740a9c..fc916f5d7314 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
| @@ -1426,6 +1426,8 @@ static enum io_sch_action sch_get_action(struct subchannel *sch) | |||
| 1426 | return IO_SCH_REPROBE; | 1426 | return IO_SCH_REPROBE; |
| 1427 | if (cdev->online) | 1427 | if (cdev->online) |
| 1428 | return IO_SCH_VERIFY; | 1428 | return IO_SCH_VERIFY; |
| 1429 | if (cdev->private->state == DEV_STATE_NOT_OPER) | ||
| 1430 | return IO_SCH_UNREG_ATTACH; | ||
| 1429 | return IO_SCH_NOP; | 1431 | return IO_SCH_NOP; |
| 1430 | } | 1432 | } |
| 1431 | 1433 | ||
| @@ -1519,11 +1521,14 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) | |||
| 1519 | goto out; | 1521 | goto out; |
| 1520 | break; | 1522 | break; |
| 1521 | case IO_SCH_UNREG_ATTACH: | 1523 | case IO_SCH_UNREG_ATTACH: |
| 1524 | spin_lock_irqsave(sch->lock, flags); | ||
| 1522 | if (cdev->private->flags.resuming) { | 1525 | if (cdev->private->flags.resuming) { |
| 1523 | /* Device will be handled later. */ | 1526 | /* Device will be handled later. */ |
| 1524 | rc = 0; | 1527 | rc = 0; |
| 1525 | goto out; | 1528 | goto out_unlock; |
| 1526 | } | 1529 | } |
| 1530 | sch_set_cdev(sch, NULL); | ||
| 1531 | spin_unlock_irqrestore(sch->lock, flags); | ||
| 1527 | /* Unregister ccw device. */ | 1532 | /* Unregister ccw device. */ |
| 1528 | ccw_device_unregister(cdev); | 1533 | ccw_device_unregister(cdev); |
| 1529 | break; | 1534 | break; |
diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c new file mode 100644 index 000000000000..6c9673400464 --- /dev/null +++ b/drivers/s390/cio/eadm_sch.c | |||
| @@ -0,0 +1,401 @@ | |||
| 1 | /* | ||
| 2 | * Driver for s390 eadm subchannels | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/kernel_stat.h> | ||
| 9 | #include <linux/workqueue.h> | ||
| 10 | #include <linux/spinlock.h> | ||
| 11 | #include <linux/device.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/timer.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include <linux/list.h> | ||
| 16 | |||
| 17 | #include <asm/css_chars.h> | ||
| 18 | #include <asm/debug.h> | ||
| 19 | #include <asm/isc.h> | ||
| 20 | #include <asm/cio.h> | ||
| 21 | #include <asm/scsw.h> | ||
| 22 | #include <asm/eadm.h> | ||
| 23 | |||
| 24 | #include "eadm_sch.h" | ||
| 25 | #include "ioasm.h" | ||
| 26 | #include "cio.h" | ||
| 27 | #include "css.h" | ||
| 28 | #include "orb.h" | ||
| 29 | |||
| 30 | MODULE_DESCRIPTION("driver for s390 eadm subchannels"); | ||
| 31 | MODULE_LICENSE("GPL"); | ||
| 32 | |||
| 33 | #define EADM_TIMEOUT (5 * HZ) | ||
| 34 | static DEFINE_SPINLOCK(list_lock); | ||
| 35 | static LIST_HEAD(eadm_list); | ||
| 36 | |||
| 37 | static debug_info_t *eadm_debug; | ||
| 38 | |||
| 39 | #define EADM_LOG(imp, txt) do { \ | ||
| 40 | debug_text_event(eadm_debug, imp, txt); \ | ||
| 41 | } while (0) | ||
| 42 | |||
| 43 | static void EADM_LOG_HEX(int level, void *data, int length) | ||
| 44 | { | ||
| 45 | if (level > eadm_debug->level) | ||
| 46 | return; | ||
| 47 | while (length > 0) { | ||
| 48 | debug_event(eadm_debug, level, data, length); | ||
| 49 | length -= eadm_debug->buf_size; | ||
| 50 | data += eadm_debug->buf_size; | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | static void orb_init(union orb *orb) | ||
| 55 | { | ||
| 56 | memset(orb, 0, sizeof(union orb)); | ||
| 57 | orb->eadm.compat1 = 1; | ||
| 58 | orb->eadm.compat2 = 1; | ||
| 59 | orb->eadm.fmt = 1; | ||
| 60 | orb->eadm.x = 1; | ||
| 61 | } | ||
| 62 | |||
| 63 | static int eadm_subchannel_start(struct subchannel *sch, struct aob *aob) | ||
| 64 | { | ||
| 65 | union orb *orb = &get_eadm_private(sch)->orb; | ||
| 66 | int cc; | ||
| 67 | |||
| 68 | orb_init(orb); | ||
| 69 | orb->eadm.aob = (u32)__pa(aob); | ||
| 70 | orb->eadm.intparm = (u32)(addr_t)sch; | ||
| 71 | orb->eadm.key = PAGE_DEFAULT_KEY >> 4; | ||
| 72 | |||
| 73 | EADM_LOG(6, "start"); | ||
| 74 | EADM_LOG_HEX(6, &sch->schid, sizeof(sch->schid)); | ||
| 75 | |||
| 76 | cc = ssch(sch->schid, orb); | ||
| 77 | switch (cc) { | ||
| 78 | case 0: | ||
| 79 | sch->schib.scsw.eadm.actl |= SCSW_ACTL_START_PEND; | ||
| 80 | break; | ||
| 81 | case 1: /* status pending */ | ||
| 82 | case 2: /* busy */ | ||
| 83 | return -EBUSY; | ||
| 84 | case 3: /* not operational */ | ||
| 85 | return -ENODEV; | ||
| 86 | } | ||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | static int eadm_subchannel_clear(struct subchannel *sch) | ||
| 91 | { | ||
| 92 | int cc; | ||
| 93 | |||
| 94 | cc = csch(sch->schid); | ||
| 95 | if (cc) | ||
| 96 | return -ENODEV; | ||
| 97 | |||
| 98 | sch->schib.scsw.eadm.actl |= SCSW_ACTL_CLEAR_PEND; | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | static void eadm_subchannel_timeout(unsigned long data) | ||
| 103 | { | ||
| 104 | struct subchannel *sch = (struct subchannel *) data; | ||
| 105 | |||
| 106 | spin_lock_irq(sch->lock); | ||
| 107 | EADM_LOG(1, "timeout"); | ||
| 108 | EADM_LOG_HEX(1, &sch->schid, sizeof(sch->schid)); | ||
| 109 | if (eadm_subchannel_clear(sch)) | ||
| 110 | EADM_LOG(0, "clear failed"); | ||
| 111 | spin_unlock_irq(sch->lock); | ||
| 112 | } | ||
| 113 | |||
| 114 | static void eadm_subchannel_set_timeout(struct subchannel *sch, int expires) | ||
| 115 | { | ||
| 116 | struct eadm_private *private = get_eadm_private(sch); | ||
| 117 | |||
| 118 | if (expires == 0) { | ||
| 119 | del_timer(&private->timer); | ||
| 120 | return; | ||
| 121 | } | ||
| 122 | if (timer_pending(&private->timer)) { | ||
| 123 | if (mod_timer(&private->timer, jiffies + expires)) | ||
| 124 | return; | ||
| 125 | } | ||
| 126 | private->timer.function = eadm_subchannel_timeout; | ||
| 127 | private->timer.data = (unsigned long) sch; | ||
| 128 | private->timer.expires = jiffies + expires; | ||
| 129 | add_timer(&private->timer); | ||
| 130 | } | ||
| 131 | |||
| 132 | static void eadm_subchannel_irq(struct subchannel *sch) | ||
| 133 | { | ||
| 134 | struct eadm_private *private = get_eadm_private(sch); | ||
| 135 | struct eadm_scsw *scsw = &sch->schib.scsw.eadm; | ||
| 136 | struct irb *irb = (struct irb *)&S390_lowcore.irb; | ||
| 137 | int error = 0; | ||
| 138 | |||
| 139 | EADM_LOG(6, "irq"); | ||
| 140 | EADM_LOG_HEX(6, irb, sizeof(*irb)); | ||
| 141 | |||
| 142 | kstat_cpu(smp_processor_id()).irqs[IOINT_ADM]++; | ||
| 143 | |||
| 144 | if ((scsw->stctl & (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) | ||
| 145 | && scsw->eswf == 1 && irb->esw.eadm.erw.r) | ||
| 146 | error = -EIO; | ||
| 147 | |||
| 148 | if (scsw->fctl & SCSW_FCTL_CLEAR_FUNC) | ||
| 149 | error = -ETIMEDOUT; | ||
| 150 | |||
| 151 | eadm_subchannel_set_timeout(sch, 0); | ||
| 152 | |||
| 153 | if (private->state != EADM_BUSY) { | ||
| 154 | EADM_LOG(1, "irq unsol"); | ||
| 155 | EADM_LOG_HEX(1, irb, sizeof(*irb)); | ||
| 156 | private->state = EADM_NOT_OPER; | ||
| 157 | css_sched_sch_todo(sch, SCH_TODO_EVAL); | ||
| 158 | return; | ||
| 159 | } | ||
| 160 | scm_irq_handler((struct aob *)(unsigned long)scsw->aob, error); | ||
| 161 | private->state = EADM_IDLE; | ||
| 162 | } | ||
| 163 | |||
| 164 | static struct subchannel *eadm_get_idle_sch(void) | ||
| 165 | { | ||
| 166 | struct eadm_private *private; | ||
| 167 | struct subchannel *sch; | ||
| 168 | unsigned long flags; | ||
| 169 | |||
| 170 | spin_lock_irqsave(&list_lock, flags); | ||
| 171 | list_for_each_entry(private, &eadm_list, head) { | ||
| 172 | sch = private->sch; | ||
| 173 | spin_lock(sch->lock); | ||
| 174 | if (private->state == EADM_IDLE) { | ||
| 175 | private->state = EADM_BUSY; | ||
| 176 | list_move_tail(&private->head, &eadm_list); | ||
| 177 | spin_unlock(sch->lock); | ||
| 178 | spin_unlock_irqrestore(&list_lock, flags); | ||
| 179 | |||
| 180 | return sch; | ||
| 181 | } | ||
| 182 | spin_unlock(sch->lock); | ||
| 183 | } | ||
| 184 | spin_unlock_irqrestore(&list_lock, flags); | ||
| 185 | |||
| 186 | return NULL; | ||
| 187 | } | ||
| 188 | |||
| 189 | static int eadm_start_aob(struct aob *aob) | ||
| 190 | { | ||
| 191 | struct eadm_private *private; | ||
| 192 | struct subchannel *sch; | ||
| 193 | unsigned long flags; | ||
| 194 | int ret; | ||
| 195 | |||
| 196 | sch = eadm_get_idle_sch(); | ||
| 197 | if (!sch) | ||
| 198 | return -EBUSY; | ||
| 199 | |||
| 200 | spin_lock_irqsave(sch->lock, flags); | ||
| 201 | eadm_subchannel_set_timeout(sch, EADM_TIMEOUT); | ||
| 202 | ret = eadm_subchannel_start(sch, aob); | ||
| 203 | if (!ret) | ||
| 204 | goto out_unlock; | ||
| 205 | |||
| 206 | /* Handle start subchannel failure. */ | ||
| 207 | eadm_subchannel_set_timeout(sch, 0); | ||
| 208 | private = get_eadm_private(sch); | ||
| 209 | private->state = EADM_NOT_OPER; | ||
| 210 | css_sched_sch_todo(sch, SCH_TODO_EVAL); | ||
| 211 | |||
| 212 | out_unlock: | ||
| 213 | spin_unlock_irqrestore(sch->lock, flags); | ||
| 214 | |||
| 215 | return ret; | ||
| 216 | } | ||
| 217 | |||
| 218 | static int eadm_subchannel_probe(struct subchannel *sch) | ||
| 219 | { | ||
| 220 | struct eadm_private *private; | ||
| 221 | int ret; | ||
| 222 | |||
| 223 | private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA); | ||
| 224 | if (!private) | ||
| 225 | return -ENOMEM; | ||
| 226 | |||
| 227 | INIT_LIST_HEAD(&private->head); | ||
| 228 | init_timer(&private->timer); | ||
| 229 | |||
| 230 | spin_lock_irq(sch->lock); | ||
| 231 | set_eadm_private(sch, private); | ||
| 232 | private->state = EADM_IDLE; | ||
| 233 | private->sch = sch; | ||
| 234 | sch->isc = EADM_SCH_ISC; | ||
| 235 | ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); | ||
| 236 | if (ret) { | ||
| 237 | set_eadm_private(sch, NULL); | ||
| 238 | spin_unlock_irq(sch->lock); | ||
| 239 | kfree(private); | ||
| 240 | goto out; | ||
| 241 | } | ||
| 242 | spin_unlock_irq(sch->lock); | ||
| 243 | |||
| 244 | spin_lock_irq(&list_lock); | ||
| 245 | list_add(&private->head, &eadm_list); | ||
| 246 | spin_unlock_irq(&list_lock); | ||
| 247 | |||
| 248 | if (dev_get_uevent_suppress(&sch->dev)) { | ||
| 249 | dev_set_uevent_suppress(&sch->dev, 0); | ||
| 250 | kobject_uevent(&sch->dev.kobj, KOBJ_ADD); | ||
| 251 | } | ||
| 252 | out: | ||
| 253 | return ret; | ||
| 254 | } | ||
| 255 | |||
| 256 | static void eadm_quiesce(struct subchannel *sch) | ||
| 257 | { | ||
| 258 | int ret; | ||
| 259 | |||
| 260 | do { | ||
| 261 | spin_lock_irq(sch->lock); | ||
| 262 | ret = cio_disable_subchannel(sch); | ||
| 263 | spin_unlock_irq(sch->lock); | ||
| 264 | } while (ret == -EBUSY); | ||
| 265 | } | ||
| 266 | |||
| 267 | static int eadm_subchannel_remove(struct subchannel *sch) | ||
| 268 | { | ||
| 269 | struct eadm_private *private = get_eadm_private(sch); | ||
| 270 | |||
| 271 | spin_lock_irq(&list_lock); | ||
| 272 | list_del(&private->head); | ||
| 273 | spin_unlock_irq(&list_lock); | ||
| 274 | |||
| 275 | eadm_quiesce(sch); | ||
| 276 | |||
| 277 | spin_lock_irq(sch->lock); | ||
| 278 | set_eadm_private(sch, NULL); | ||
| 279 | spin_unlock_irq(sch->lock); | ||
| 280 | |||
| 281 | kfree(private); | ||
| 282 | |||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | |||
| 286 | static void eadm_subchannel_shutdown(struct subchannel *sch) | ||
| 287 | { | ||
| 288 | eadm_quiesce(sch); | ||
| 289 | } | ||
| 290 | |||
| 291 | static int eadm_subchannel_freeze(struct subchannel *sch) | ||
| 292 | { | ||
| 293 | return cio_disable_subchannel(sch); | ||
| 294 | } | ||
| 295 | |||
| 296 | static int eadm_subchannel_restore(struct subchannel *sch) | ||
| 297 | { | ||
| 298 | return cio_enable_subchannel(sch, (u32)(unsigned long)sch); | ||
| 299 | } | ||
| 300 | |||
| 301 | /** | ||
| 302 | * eadm_subchannel_sch_event - process subchannel event | ||
| 303 | * @sch: subchannel | ||
| 304 | * @process: non-zero if function is called in process context | ||
| 305 | * | ||
| 306 | * An unspecified event occurred for this subchannel. Adjust data according | ||
| 307 | * to the current operational state of the subchannel. Return zero when the | ||
| 308 | * event has been handled sufficiently or -EAGAIN when this function should | ||
| 309 | * be called again in process context. | ||
| 310 | */ | ||
| 311 | static int eadm_subchannel_sch_event(struct subchannel *sch, int process) | ||
| 312 | { | ||
| 313 | struct eadm_private *private; | ||
| 314 | unsigned long flags; | ||
| 315 | int ret = 0; | ||
| 316 | |||
| 317 | spin_lock_irqsave(sch->lock, flags); | ||
| 318 | if (!device_is_registered(&sch->dev)) | ||
| 319 | goto out_unlock; | ||
| 320 | |||
| 321 | if (work_pending(&sch->todo_work)) | ||
| 322 | goto out_unlock; | ||
| 323 | |||
| 324 | if (cio_update_schib(sch)) { | ||
| 325 | css_sched_sch_todo(sch, SCH_TODO_UNREG); | ||
| 326 | goto out_unlock; | ||
| 327 | } | ||
| 328 | private = get_eadm_private(sch); | ||
| 329 | if (private->state == EADM_NOT_OPER) | ||
| 330 | private->state = EADM_IDLE; | ||
| 331 | |||
| 332 | out_unlock: | ||
| 333 | spin_unlock_irqrestore(sch->lock, flags); | ||
| 334 | |||
| 335 | return ret; | ||
| 336 | } | ||
| 337 | |||
| 338 | static struct css_device_id eadm_subchannel_ids[] = { | ||
| 339 | { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_ADM, }, | ||
| 340 | { /* end of list */ }, | ||
| 341 | }; | ||
| 342 | MODULE_DEVICE_TABLE(css, eadm_subchannel_ids); | ||
| 343 | |||
| 344 | static struct css_driver eadm_subchannel_driver = { | ||
| 345 | .drv = { | ||
| 346 | .name = "eadm_subchannel", | ||
| 347 | .owner = THIS_MODULE, | ||
| 348 | }, | ||
| 349 | .subchannel_type = eadm_subchannel_ids, | ||
| 350 | .irq = eadm_subchannel_irq, | ||
| 351 | .probe = eadm_subchannel_probe, | ||
| 352 | .remove = eadm_subchannel_remove, | ||
| 353 | .shutdown = eadm_subchannel_shutdown, | ||
| 354 | .sch_event = eadm_subchannel_sch_event, | ||
| 355 | .freeze = eadm_subchannel_freeze, | ||
| 356 | .thaw = eadm_subchannel_restore, | ||
| 357 | .restore = eadm_subchannel_restore, | ||
| 358 | }; | ||
| 359 | |||
| 360 | static struct eadm_ops eadm_ops = { | ||
| 361 | .eadm_start = eadm_start_aob, | ||
| 362 | .owner = THIS_MODULE, | ||
| 363 | }; | ||
| 364 | |||
| 365 | static int __init eadm_sch_init(void) | ||
| 366 | { | ||
| 367 | int ret; | ||
| 368 | |||
| 369 | if (!css_general_characteristics.eadm) | ||
| 370 | return -ENXIO; | ||
| 371 | |||
| 372 | eadm_debug = debug_register("eadm_log", 16, 1, 16); | ||
| 373 | if (!eadm_debug) | ||
| 374 | return -ENOMEM; | ||
| 375 | |||
| 376 | debug_register_view(eadm_debug, &debug_hex_ascii_view); | ||
| 377 | debug_set_level(eadm_debug, 2); | ||
| 378 | |||
| 379 | isc_register(EADM_SCH_ISC); | ||
| 380 | ret = css_driver_register(&eadm_subchannel_driver); | ||
| 381 | if (ret) | ||
| 382 | goto cleanup; | ||
| 383 | |||
| 384 | register_eadm_ops(&eadm_ops); | ||
| 385 | return ret; | ||
| 386 | |||
| 387 | cleanup: | ||
| 388 | isc_unregister(EADM_SCH_ISC); | ||
| 389 | debug_unregister(eadm_debug); | ||
| 390 | return ret; | ||
| 391 | } | ||
| 392 | |||
| 393 | static void __exit eadm_sch_exit(void) | ||
| 394 | { | ||
| 395 | unregister_eadm_ops(&eadm_ops); | ||
| 396 | css_driver_unregister(&eadm_subchannel_driver); | ||
| 397 | isc_unregister(EADM_SCH_ISC); | ||
| 398 | debug_unregister(eadm_debug); | ||
| 399 | } | ||
| 400 | module_init(eadm_sch_init); | ||
| 401 | module_exit(eadm_sch_exit); | ||
diff --git a/drivers/s390/cio/eadm_sch.h b/drivers/s390/cio/eadm_sch.h new file mode 100644 index 000000000000..2779be093982 --- /dev/null +++ b/drivers/s390/cio/eadm_sch.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | #ifndef EADM_SCH_H | ||
| 2 | #define EADM_SCH_H | ||
| 3 | |||
| 4 | #include <linux/device.h> | ||
| 5 | #include <linux/timer.h> | ||
| 6 | #include <linux/list.h> | ||
| 7 | #include "orb.h" | ||
| 8 | |||
| 9 | struct eadm_private { | ||
| 10 | union orb orb; | ||
| 11 | enum {EADM_IDLE, EADM_BUSY, EADM_NOT_OPER} state; | ||
| 12 | struct timer_list timer; | ||
| 13 | struct list_head head; | ||
| 14 | struct subchannel *sch; | ||
| 15 | } __aligned(8); | ||
| 16 | |||
| 17 | #define get_eadm_private(n) ((struct eadm_private *)dev_get_drvdata(&n->dev)) | ||
| 18 | #define set_eadm_private(n, p) (dev_set_drvdata(&n->dev, p)) | ||
| 19 | |||
| 20 | #endif | ||
diff --git a/drivers/s390/cio/orb.h b/drivers/s390/cio/orb.h index 45a9865c2b36..7a640530e7f5 100644 --- a/drivers/s390/cio/orb.h +++ b/drivers/s390/cio/orb.h | |||
| @@ -59,9 +59,33 @@ struct tm_orb { | |||
| 59 | u32:32; | 59 | u32:32; |
| 60 | } __packed __aligned(4); | 60 | } __packed __aligned(4); |
| 61 | 61 | ||
| 62 | /* | ||
| 63 | * eadm operation request block | ||
| 64 | */ | ||
| 65 | struct eadm_orb { | ||
| 66 | u32 intparm; | ||
| 67 | u32 key:4; | ||
| 68 | u32:4; | ||
| 69 | u32 compat1:1; | ||
| 70 | u32 compat2:1; | ||
| 71 | u32:21; | ||
| 72 | u32 x:1; | ||
| 73 | u32 aob; | ||
| 74 | u32 css_prio:8; | ||
| 75 | u32:8; | ||
| 76 | u32 scm_prio:8; | ||
| 77 | u32:8; | ||
| 78 | u32:29; | ||
| 79 | u32 fmt:3; | ||
| 80 | u32:32; | ||
| 81 | u32:32; | ||
| 82 | u32:32; | ||
| 83 | } __packed __aligned(4); | ||
| 84 | |||
| 62 | union orb { | 85 | union orb { |
| 63 | struct cmd_orb cmd; | 86 | struct cmd_orb cmd; |
| 64 | struct tm_orb tm; | 87 | struct tm_orb tm; |
| 88 | struct eadm_orb eadm; | ||
| 65 | } __packed __aligned(4); | 89 | } __packed __aligned(4); |
| 66 | 90 | ||
| 67 | #endif /* S390_ORB_H */ | 91 | #endif /* S390_ORB_H */ |
diff --git a/drivers/s390/cio/qdio_debug.h b/drivers/s390/cio/qdio_debug.h index e1f646800ddb..7f8b973da298 100644 --- a/drivers/s390/cio/qdio_debug.h +++ b/drivers/s390/cio/qdio_debug.h | |||
| @@ -37,10 +37,14 @@ static inline int qdio_dbf_passes(debug_info_t *dbf_grp, int level) | |||
| 37 | debug_text_event(qdio_dbf_setup, DBF_ERR, debug_buffer); \ | 37 | debug_text_event(qdio_dbf_setup, DBF_ERR, debug_buffer); \ |
| 38 | } while (0) | 38 | } while (0) |
| 39 | 39 | ||
| 40 | #define DBF_HEX(addr, len) \ | 40 | static inline void DBF_HEX(void *addr, int len) |
| 41 | do { \ | 41 | { |
| 42 | debug_event(qdio_dbf_setup, DBF_ERR, (void*)(addr), len); \ | 42 | while (len > 0) { |
| 43 | } while (0) | 43 | debug_event(qdio_dbf_setup, DBF_ERR, addr, len); |
| 44 | len -= qdio_dbf_setup->buf_size; | ||
| 45 | addr += qdio_dbf_setup->buf_size; | ||
| 46 | } | ||
| 47 | } | ||
| 44 | 48 | ||
| 45 | #define DBF_ERROR(text...) \ | 49 | #define DBF_ERROR(text...) \ |
| 46 | do { \ | 50 | do { \ |
| @@ -49,11 +53,14 @@ static inline int qdio_dbf_passes(debug_info_t *dbf_grp, int level) | |||
| 49 | debug_text_event(qdio_dbf_error, DBF_ERR, debug_buffer); \ | 53 | debug_text_event(qdio_dbf_error, DBF_ERR, debug_buffer); \ |
| 50 | } while (0) | 54 | } while (0) |
| 51 | 55 | ||
| 52 | #define DBF_ERROR_HEX(addr, len) \ | 56 | static inline void DBF_ERROR_HEX(void *addr, int len) |
| 53 | do { \ | 57 | { |
| 54 | debug_event(qdio_dbf_error, DBF_ERR, (void*)(addr), len); \ | 58 | while (len > 0) { |
| 55 | } while (0) | 59 | debug_event(qdio_dbf_error, DBF_ERR, addr, len); |
| 56 | 60 | len -= qdio_dbf_error->buf_size; | |
| 61 | addr += qdio_dbf_error->buf_size; | ||
| 62 | } | ||
| 63 | } | ||
| 57 | 64 | ||
| 58 | #define DBF_DEV_EVENT(level, device, text...) \ | 65 | #define DBF_DEV_EVENT(level, device, text...) \ |
| 59 | do { \ | 66 | do { \ |
| @@ -64,10 +71,15 @@ static inline int qdio_dbf_passes(debug_info_t *dbf_grp, int level) | |||
| 64 | } \ | 71 | } \ |
| 65 | } while (0) | 72 | } while (0) |
| 66 | 73 | ||
| 67 | #define DBF_DEV_HEX(level, device, addr, len) \ | 74 | static inline void DBF_DEV_HEX(struct qdio_irq *dev, void *addr, |
| 68 | do { \ | 75 | int len, int level) |
| 69 | debug_event(device->debug_area, level, (void*)(addr), len); \ | 76 | { |
| 70 | } while (0) | 77 | while (len > 0) { |
| 78 | debug_event(dev->debug_area, level, addr, len); | ||
| 79 | len -= dev->debug_area->buf_size; | ||
| 80 | addr += dev->debug_area->buf_size; | ||
| 81 | } | ||
| 82 | } | ||
| 71 | 83 | ||
| 72 | void qdio_allocate_dbf(struct qdio_initialize *init_data, | 84 | void qdio_allocate_dbf(struct qdio_initialize *init_data, |
| 73 | struct qdio_irq *irq_ptr); | 85 | struct qdio_irq *irq_ptr); |
diff --git a/drivers/s390/cio/scm.c b/drivers/s390/cio/scm.c new file mode 100644 index 000000000000..bcf20f3aa51b --- /dev/null +++ b/drivers/s390/cio/scm.c | |||
| @@ -0,0 +1,317 @@ | |||
| 1 | /* | ||
| 2 | * Recognize and maintain s390 storage class memory. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/device.h> | ||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/mutex.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include <linux/init.h> | ||
| 13 | #include <linux/err.h> | ||
| 14 | #include <asm/eadm.h> | ||
| 15 | #include "chsc.h" | ||
| 16 | |||
| 17 | static struct device *scm_root; | ||
| 18 | static struct eadm_ops *eadm_ops; | ||
| 19 | static DEFINE_MUTEX(eadm_ops_mutex); | ||
| 20 | |||
| 21 | #define to_scm_dev(n) container_of(n, struct scm_device, dev) | ||
| 22 | #define to_scm_drv(d) container_of(d, struct scm_driver, drv) | ||
| 23 | |||
| 24 | static int scmdev_probe(struct device *dev) | ||
| 25 | { | ||
| 26 | struct scm_device *scmdev = to_scm_dev(dev); | ||
| 27 | struct scm_driver *scmdrv = to_scm_drv(dev->driver); | ||
| 28 | |||
| 29 | return scmdrv->probe ? scmdrv->probe(scmdev) : -ENODEV; | ||
| 30 | } | ||
| 31 | |||
| 32 | static int scmdev_remove(struct device *dev) | ||
| 33 | { | ||
| 34 | struct scm_device *scmdev = to_scm_dev(dev); | ||
| 35 | struct scm_driver *scmdrv = to_scm_drv(dev->driver); | ||
| 36 | |||
| 37 | return scmdrv->remove ? scmdrv->remove(scmdev) : -ENODEV; | ||
| 38 | } | ||
| 39 | |||
| 40 | static int scmdev_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
| 41 | { | ||
| 42 | return add_uevent_var(env, "MODALIAS=scm:scmdev"); | ||
| 43 | } | ||
| 44 | |||
| 45 | static struct bus_type scm_bus_type = { | ||
| 46 | .name = "scm", | ||
| 47 | .probe = scmdev_probe, | ||
| 48 | .remove = scmdev_remove, | ||
| 49 | .uevent = scmdev_uevent, | ||
| 50 | }; | ||
| 51 | |||
| 52 | /** | ||
| 53 | * scm_driver_register() - register a scm driver | ||
| 54 | * @scmdrv: driver to be registered | ||
| 55 | */ | ||
| 56 | int scm_driver_register(struct scm_driver *scmdrv) | ||
| 57 | { | ||
| 58 | struct device_driver *drv = &scmdrv->drv; | ||
| 59 | |||
| 60 | drv->bus = &scm_bus_type; | ||
| 61 | |||
| 62 | return driver_register(drv); | ||
| 63 | } | ||
| 64 | EXPORT_SYMBOL_GPL(scm_driver_register); | ||
| 65 | |||
| 66 | /** | ||
| 67 | * scm_driver_unregister() - deregister a scm driver | ||
| 68 | * @scmdrv: driver to be deregistered | ||
| 69 | */ | ||
| 70 | void scm_driver_unregister(struct scm_driver *scmdrv) | ||
| 71 | { | ||
| 72 | driver_unregister(&scmdrv->drv); | ||
| 73 | } | ||
| 74 | EXPORT_SYMBOL_GPL(scm_driver_unregister); | ||
| 75 | |||
| 76 | int scm_get_ref(void) | ||
| 77 | { | ||
| 78 | int ret = 0; | ||
| 79 | |||
| 80 | mutex_lock(&eadm_ops_mutex); | ||
| 81 | if (!eadm_ops || !try_module_get(eadm_ops->owner)) | ||
| 82 | ret = -ENOENT; | ||
| 83 | mutex_unlock(&eadm_ops_mutex); | ||
| 84 | |||
| 85 | return ret; | ||
| 86 | } | ||
| 87 | EXPORT_SYMBOL_GPL(scm_get_ref); | ||
| 88 | |||
| 89 | void scm_put_ref(void) | ||
| 90 | { | ||
| 91 | mutex_lock(&eadm_ops_mutex); | ||
| 92 | module_put(eadm_ops->owner); | ||
| 93 | mutex_unlock(&eadm_ops_mutex); | ||
| 94 | } | ||
| 95 | EXPORT_SYMBOL_GPL(scm_put_ref); | ||
| 96 | |||
| 97 | void register_eadm_ops(struct eadm_ops *ops) | ||
| 98 | { | ||
| 99 | mutex_lock(&eadm_ops_mutex); | ||
| 100 | eadm_ops = ops; | ||
| 101 | mutex_unlock(&eadm_ops_mutex); | ||
| 102 | } | ||
| 103 | EXPORT_SYMBOL_GPL(register_eadm_ops); | ||
| 104 | |||
| 105 | void unregister_eadm_ops(struct eadm_ops *ops) | ||
| 106 | { | ||
| 107 | mutex_lock(&eadm_ops_mutex); | ||
| 108 | eadm_ops = NULL; | ||
| 109 | mutex_unlock(&eadm_ops_mutex); | ||
| 110 | } | ||
| 111 | EXPORT_SYMBOL_GPL(unregister_eadm_ops); | ||
| 112 | |||
| 113 | int scm_start_aob(struct aob *aob) | ||
| 114 | { | ||
| 115 | return eadm_ops->eadm_start(aob); | ||
| 116 | } | ||
| 117 | EXPORT_SYMBOL_GPL(scm_start_aob); | ||
| 118 | |||
| 119 | void scm_irq_handler(struct aob *aob, int error) | ||
| 120 | { | ||
| 121 | struct aob_rq_header *aobrq = (void *) aob->request.data; | ||
| 122 | struct scm_device *scmdev = aobrq->scmdev; | ||
| 123 | struct scm_driver *scmdrv = to_scm_drv(scmdev->dev.driver); | ||
| 124 | |||
| 125 | scmdrv->handler(scmdev, aobrq->data, error); | ||
| 126 | } | ||
| 127 | EXPORT_SYMBOL_GPL(scm_irq_handler); | ||
| 128 | |||
| 129 | #define scm_attr(name) \ | ||
| 130 | static ssize_t show_##name(struct device *dev, \ | ||
| 131 | struct device_attribute *attr, char *buf) \ | ||
| 132 | { \ | ||
| 133 | struct scm_device *scmdev = to_scm_dev(dev); \ | ||
| 134 | int ret; \ | ||
| 135 | \ | ||
| 136 | device_lock(dev); \ | ||
| 137 | ret = sprintf(buf, "%u\n", scmdev->attrs.name); \ | ||
| 138 | device_unlock(dev); \ | ||
| 139 | \ | ||
| 140 | return ret; \ | ||
| 141 | } \ | ||
| 142 | static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); | ||
| 143 | |||
| 144 | scm_attr(persistence); | ||
| 145 | scm_attr(oper_state); | ||
| 146 | scm_attr(data_state); | ||
| 147 | scm_attr(rank); | ||
| 148 | scm_attr(release); | ||
| 149 | scm_attr(res_id); | ||
| 150 | |||
| 151 | static struct attribute *scmdev_attrs[] = { | ||
| 152 | &dev_attr_persistence.attr, | ||
| 153 | &dev_attr_oper_state.attr, | ||
| 154 | &dev_attr_data_state.attr, | ||
| 155 | &dev_attr_rank.attr, | ||
| 156 | &dev_attr_release.attr, | ||
| 157 | &dev_attr_res_id.attr, | ||
| 158 | NULL, | ||
| 159 | }; | ||
| 160 | |||
| 161 | static struct attribute_group scmdev_attr_group = { | ||
| 162 | .attrs = scmdev_attrs, | ||
| 163 | }; | ||
| 164 | |||
| 165 | static const struct attribute_group *scmdev_attr_groups[] = { | ||
| 166 | &scmdev_attr_group, | ||
| 167 | NULL, | ||
| 168 | }; | ||
| 169 | |||
| 170 | static void scmdev_release(struct device *dev) | ||
| 171 | { | ||
| 172 | struct scm_device *scmdev = to_scm_dev(dev); | ||
| 173 | |||
| 174 | kfree(scmdev); | ||
| 175 | } | ||
| 176 | |||
| 177 | static void scmdev_setup(struct scm_device *scmdev, struct sale *sale, | ||
| 178 | unsigned int size, unsigned int max_blk_count) | ||
| 179 | { | ||
| 180 | dev_set_name(&scmdev->dev, "%016llx", (unsigned long long) sale->sa); | ||
| 181 | scmdev->nr_max_block = max_blk_count; | ||
| 182 | scmdev->address = sale->sa; | ||
| 183 | scmdev->size = 1UL << size; | ||
| 184 | scmdev->attrs.rank = sale->rank; | ||
| 185 | scmdev->attrs.persistence = sale->p; | ||
| 186 | scmdev->attrs.oper_state = sale->op_state; | ||
| 187 | scmdev->attrs.data_state = sale->data_state; | ||
| 188 | scmdev->attrs.rank = sale->rank; | ||
| 189 | scmdev->attrs.release = sale->r; | ||
| 190 | scmdev->attrs.res_id = sale->rid; | ||
| 191 | scmdev->dev.parent = scm_root; | ||
| 192 | scmdev->dev.bus = &scm_bus_type; | ||
| 193 | scmdev->dev.release = scmdev_release; | ||
| 194 | scmdev->dev.groups = scmdev_attr_groups; | ||
| 195 | } | ||
| 196 | |||
| 197 | /* | ||
| 198 | * Check for state-changes, notify the driver and userspace. | ||
| 199 | */ | ||
| 200 | static void scmdev_update(struct scm_device *scmdev, struct sale *sale) | ||
| 201 | { | ||
| 202 | struct scm_driver *scmdrv; | ||
| 203 | bool changed; | ||
| 204 | |||
| 205 | device_lock(&scmdev->dev); | ||
| 206 | changed = scmdev->attrs.rank != sale->rank || | ||
| 207 | scmdev->attrs.oper_state != sale->op_state; | ||
| 208 | scmdev->attrs.rank = sale->rank; | ||
| 209 | scmdev->attrs.oper_state = sale->op_state; | ||
| 210 | if (!scmdev->dev.driver) | ||
| 211 | goto out; | ||
| 212 | scmdrv = to_scm_drv(scmdev->dev.driver); | ||
| 213 | if (changed && scmdrv->notify) | ||
| 214 | scmdrv->notify(scmdev); | ||
| 215 | out: | ||
| 216 | device_unlock(&scmdev->dev); | ||
| 217 | if (changed) | ||
| 218 | kobject_uevent(&scmdev->dev.kobj, KOBJ_CHANGE); | ||
| 219 | } | ||
| 220 | |||
| 221 | static int check_address(struct device *dev, void *data) | ||
| 222 | { | ||
| 223 | struct scm_device *scmdev = to_scm_dev(dev); | ||
| 224 | struct sale *sale = data; | ||
| 225 | |||
| 226 | return scmdev->address == sale->sa; | ||
| 227 | } | ||
| 228 | |||
| 229 | static struct scm_device *scmdev_find(struct sale *sale) | ||
| 230 | { | ||
| 231 | struct device *dev; | ||
| 232 | |||
| 233 | dev = bus_find_device(&scm_bus_type, NULL, sale, check_address); | ||
| 234 | |||
| 235 | return dev ? to_scm_dev(dev) : NULL; | ||
| 236 | } | ||
| 237 | |||
| 238 | static int scm_add(struct chsc_scm_info *scm_info, size_t num) | ||
| 239 | { | ||
| 240 | struct sale *sale, *scmal = scm_info->scmal; | ||
| 241 | struct scm_device *scmdev; | ||
| 242 | int ret; | ||
| 243 | |||
| 244 | for (sale = scmal; sale < scmal + num; sale++) { | ||
| 245 | scmdev = scmdev_find(sale); | ||
| 246 | if (scmdev) { | ||
| 247 | scmdev_update(scmdev, sale); | ||
| 248 | /* Release reference from scm_find(). */ | ||
| 249 | put_device(&scmdev->dev); | ||
| 250 | continue; | ||
| 251 | } | ||
| 252 | scmdev = kzalloc(sizeof(*scmdev), GFP_KERNEL); | ||
| 253 | if (!scmdev) | ||
| 254 | return -ENODEV; | ||
| 255 | scmdev_setup(scmdev, sale, scm_info->is, scm_info->mbc); | ||
| 256 | ret = device_register(&scmdev->dev); | ||
| 257 | if (ret) { | ||
| 258 | /* Release reference from device_initialize(). */ | ||
| 259 | put_device(&scmdev->dev); | ||
| 260 | return ret; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | return 0; | ||
| 265 | } | ||
| 266 | |||
| 267 | int scm_update_information(void) | ||
| 268 | { | ||
| 269 | struct chsc_scm_info *scm_info; | ||
| 270 | u64 token = 0; | ||
| 271 | size_t num; | ||
| 272 | int ret; | ||
| 273 | |||
| 274 | scm_info = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); | ||
| 275 | if (!scm_info) | ||
| 276 | return -ENOMEM; | ||
| 277 | |||
| 278 | do { | ||
| 279 | ret = chsc_scm_info(scm_info, token); | ||
| 280 | if (ret) | ||
| 281 | break; | ||
| 282 | |||
| 283 | num = (scm_info->response.length - | ||
| 284 | (offsetof(struct chsc_scm_info, scmal) - | ||
| 285 | offsetof(struct chsc_scm_info, response)) | ||
| 286 | ) / sizeof(struct sale); | ||
| 287 | |||
| 288 | ret = scm_add(scm_info, num); | ||
| 289 | if (ret) | ||
| 290 | break; | ||
| 291 | |||
| 292 | token = scm_info->restok; | ||
| 293 | } while (token); | ||
| 294 | |||
| 295 | free_page((unsigned long)scm_info); | ||
| 296 | |||
| 297 | return ret; | ||
| 298 | } | ||
| 299 | |||
| 300 | static int __init scm_init(void) | ||
| 301 | { | ||
| 302 | int ret; | ||
| 303 | |||
| 304 | ret = bus_register(&scm_bus_type); | ||
| 305 | if (ret) | ||
| 306 | return ret; | ||
| 307 | |||
| 308 | scm_root = root_device_register("scm"); | ||
| 309 | if (IS_ERR(scm_root)) { | ||
| 310 | bus_unregister(&scm_bus_type); | ||
| 311 | return PTR_ERR(scm_root); | ||
| 312 | } | ||
| 313 | |||
| 314 | scm_update_information(); | ||
| 315 | return 0; | ||
| 316 | } | ||
| 317 | subsys_initcall_sync(scm_init); | ||
diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index af3c7f16ea88..771faf7094d6 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile | |||
| @@ -4,4 +4,5 @@ | |||
| 4 | 4 | ||
| 5 | ap-objs := ap_bus.o | 5 | ap-objs := ap_bus.o |
| 6 | obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o zcrypt_pcicc.o zcrypt_pcixcc.o | 6 | obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o zcrypt_pcicc.o zcrypt_pcixcc.o |
| 7 | obj-$(CONFIG_ZCRYPT) += zcrypt_pcica.o zcrypt_cex2a.o | 7 | obj-$(CONFIG_ZCRYPT) += zcrypt_pcica.o zcrypt_cex2a.o zcrypt_cex4.o |
| 8 | obj-$(CONFIG_ZCRYPT) += zcrypt_msgtype6.o zcrypt_msgtype50.o | ||
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index ae258a4b4e5e..7b865a7300e6 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright IBM Corp. 2006 | 2 | * Copyright IBM Corp. 2006, 2012 |
| 3 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> | 3 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> |
| 4 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 4 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 5 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | 5 | * Ralph Wuerthner <rwuerthn@de.ibm.com> |
| @@ -62,13 +62,14 @@ static void ap_interrupt_handler(void *unused1, void *unused2); | |||
| 62 | static void ap_reset(struct ap_device *ap_dev); | 62 | static void ap_reset(struct ap_device *ap_dev); |
| 63 | static void ap_config_timeout(unsigned long ptr); | 63 | static void ap_config_timeout(unsigned long ptr); |
| 64 | static int ap_select_domain(void); | 64 | static int ap_select_domain(void); |
| 65 | static void ap_query_configuration(void); | ||
| 65 | 66 | ||
| 66 | /* | 67 | /* |
| 67 | * Module description. | 68 | * Module description. |
| 68 | */ | 69 | */ |
| 69 | MODULE_AUTHOR("IBM Corporation"); | 70 | MODULE_AUTHOR("IBM Corporation"); |
| 70 | MODULE_DESCRIPTION("Adjunct Processor Bus driver, " | 71 | MODULE_DESCRIPTION("Adjunct Processor Bus driver, " \ |
| 71 | "Copyright IBM Corp. 2006"); | 72 | "Copyright IBM Corp. 2006, 2012"); |
| 72 | MODULE_LICENSE("GPL"); | 73 | MODULE_LICENSE("GPL"); |
| 73 | 74 | ||
| 74 | /* | 75 | /* |
| @@ -84,6 +85,7 @@ module_param_named(poll_thread, ap_thread_flag, int, 0000); | |||
| 84 | MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off)."); | 85 | MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off)."); |
| 85 | 86 | ||
| 86 | static struct device *ap_root_device = NULL; | 87 | static struct device *ap_root_device = NULL; |
| 88 | static struct ap_config_info *ap_configuration; | ||
| 87 | static DEFINE_SPINLOCK(ap_device_list_lock); | 89 | static DEFINE_SPINLOCK(ap_device_list_lock); |
| 88 | static LIST_HEAD(ap_device_list); | 90 | static LIST_HEAD(ap_device_list); |
| 89 | 91 | ||
| @@ -158,6 +160,19 @@ static int ap_interrupts_available(void) | |||
| 158 | } | 160 | } |
| 159 | 161 | ||
| 160 | /** | 162 | /** |
| 163 | * ap_configuration_available(): Test if AP configuration | ||
| 164 | * information is available. | ||
| 165 | * | ||
| 166 | * Returns 1 if AP configuration information is available. | ||
| 167 | */ | ||
| 168 | #ifdef CONFIG_64BIT | ||
| 169 | static int ap_configuration_available(void) | ||
| 170 | { | ||
| 171 | return test_facility(2) && test_facility(12); | ||
| 172 | } | ||
| 173 | #endif | ||
| 174 | |||
| 175 | /** | ||
| 161 | * ap_test_queue(): Test adjunct processor queue. | 176 | * ap_test_queue(): Test adjunct processor queue. |
| 162 | * @qid: The AP queue number | 177 | * @qid: The AP queue number |
| 163 | * @queue_depth: Pointer to queue depth value | 178 | * @queue_depth: Pointer to queue depth value |
| @@ -242,6 +257,26 @@ __ap_query_functions(ap_qid_t qid, unsigned int *functions) | |||
| 242 | } | 257 | } |
| 243 | #endif | 258 | #endif |
| 244 | 259 | ||
| 260 | #ifdef CONFIG_64BIT | ||
| 261 | static inline int __ap_query_configuration(struct ap_config_info *config) | ||
| 262 | { | ||
| 263 | register unsigned long reg0 asm ("0") = 0x04000000UL; | ||
| 264 | register unsigned long reg1 asm ("1") = -EINVAL; | ||
| 265 | register unsigned char *reg2 asm ("2") = (unsigned char *)config; | ||
| 266 | |||
| 267 | asm volatile( | ||
| 268 | ".long 0xb2af0000\n" /* PQAP(QCI) */ | ||
| 269 | "0: la %1,0\n" | ||
| 270 | "1:\n" | ||
| 271 | EX_TABLE(0b, 1b) | ||
| 272 | : "+d" (reg0), "+d" (reg1), "+d" (reg2) | ||
| 273 | : | ||
| 274 | : "cc"); | ||
| 275 | |||
| 276 | return reg1; | ||
| 277 | } | ||
| 278 | #endif | ||
| 279 | |||
| 245 | /** | 280 | /** |
| 246 | * ap_query_functions(): Query supported functions. | 281 | * ap_query_functions(): Query supported functions. |
| 247 | * @qid: The AP queue number | 282 | * @qid: The AP queue number |
| @@ -292,25 +327,6 @@ static int ap_query_functions(ap_qid_t qid, unsigned int *functions) | |||
| 292 | } | 327 | } |
| 293 | 328 | ||
| 294 | /** | 329 | /** |
| 295 | * ap_4096_commands_availablen(): Check for availability of 4096 bit RSA | ||
| 296 | * support. | ||
| 297 | * @qid: The AP queue number | ||
| 298 | * | ||
| 299 | * Returns 1 if 4096 bit RSA keys are support fo the AP, returns 0 if not. | ||
| 300 | */ | ||
| 301 | int ap_4096_commands_available(ap_qid_t qid) | ||
| 302 | { | ||
| 303 | unsigned int functions; | ||
| 304 | |||
| 305 | if (ap_query_functions(qid, &functions)) | ||
| 306 | return 0; | ||
| 307 | |||
| 308 | return test_ap_facility(functions, 1) && | ||
| 309 | test_ap_facility(functions, 2); | ||
| 310 | } | ||
| 311 | EXPORT_SYMBOL(ap_4096_commands_available); | ||
| 312 | |||
| 313 | /** | ||
| 314 | * ap_queue_enable_interruption(): Enable interruption on an AP. | 330 | * ap_queue_enable_interruption(): Enable interruption on an AP. |
| 315 | * @qid: The AP queue number | 331 | * @qid: The AP queue number |
| 316 | * @ind: the notification indicator byte | 332 | * @ind: the notification indicator byte |
| @@ -657,6 +673,34 @@ static ssize_t ap_request_count_show(struct device *dev, | |||
| 657 | 673 | ||
| 658 | static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL); | 674 | static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL); |
| 659 | 675 | ||
| 676 | static ssize_t ap_requestq_count_show(struct device *dev, | ||
| 677 | struct device_attribute *attr, char *buf) | ||
| 678 | { | ||
| 679 | struct ap_device *ap_dev = to_ap_dev(dev); | ||
| 680 | int rc; | ||
| 681 | |||
| 682 | spin_lock_bh(&ap_dev->lock); | ||
| 683 | rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->requestq_count); | ||
| 684 | spin_unlock_bh(&ap_dev->lock); | ||
| 685 | return rc; | ||
| 686 | } | ||
| 687 | |||
| 688 | static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL); | ||
| 689 | |||
| 690 | static ssize_t ap_pendingq_count_show(struct device *dev, | ||
| 691 | struct device_attribute *attr, char *buf) | ||
| 692 | { | ||
| 693 | struct ap_device *ap_dev = to_ap_dev(dev); | ||
| 694 | int rc; | ||
| 695 | |||
| 696 | spin_lock_bh(&ap_dev->lock); | ||
| 697 | rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->pendingq_count); | ||
| 698 | spin_unlock_bh(&ap_dev->lock); | ||
| 699 | return rc; | ||
| 700 | } | ||
| 701 | |||
| 702 | static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL); | ||
| 703 | |||
| 660 | static ssize_t ap_modalias_show(struct device *dev, | 704 | static ssize_t ap_modalias_show(struct device *dev, |
| 661 | struct device_attribute *attr, char *buf) | 705 | struct device_attribute *attr, char *buf) |
| 662 | { | 706 | { |
| @@ -665,11 +709,23 @@ static ssize_t ap_modalias_show(struct device *dev, | |||
| 665 | 709 | ||
| 666 | static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL); | 710 | static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL); |
| 667 | 711 | ||
| 712 | static ssize_t ap_functions_show(struct device *dev, | ||
| 713 | struct device_attribute *attr, char *buf) | ||
| 714 | { | ||
| 715 | struct ap_device *ap_dev = to_ap_dev(dev); | ||
| 716 | return snprintf(buf, PAGE_SIZE, "0x%08X\n", ap_dev->functions); | ||
| 717 | } | ||
| 718 | |||
| 719 | static DEVICE_ATTR(ap_functions, 0444, ap_functions_show, NULL); | ||
| 720 | |||
| 668 | static struct attribute *ap_dev_attrs[] = { | 721 | static struct attribute *ap_dev_attrs[] = { |
| 669 | &dev_attr_hwtype.attr, | 722 | &dev_attr_hwtype.attr, |
| 670 | &dev_attr_depth.attr, | 723 | &dev_attr_depth.attr, |
| 671 | &dev_attr_request_count.attr, | 724 | &dev_attr_request_count.attr, |
| 725 | &dev_attr_requestq_count.attr, | ||
| 726 | &dev_attr_pendingq_count.attr, | ||
| 672 | &dev_attr_modalias.attr, | 727 | &dev_attr_modalias.attr, |
| 728 | &dev_attr_ap_functions.attr, | ||
| 673 | NULL | 729 | NULL |
| 674 | }; | 730 | }; |
| 675 | static struct attribute_group ap_dev_attr_group = { | 731 | static struct attribute_group ap_dev_attr_group = { |
| @@ -772,6 +828,7 @@ static int ap_bus_resume(struct device *dev) | |||
| 772 | ap_suspend_flag = 0; | 828 | ap_suspend_flag = 0; |
| 773 | if (!ap_interrupts_available()) | 829 | if (!ap_interrupts_available()) |
| 774 | ap_interrupt_indicator = NULL; | 830 | ap_interrupt_indicator = NULL; |
| 831 | ap_query_configuration(); | ||
| 775 | if (!user_set_domain) { | 832 | if (!user_set_domain) { |
| 776 | ap_domain_index = -1; | 833 | ap_domain_index = -1; |
| 777 | ap_select_domain(); | 834 | ap_select_domain(); |
| @@ -895,6 +952,20 @@ void ap_driver_unregister(struct ap_driver *ap_drv) | |||
| 895 | } | 952 | } |
| 896 | EXPORT_SYMBOL(ap_driver_unregister); | 953 | EXPORT_SYMBOL(ap_driver_unregister); |
| 897 | 954 | ||
| 955 | void ap_bus_force_rescan(void) | ||
| 956 | { | ||
| 957 | /* Delete the AP bus rescan timer. */ | ||
| 958 | del_timer(&ap_config_timer); | ||
| 959 | |||
| 960 | /* processing a synchonuous bus rescan */ | ||
| 961 | ap_scan_bus(NULL); | ||
| 962 | |||
| 963 | /* Setup the AP bus rescan timer again. */ | ||
| 964 | ap_config_timer.expires = jiffies + ap_config_time * HZ; | ||
| 965 | add_timer(&ap_config_timer); | ||
| 966 | } | ||
| 967 | EXPORT_SYMBOL(ap_bus_force_rescan); | ||
| 968 | |||
| 898 | /* | 969 | /* |
| 899 | * AP bus attributes. | 970 | * AP bus attributes. |
| 900 | */ | 971 | */ |
| @@ -997,6 +1068,65 @@ static struct bus_attribute *const ap_bus_attrs[] = { | |||
| 997 | NULL, | 1068 | NULL, |
| 998 | }; | 1069 | }; |
| 999 | 1070 | ||
| 1071 | static inline int ap_test_config(unsigned int *field, unsigned int nr) | ||
| 1072 | { | ||
| 1073 | if (nr > 0xFFu) | ||
| 1074 | return 0; | ||
| 1075 | return ap_test_bit((field + (nr >> 5)), (nr & 0x1f)); | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | /* | ||
| 1079 | * ap_test_config_card_id(): Test, whether an AP card ID is configured. | ||
| 1080 | * @id AP card ID | ||
| 1081 | * | ||
| 1082 | * Returns 0 if the card is not configured | ||
| 1083 | * 1 if the card is configured or | ||
| 1084 | * if the configuration information is not available | ||
| 1085 | */ | ||
| 1086 | static inline int ap_test_config_card_id(unsigned int id) | ||
| 1087 | { | ||
| 1088 | if (!ap_configuration) | ||
| 1089 | return 1; | ||
| 1090 | return ap_test_config(ap_configuration->apm, id); | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | /* | ||
| 1094 | * ap_test_config_domain(): Test, whether an AP usage domain is configured. | ||
| 1095 | * @domain AP usage domain ID | ||
| 1096 | * | ||
| 1097 | * Returns 0 if the usage domain is not configured | ||
| 1098 | * 1 if the usage domain is configured or | ||
| 1099 | * if the configuration information is not available | ||
| 1100 | */ | ||
| 1101 | static inline int ap_test_config_domain(unsigned int domain) | ||
| 1102 | { | ||
| 1103 | if (!ap_configuration) | ||
| 1104 | return 1; | ||
| 1105 | return ap_test_config(ap_configuration->aqm, domain); | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | /** | ||
| 1109 | * ap_query_configuration(): Query AP configuration information. | ||
| 1110 | * | ||
| 1111 | * Query information of installed cards and configured domains from AP. | ||
| 1112 | */ | ||
| 1113 | static void ap_query_configuration(void) | ||
| 1114 | { | ||
| 1115 | #ifdef CONFIG_64BIT | ||
| 1116 | if (ap_configuration_available()) { | ||
| 1117 | if (!ap_configuration) | ||
| 1118 | ap_configuration = | ||
| 1119 | kzalloc(sizeof(struct ap_config_info), | ||
| 1120 | GFP_KERNEL); | ||
| 1121 | if (ap_configuration) | ||
| 1122 | __ap_query_configuration(ap_configuration); | ||
| 1123 | } else | ||
| 1124 | ap_configuration = NULL; | ||
| 1125 | #else | ||
| 1126 | ap_configuration = NULL; | ||
| 1127 | #endif | ||
| 1128 | } | ||
| 1129 | |||
| 1000 | /** | 1130 | /** |
| 1001 | * ap_select_domain(): Select an AP domain. | 1131 | * ap_select_domain(): Select an AP domain. |
| 1002 | * | 1132 | * |
| @@ -1005,6 +1135,7 @@ static struct bus_attribute *const ap_bus_attrs[] = { | |||
| 1005 | static int ap_select_domain(void) | 1135 | static int ap_select_domain(void) |
| 1006 | { | 1136 | { |
| 1007 | int queue_depth, device_type, count, max_count, best_domain; | 1137 | int queue_depth, device_type, count, max_count, best_domain; |
| 1138 | ap_qid_t qid; | ||
| 1008 | int rc, i, j; | 1139 | int rc, i, j; |
| 1009 | 1140 | ||
| 1010 | /* | 1141 | /* |
| @@ -1018,9 +1149,13 @@ static int ap_select_domain(void) | |||
| 1018 | best_domain = -1; | 1149 | best_domain = -1; |
| 1019 | max_count = 0; | 1150 | max_count = 0; |
| 1020 | for (i = 0; i < AP_DOMAINS; i++) { | 1151 | for (i = 0; i < AP_DOMAINS; i++) { |
| 1152 | if (!ap_test_config_domain(i)) | ||
| 1153 | continue; | ||
| 1021 | count = 0; | 1154 | count = 0; |
| 1022 | for (j = 0; j < AP_DEVICES; j++) { | 1155 | for (j = 0; j < AP_DEVICES; j++) { |
| 1023 | ap_qid_t qid = AP_MKQID(j, i); | 1156 | if (!ap_test_config_card_id(j)) |
| 1157 | continue; | ||
| 1158 | qid = AP_MKQID(j, i); | ||
| 1024 | rc = ap_query_queue(qid, &queue_depth, &device_type); | 1159 | rc = ap_query_queue(qid, &queue_depth, &device_type); |
| 1025 | if (rc) | 1160 | if (rc) |
| 1026 | continue; | 1161 | continue; |
| @@ -1169,6 +1304,7 @@ static void ap_scan_bus(struct work_struct *unused) | |||
| 1169 | unsigned int device_functions; | 1304 | unsigned int device_functions; |
| 1170 | int rc, i; | 1305 | int rc, i; |
| 1171 | 1306 | ||
| 1307 | ap_query_configuration(); | ||
| 1172 | if (ap_select_domain() != 0) | 1308 | if (ap_select_domain() != 0) |
| 1173 | return; | 1309 | return; |
| 1174 | for (i = 0; i < AP_DEVICES; i++) { | 1310 | for (i = 0; i < AP_DEVICES; i++) { |
| @@ -1176,7 +1312,10 @@ static void ap_scan_bus(struct work_struct *unused) | |||
| 1176 | dev = bus_find_device(&ap_bus_type, NULL, | 1312 | dev = bus_find_device(&ap_bus_type, NULL, |
| 1177 | (void *)(unsigned long)qid, | 1313 | (void *)(unsigned long)qid, |
| 1178 | __ap_scan_bus); | 1314 | __ap_scan_bus); |
| 1179 | rc = ap_query_queue(qid, &queue_depth, &device_type); | 1315 | if (ap_test_config_card_id(i)) |
| 1316 | rc = ap_query_queue(qid, &queue_depth, &device_type); | ||
| 1317 | else | ||
| 1318 | rc = -ENODEV; | ||
| 1180 | if (dev) { | 1319 | if (dev) { |
| 1181 | if (rc == -EBUSY) { | 1320 | if (rc == -EBUSY) { |
| 1182 | set_current_state(TASK_UNINTERRUPTIBLE); | 1321 | set_current_state(TASK_UNINTERRUPTIBLE); |
| @@ -1217,29 +1356,22 @@ static void ap_scan_bus(struct work_struct *unused) | |||
| 1217 | (unsigned long) ap_dev); | 1356 | (unsigned long) ap_dev); |
| 1218 | switch (device_type) { | 1357 | switch (device_type) { |
| 1219 | case 0: | 1358 | case 0: |
| 1359 | /* device type probing for old cards */ | ||
| 1220 | if (ap_probe_device_type(ap_dev)) { | 1360 | if (ap_probe_device_type(ap_dev)) { |
| 1221 | kfree(ap_dev); | 1361 | kfree(ap_dev); |
| 1222 | continue; | 1362 | continue; |
| 1223 | } | 1363 | } |
| 1224 | break; | 1364 | break; |
| 1225 | case 10: | ||
| 1226 | if (ap_query_functions(qid, &device_functions)) { | ||
| 1227 | kfree(ap_dev); | ||
| 1228 | continue; | ||
| 1229 | } | ||
| 1230 | if (test_ap_facility(device_functions, 3)) | ||
| 1231 | ap_dev->device_type = AP_DEVICE_TYPE_CEX3C; | ||
| 1232 | else if (test_ap_facility(device_functions, 4)) | ||
| 1233 | ap_dev->device_type = AP_DEVICE_TYPE_CEX3A; | ||
| 1234 | else { | ||
| 1235 | kfree(ap_dev); | ||
| 1236 | continue; | ||
| 1237 | } | ||
| 1238 | break; | ||
| 1239 | default: | 1365 | default: |
| 1240 | ap_dev->device_type = device_type; | 1366 | ap_dev->device_type = device_type; |
| 1241 | } | 1367 | } |
| 1242 | 1368 | ||
| 1369 | rc = ap_query_functions(qid, &device_functions); | ||
| 1370 | if (!rc) | ||
| 1371 | ap_dev->functions = device_functions; | ||
| 1372 | else | ||
| 1373 | ap_dev->functions = 0u; | ||
| 1374 | |||
| 1243 | ap_dev->device.bus = &ap_bus_type; | 1375 | ap_dev->device.bus = &ap_bus_type; |
| 1244 | ap_dev->device.parent = ap_root_device; | 1376 | ap_dev->device.parent = ap_root_device; |
| 1245 | if (dev_set_name(&ap_dev->device, "card%02x", | 1377 | if (dev_set_name(&ap_dev->device, "card%02x", |
| @@ -1785,6 +1917,7 @@ int __init ap_module_init(void) | |||
| 1785 | goto out_root; | 1917 | goto out_root; |
| 1786 | } | 1918 | } |
| 1787 | 1919 | ||
| 1920 | ap_query_configuration(); | ||
| 1788 | if (ap_select_domain() == 0) | 1921 | if (ap_select_domain() == 0) |
| 1789 | ap_scan_bus(NULL); | 1922 | ap_scan_bus(NULL); |
| 1790 | 1923 | ||
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 52d61995af88..685f6cc022f9 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright IBM Corp. 2006 | 2 | * Copyright IBM Corp. 2006, 2012 |
| 3 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> | 3 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> |
| 4 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 4 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 5 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | 5 | * Ralph Wuerthner <rwuerthn@de.ibm.com> |
| @@ -83,13 +83,12 @@ int ap_queue_status_invalid_test(struct ap_queue_status *status) | |||
| 83 | return !(memcmp(status, &invalid, sizeof(struct ap_queue_status))); | 83 | return !(memcmp(status, &invalid, sizeof(struct ap_queue_status))); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | #define MAX_AP_FACILITY 31 | 86 | #define AP_MAX_BITS 31 |
| 87 | 87 | static inline int ap_test_bit(unsigned int *ptr, unsigned int nr) | |
| 88 | static inline int test_ap_facility(unsigned int function, unsigned int nr) | ||
| 89 | { | 88 | { |
| 90 | if (nr > MAX_AP_FACILITY) | 89 | if (nr > AP_MAX_BITS) |
| 91 | return 0; | 90 | return 0; |
| 92 | return function & (unsigned int)(0x80000000 >> nr); | 91 | return (*ptr & (0x80000000u >> nr)) != 0; |
| 93 | } | 92 | } |
| 94 | 93 | ||
| 95 | #define AP_RESPONSE_NORMAL 0x00 | 94 | #define AP_RESPONSE_NORMAL 0x00 |
| @@ -117,6 +116,15 @@ static inline int test_ap_facility(unsigned int function, unsigned int nr) | |||
| 117 | #define AP_DEVICE_TYPE_CEX2C 7 | 116 | #define AP_DEVICE_TYPE_CEX2C 7 |
| 118 | #define AP_DEVICE_TYPE_CEX3A 8 | 117 | #define AP_DEVICE_TYPE_CEX3A 8 |
| 119 | #define AP_DEVICE_TYPE_CEX3C 9 | 118 | #define AP_DEVICE_TYPE_CEX3C 9 |
| 119 | #define AP_DEVICE_TYPE_CEX4 10 | ||
| 120 | |||
| 121 | /* | ||
| 122 | * Known function facilities | ||
| 123 | */ | ||
| 124 | #define AP_FUNC_MEX4K 1 | ||
| 125 | #define AP_FUNC_CRT4K 2 | ||
| 126 | #define AP_FUNC_COPRO 3 | ||
| 127 | #define AP_FUNC_ACCEL 4 | ||
| 120 | 128 | ||
| 121 | /* | 129 | /* |
| 122 | * AP reset flag states | 130 | * AP reset flag states |
| @@ -151,6 +159,7 @@ struct ap_device { | |||
| 151 | ap_qid_t qid; /* AP queue id. */ | 159 | ap_qid_t qid; /* AP queue id. */ |
| 152 | int queue_depth; /* AP queue depth.*/ | 160 | int queue_depth; /* AP queue depth.*/ |
| 153 | int device_type; /* AP device type. */ | 161 | int device_type; /* AP device type. */ |
| 162 | unsigned int functions; /* AP device function bitfield. */ | ||
| 154 | int unregistered; /* marks AP device as unregistered */ | 163 | int unregistered; /* marks AP device as unregistered */ |
| 155 | struct timer_list timeout; /* Timer for request timeouts. */ | 164 | struct timer_list timeout; /* Timer for request timeouts. */ |
| 156 | int reset; /* Reset required after req. timeout. */ | 165 | int reset; /* Reset required after req. timeout. */ |
| @@ -183,6 +192,17 @@ struct ap_message { | |||
| 183 | struct ap_message *); | 192 | struct ap_message *); |
| 184 | }; | 193 | }; |
| 185 | 194 | ||
| 195 | struct ap_config_info { | ||
| 196 | unsigned int special_command:1; | ||
| 197 | unsigned int ap_extended:1; | ||
| 198 | unsigned char reserved1:6; | ||
| 199 | unsigned char reserved2[15]; | ||
| 200 | unsigned int apm[8]; /* AP ID mask */ | ||
| 201 | unsigned int aqm[8]; /* AP queue mask */ | ||
| 202 | unsigned int adm[8]; /* AP domain mask */ | ||
| 203 | unsigned char reserved4[16]; | ||
| 204 | } __packed; | ||
| 205 | |||
| 186 | #define AP_DEVICE(dt) \ | 206 | #define AP_DEVICE(dt) \ |
| 187 | .dev_type=(dt), \ | 207 | .dev_type=(dt), \ |
| 188 | .match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE, | 208 | .match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE, |
| @@ -211,10 +231,9 @@ int ap_recv(ap_qid_t, unsigned long long *, void *, size_t); | |||
| 211 | void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg); | 231 | void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg); |
| 212 | void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg); | 232 | void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg); |
| 213 | void ap_flush_queue(struct ap_device *ap_dev); | 233 | void ap_flush_queue(struct ap_device *ap_dev); |
| 234 | void ap_bus_force_rescan(void); | ||
| 214 | 235 | ||
| 215 | int ap_module_init(void); | 236 | int ap_module_init(void); |
| 216 | void ap_module_exit(void); | 237 | void ap_module_exit(void); |
| 217 | 238 | ||
| 218 | int ap_4096_commands_available(ap_qid_t qid); | ||
| 219 | |||
| 220 | #endif /* _AP_BUS_H_ */ | 239 | #endif /* _AP_BUS_H_ */ |
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 2f94132246a1..31cfaa556072 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * zcrypt 2.1.0 | 2 | * zcrypt 2.1.0 |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2001, 2006 | 4 | * Copyright IBM Corp. 2001, 2012 |
| 5 | * Author(s): Robert Burroughs | 5 | * Author(s): Robert Burroughs |
| 6 | * Eric Rossman (edrossma@us.ibm.com) | 6 | * Eric Rossman (edrossma@us.ibm.com) |
| 7 | * Cornelia Huck <cornelia.huck@de.ibm.com> | 7 | * Cornelia Huck <cornelia.huck@de.ibm.com> |
| @@ -9,6 +9,7 @@ | |||
| 9 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | 9 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) |
| 10 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | 10 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 11 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | 11 | * Ralph Wuerthner <rwuerthn@de.ibm.com> |
| 12 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 12 | * | 13 | * |
| 13 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
| 14 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
| @@ -37,25 +38,39 @@ | |||
| 37 | #include <linux/atomic.h> | 38 | #include <linux/atomic.h> |
| 38 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
| 39 | #include <linux/hw_random.h> | 40 | #include <linux/hw_random.h> |
| 41 | #include <linux/debugfs.h> | ||
| 42 | #include <asm/debug.h> | ||
| 40 | 43 | ||
| 44 | #include "zcrypt_debug.h" | ||
| 41 | #include "zcrypt_api.h" | 45 | #include "zcrypt_api.h" |
| 42 | 46 | ||
| 43 | /* | 47 | /* |
| 44 | * Module description. | 48 | * Module description. |
| 45 | */ | 49 | */ |
| 46 | MODULE_AUTHOR("IBM Corporation"); | 50 | MODULE_AUTHOR("IBM Corporation"); |
| 47 | MODULE_DESCRIPTION("Cryptographic Coprocessor interface, " | 51 | MODULE_DESCRIPTION("Cryptographic Coprocessor interface, " \ |
| 48 | "Copyright IBM Corp. 2001, 2006"); | 52 | "Copyright IBM Corp. 2001, 2012"); |
| 49 | MODULE_LICENSE("GPL"); | 53 | MODULE_LICENSE("GPL"); |
| 50 | 54 | ||
| 51 | static DEFINE_SPINLOCK(zcrypt_device_lock); | 55 | static DEFINE_SPINLOCK(zcrypt_device_lock); |
| 52 | static LIST_HEAD(zcrypt_device_list); | 56 | static LIST_HEAD(zcrypt_device_list); |
| 53 | static int zcrypt_device_count = 0; | 57 | static int zcrypt_device_count = 0; |
| 54 | static atomic_t zcrypt_open_count = ATOMIC_INIT(0); | 58 | static atomic_t zcrypt_open_count = ATOMIC_INIT(0); |
| 59 | static atomic_t zcrypt_rescan_count = ATOMIC_INIT(0); | ||
| 60 | |||
| 61 | atomic_t zcrypt_rescan_req = ATOMIC_INIT(0); | ||
| 62 | EXPORT_SYMBOL(zcrypt_rescan_req); | ||
| 55 | 63 | ||
| 56 | static int zcrypt_rng_device_add(void); | 64 | static int zcrypt_rng_device_add(void); |
| 57 | static void zcrypt_rng_device_remove(void); | 65 | static void zcrypt_rng_device_remove(void); |
| 58 | 66 | ||
| 67 | static DEFINE_SPINLOCK(zcrypt_ops_list_lock); | ||
| 68 | static LIST_HEAD(zcrypt_ops_list); | ||
| 69 | |||
| 70 | static debug_info_t *zcrypt_dbf_common; | ||
| 71 | static debug_info_t *zcrypt_dbf_devices; | ||
| 72 | static struct dentry *debugfs_root; | ||
| 73 | |||
| 59 | /* | 74 | /* |
| 60 | * Device attributes common for all crypto devices. | 75 | * Device attributes common for all crypto devices. |
| 61 | */ | 76 | */ |
| @@ -85,6 +100,8 @@ static ssize_t zcrypt_online_store(struct device *dev, | |||
| 85 | if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) | 100 | if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) |
| 86 | return -EINVAL; | 101 | return -EINVAL; |
| 87 | zdev->online = online; | 102 | zdev->online = online; |
| 103 | ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dman", zdev->ap_dev->qid, | ||
| 104 | zdev->online); | ||
| 88 | if (!online) | 105 | if (!online) |
| 89 | ap_flush_queue(zdev->ap_dev); | 106 | ap_flush_queue(zdev->ap_dev); |
| 90 | return count; | 107 | return count; |
| @@ -103,6 +120,24 @@ static struct attribute_group zcrypt_device_attr_group = { | |||
| 103 | }; | 120 | }; |
| 104 | 121 | ||
| 105 | /** | 122 | /** |
| 123 | * Process a rescan of the transport layer. | ||
| 124 | * | ||
| 125 | * Returns 1, if the rescan has been processed, otherwise 0. | ||
| 126 | */ | ||
| 127 | static inline int zcrypt_process_rescan(void) | ||
| 128 | { | ||
| 129 | if (atomic_read(&zcrypt_rescan_req)) { | ||
| 130 | atomic_set(&zcrypt_rescan_req, 0); | ||
| 131 | atomic_inc(&zcrypt_rescan_count); | ||
| 132 | ap_bus_force_rescan(); | ||
| 133 | ZCRYPT_DBF_COMMON(DBF_INFO, "rescan%07d", | ||
| 134 | atomic_inc_return(&zcrypt_rescan_count)); | ||
| 135 | return 1; | ||
| 136 | } | ||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | /** | ||
| 106 | * __zcrypt_increase_preference(): Increase preference of a crypto device. | 141 | * __zcrypt_increase_preference(): Increase preference of a crypto device. |
| 107 | * @zdev: Pointer the crypto device | 142 | * @zdev: Pointer the crypto device |
| 108 | * | 143 | * |
| @@ -190,6 +225,7 @@ struct zcrypt_device *zcrypt_device_alloc(size_t max_response_size) | |||
| 190 | zdev->reply.length = max_response_size; | 225 | zdev->reply.length = max_response_size; |
| 191 | spin_lock_init(&zdev->lock); | 226 | spin_lock_init(&zdev->lock); |
| 192 | INIT_LIST_HEAD(&zdev->list); | 227 | INIT_LIST_HEAD(&zdev->list); |
| 228 | zdev->dbf_area = zcrypt_dbf_devices; | ||
| 193 | return zdev; | 229 | return zdev; |
| 194 | 230 | ||
| 195 | out_free: | 231 | out_free: |
| @@ -215,6 +251,8 @@ int zcrypt_device_register(struct zcrypt_device *zdev) | |||
| 215 | { | 251 | { |
| 216 | int rc; | 252 | int rc; |
| 217 | 253 | ||
| 254 | if (!zdev->ops) | ||
| 255 | return -ENODEV; | ||
| 218 | rc = sysfs_create_group(&zdev->ap_dev->device.kobj, | 256 | rc = sysfs_create_group(&zdev->ap_dev->device.kobj, |
| 219 | &zcrypt_device_attr_group); | 257 | &zcrypt_device_attr_group); |
| 220 | if (rc) | 258 | if (rc) |
| @@ -223,6 +261,8 @@ int zcrypt_device_register(struct zcrypt_device *zdev) | |||
| 223 | kref_init(&zdev->refcount); | 261 | kref_init(&zdev->refcount); |
| 224 | spin_lock_bh(&zcrypt_device_lock); | 262 | spin_lock_bh(&zcrypt_device_lock); |
| 225 | zdev->online = 1; /* New devices are online by default. */ | 263 | zdev->online = 1; /* New devices are online by default. */ |
| 264 | ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dreg", zdev->ap_dev->qid, | ||
| 265 | zdev->online); | ||
| 226 | list_add_tail(&zdev->list, &zcrypt_device_list); | 266 | list_add_tail(&zdev->list, &zcrypt_device_list); |
| 227 | __zcrypt_increase_preference(zdev); | 267 | __zcrypt_increase_preference(zdev); |
| 228 | zcrypt_device_count++; | 268 | zcrypt_device_count++; |
| @@ -269,6 +309,67 @@ void zcrypt_device_unregister(struct zcrypt_device *zdev) | |||
| 269 | } | 309 | } |
| 270 | EXPORT_SYMBOL(zcrypt_device_unregister); | 310 | EXPORT_SYMBOL(zcrypt_device_unregister); |
| 271 | 311 | ||
| 312 | void zcrypt_msgtype_register(struct zcrypt_ops *zops) | ||
| 313 | { | ||
| 314 | if (zops->owner) { | ||
| 315 | spin_lock_bh(&zcrypt_ops_list_lock); | ||
| 316 | list_add_tail(&zops->list, &zcrypt_ops_list); | ||
| 317 | spin_unlock_bh(&zcrypt_ops_list_lock); | ||
| 318 | } | ||
| 319 | } | ||
| 320 | EXPORT_SYMBOL(zcrypt_msgtype_register); | ||
| 321 | |||
| 322 | void zcrypt_msgtype_unregister(struct zcrypt_ops *zops) | ||
| 323 | { | ||
| 324 | spin_lock_bh(&zcrypt_ops_list_lock); | ||
| 325 | list_del_init(&zops->list); | ||
| 326 | spin_unlock_bh(&zcrypt_ops_list_lock); | ||
| 327 | } | ||
| 328 | EXPORT_SYMBOL(zcrypt_msgtype_unregister); | ||
| 329 | |||
| 330 | static inline | ||
| 331 | struct zcrypt_ops *__ops_lookup(unsigned char *name, int variant) | ||
| 332 | { | ||
| 333 | struct zcrypt_ops *zops; | ||
| 334 | int found = 0; | ||
| 335 | |||
| 336 | spin_lock_bh(&zcrypt_ops_list_lock); | ||
| 337 | list_for_each_entry(zops, &zcrypt_ops_list, list) { | ||
| 338 | if ((zops->variant == variant) && | ||
| 339 | (!strncmp(zops->owner->name, name, MODULE_NAME_LEN))) { | ||
| 340 | found = 1; | ||
| 341 | break; | ||
| 342 | } | ||
| 343 | } | ||
| 344 | spin_unlock_bh(&zcrypt_ops_list_lock); | ||
| 345 | |||
| 346 | if (!found) | ||
| 347 | return NULL; | ||
| 348 | return zops; | ||
| 349 | } | ||
| 350 | |||
| 351 | struct zcrypt_ops *zcrypt_msgtype_request(unsigned char *name, int variant) | ||
| 352 | { | ||
| 353 | struct zcrypt_ops *zops = NULL; | ||
| 354 | |||
| 355 | zops = __ops_lookup(name, variant); | ||
| 356 | if (!zops) { | ||
| 357 | request_module(name); | ||
| 358 | zops = __ops_lookup(name, variant); | ||
| 359 | } | ||
| 360 | if ((!zops) || (!try_module_get(zops->owner))) | ||
| 361 | return NULL; | ||
| 362 | return zops; | ||
| 363 | } | ||
| 364 | EXPORT_SYMBOL(zcrypt_msgtype_request); | ||
| 365 | |||
| 366 | void zcrypt_msgtype_release(struct zcrypt_ops *zops) | ||
| 367 | { | ||
| 368 | if (zops) | ||
| 369 | module_put(zops->owner); | ||
| 370 | } | ||
| 371 | EXPORT_SYMBOL(zcrypt_msgtype_release); | ||
| 372 | |||
| 272 | /** | 373 | /** |
| 273 | * zcrypt_read (): Not supported beyond zcrypt 1.3.1. | 374 | * zcrypt_read (): Not supported beyond zcrypt 1.3.1. |
| 274 | * | 375 | * |
| @@ -640,6 +741,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, | |||
| 640 | do { | 741 | do { |
| 641 | rc = zcrypt_rsa_modexpo(&mex); | 742 | rc = zcrypt_rsa_modexpo(&mex); |
| 642 | } while (rc == -EAGAIN); | 743 | } while (rc == -EAGAIN); |
| 744 | /* on failure: retry once again after a requested rescan */ | ||
| 745 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) | ||
| 746 | do { | ||
| 747 | rc = zcrypt_rsa_modexpo(&mex); | ||
| 748 | } while (rc == -EAGAIN); | ||
| 643 | if (rc) | 749 | if (rc) |
| 644 | return rc; | 750 | return rc; |
| 645 | return put_user(mex.outputdatalength, &umex->outputdatalength); | 751 | return put_user(mex.outputdatalength, &umex->outputdatalength); |
| @@ -652,6 +758,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, | |||
| 652 | do { | 758 | do { |
| 653 | rc = zcrypt_rsa_crt(&crt); | 759 | rc = zcrypt_rsa_crt(&crt); |
| 654 | } while (rc == -EAGAIN); | 760 | } while (rc == -EAGAIN); |
| 761 | /* on failure: retry once again after a requested rescan */ | ||
| 762 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) | ||
| 763 | do { | ||
| 764 | rc = zcrypt_rsa_crt(&crt); | ||
| 765 | } while (rc == -EAGAIN); | ||
| 655 | if (rc) | 766 | if (rc) |
| 656 | return rc; | 767 | return rc; |
| 657 | return put_user(crt.outputdatalength, &ucrt->outputdatalength); | 768 | return put_user(crt.outputdatalength, &ucrt->outputdatalength); |
| @@ -664,6 +775,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, | |||
| 664 | do { | 775 | do { |
| 665 | rc = zcrypt_send_cprb(&xcRB); | 776 | rc = zcrypt_send_cprb(&xcRB); |
| 666 | } while (rc == -EAGAIN); | 777 | } while (rc == -EAGAIN); |
| 778 | /* on failure: retry once again after a requested rescan */ | ||
| 779 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) | ||
| 780 | do { | ||
| 781 | rc = zcrypt_send_cprb(&xcRB); | ||
| 782 | } while (rc == -EAGAIN); | ||
| 667 | if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB))) | 783 | if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB))) |
| 668 | return -EFAULT; | 784 | return -EFAULT; |
| 669 | return rc; | 785 | return rc; |
| @@ -770,10 +886,15 @@ static long trans_modexpo32(struct file *filp, unsigned int cmd, | |||
| 770 | do { | 886 | do { |
| 771 | rc = zcrypt_rsa_modexpo(&mex64); | 887 | rc = zcrypt_rsa_modexpo(&mex64); |
| 772 | } while (rc == -EAGAIN); | 888 | } while (rc == -EAGAIN); |
| 773 | if (!rc) | 889 | /* on failure: retry once again after a requested rescan */ |
| 774 | rc = put_user(mex64.outputdatalength, | 890 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) |
| 775 | &umex32->outputdatalength); | 891 | do { |
| 776 | return rc; | 892 | rc = zcrypt_rsa_modexpo(&mex64); |
| 893 | } while (rc == -EAGAIN); | ||
| 894 | if (rc) | ||
| 895 | return rc; | ||
| 896 | return put_user(mex64.outputdatalength, | ||
| 897 | &umex32->outputdatalength); | ||
| 777 | } | 898 | } |
| 778 | 899 | ||
| 779 | struct compat_ica_rsa_modexpo_crt { | 900 | struct compat_ica_rsa_modexpo_crt { |
| @@ -810,10 +931,15 @@ static long trans_modexpo_crt32(struct file *filp, unsigned int cmd, | |||
| 810 | do { | 931 | do { |
| 811 | rc = zcrypt_rsa_crt(&crt64); | 932 | rc = zcrypt_rsa_crt(&crt64); |
| 812 | } while (rc == -EAGAIN); | 933 | } while (rc == -EAGAIN); |
| 813 | if (!rc) | 934 | /* on failure: retry once again after a requested rescan */ |
| 814 | rc = put_user(crt64.outputdatalength, | 935 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) |
| 815 | &ucrt32->outputdatalength); | 936 | do { |
| 816 | return rc; | 937 | rc = zcrypt_rsa_crt(&crt64); |
| 938 | } while (rc == -EAGAIN); | ||
| 939 | if (rc) | ||
| 940 | return rc; | ||
| 941 | return put_user(crt64.outputdatalength, | ||
| 942 | &ucrt32->outputdatalength); | ||
| 817 | } | 943 | } |
| 818 | 944 | ||
| 819 | struct compat_ica_xcRB { | 945 | struct compat_ica_xcRB { |
| @@ -869,6 +995,11 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd, | |||
| 869 | do { | 995 | do { |
| 870 | rc = zcrypt_send_cprb(&xcRB64); | 996 | rc = zcrypt_send_cprb(&xcRB64); |
| 871 | } while (rc == -EAGAIN); | 997 | } while (rc == -EAGAIN); |
| 998 | /* on failure: retry once again after a requested rescan */ | ||
| 999 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) | ||
| 1000 | do { | ||
| 1001 | rc = zcrypt_send_cprb(&xcRB64); | ||
| 1002 | } while (rc == -EAGAIN); | ||
| 872 | xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length; | 1003 | xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length; |
| 873 | xcRB32.reply_data_length = xcRB64.reply_data_length; | 1004 | xcRB32.reply_data_length = xcRB64.reply_data_length; |
| 874 | xcRB32.status = xcRB64.status; | 1005 | xcRB32.status = xcRB64.status; |
| @@ -1126,6 +1257,9 @@ static int zcrypt_rng_data_read(struct hwrng *rng, u32 *data) | |||
| 1126 | */ | 1257 | */ |
| 1127 | if (zcrypt_rng_buffer_index == 0) { | 1258 | if (zcrypt_rng_buffer_index == 0) { |
| 1128 | rc = zcrypt_rng((char *) zcrypt_rng_buffer); | 1259 | rc = zcrypt_rng((char *) zcrypt_rng_buffer); |
| 1260 | /* on failure: retry once again after a requested rescan */ | ||
| 1261 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) | ||
| 1262 | rc = zcrypt_rng((char *) zcrypt_rng_buffer); | ||
| 1129 | if (rc < 0) | 1263 | if (rc < 0) |
| 1130 | return -EIO; | 1264 | return -EIO; |
| 1131 | zcrypt_rng_buffer_index = rc / sizeof *data; | 1265 | zcrypt_rng_buffer_index = rc / sizeof *data; |
| @@ -1178,6 +1312,30 @@ static void zcrypt_rng_device_remove(void) | |||
| 1178 | mutex_unlock(&zcrypt_rng_mutex); | 1312 | mutex_unlock(&zcrypt_rng_mutex); |
| 1179 | } | 1313 | } |
| 1180 | 1314 | ||
| 1315 | int __init zcrypt_debug_init(void) | ||
| 1316 | { | ||
| 1317 | debugfs_root = debugfs_create_dir("zcrypt", NULL); | ||
| 1318 | |||
| 1319 | zcrypt_dbf_common = debug_register("zcrypt_common", 1, 1, 16); | ||
| 1320 | debug_register_view(zcrypt_dbf_common, &debug_hex_ascii_view); | ||
| 1321 | debug_set_level(zcrypt_dbf_common, DBF_ERR); | ||
| 1322 | |||
| 1323 | zcrypt_dbf_devices = debug_register("zcrypt_devices", 1, 1, 16); | ||
| 1324 | debug_register_view(zcrypt_dbf_devices, &debug_hex_ascii_view); | ||
| 1325 | debug_set_level(zcrypt_dbf_devices, DBF_ERR); | ||
| 1326 | |||
| 1327 | return 0; | ||
| 1328 | } | ||
| 1329 | |||
| 1330 | void zcrypt_debug_exit(void) | ||
| 1331 | { | ||
| 1332 | debugfs_remove(debugfs_root); | ||
| 1333 | if (zcrypt_dbf_common) | ||
| 1334 | debug_unregister(zcrypt_dbf_common); | ||
| 1335 | if (zcrypt_dbf_devices) | ||
| 1336 | debug_unregister(zcrypt_dbf_devices); | ||
| 1337 | } | ||
| 1338 | |||
| 1181 | /** | 1339 | /** |
| 1182 | * zcrypt_api_init(): Module initialization. | 1340 | * zcrypt_api_init(): Module initialization. |
| 1183 | * | 1341 | * |
| @@ -1187,6 +1345,12 @@ int __init zcrypt_api_init(void) | |||
| 1187 | { | 1345 | { |
| 1188 | int rc; | 1346 | int rc; |
| 1189 | 1347 | ||
| 1348 | rc = zcrypt_debug_init(); | ||
| 1349 | if (rc) | ||
| 1350 | goto out; | ||
| 1351 | |||
| 1352 | atomic_set(&zcrypt_rescan_req, 0); | ||
| 1353 | |||
| 1190 | /* Register the request sprayer. */ | 1354 | /* Register the request sprayer. */ |
| 1191 | rc = misc_register(&zcrypt_misc_device); | 1355 | rc = misc_register(&zcrypt_misc_device); |
| 1192 | if (rc < 0) | 1356 | if (rc < 0) |
| @@ -1216,6 +1380,7 @@ void zcrypt_api_exit(void) | |||
| 1216 | { | 1380 | { |
| 1217 | remove_proc_entry("driver/z90crypt", NULL); | 1381 | remove_proc_entry("driver/z90crypt", NULL); |
| 1218 | misc_deregister(&zcrypt_misc_device); | 1382 | misc_deregister(&zcrypt_misc_device); |
| 1383 | zcrypt_debug_exit(); | ||
| 1219 | } | 1384 | } |
| 1220 | 1385 | ||
| 1221 | module_init(zcrypt_api_init); | 1386 | module_init(zcrypt_api_init); |
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 7a32c4bc8ef9..89632919c993 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * zcrypt 2.1.0 | 2 | * zcrypt 2.1.0 |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2001, 2006 | 4 | * Copyright IBM Corp. 2001, 2012 |
| 5 | * Author(s): Robert Burroughs | 5 | * Author(s): Robert Burroughs |
| 6 | * Eric Rossman (edrossma@us.ibm.com) | 6 | * Eric Rossman (edrossma@us.ibm.com) |
| 7 | * Cornelia Huck <cornelia.huck@de.ibm.com> | 7 | * Cornelia Huck <cornelia.huck@de.ibm.com> |
| @@ -9,6 +9,7 @@ | |||
| 9 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | 9 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) |
| 10 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | 10 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 11 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | 11 | * Ralph Wuerthner <rwuerthn@de.ibm.com> |
| 12 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 12 | * | 13 | * |
| 13 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
| 14 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
| @@ -28,8 +29,10 @@ | |||
| 28 | #ifndef _ZCRYPT_API_H_ | 29 | #ifndef _ZCRYPT_API_H_ |
| 29 | #define _ZCRYPT_API_H_ | 30 | #define _ZCRYPT_API_H_ |
| 30 | 31 | ||
| 31 | #include "ap_bus.h" | 32 | #include <linux/atomic.h> |
| 33 | #include <asm/debug.h> | ||
| 32 | #include <asm/zcrypt.h> | 34 | #include <asm/zcrypt.h> |
| 35 | #include "ap_bus.h" | ||
| 33 | 36 | ||
| 34 | /* deprecated status calls */ | 37 | /* deprecated status calls */ |
| 35 | #define ICAZ90STATUS _IOR(ZCRYPT_IOCTL_MAGIC, 0x10, struct ica_z90_status) | 38 | #define ICAZ90STATUS _IOR(ZCRYPT_IOCTL_MAGIC, 0x10, struct ica_z90_status) |
| @@ -87,6 +90,9 @@ struct zcrypt_ops { | |||
| 87 | struct ica_rsa_modexpo_crt *); | 90 | struct ica_rsa_modexpo_crt *); |
| 88 | long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *); | 91 | long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *); |
| 89 | long (*rng)(struct zcrypt_device *, char *); | 92 | long (*rng)(struct zcrypt_device *, char *); |
| 93 | struct list_head list; /* zcrypt ops list. */ | ||
| 94 | struct module *owner; | ||
| 95 | int variant; | ||
| 90 | }; | 96 | }; |
| 91 | 97 | ||
| 92 | struct zcrypt_device { | 98 | struct zcrypt_device { |
| @@ -108,14 +114,23 @@ struct zcrypt_device { | |||
| 108 | 114 | ||
| 109 | struct ap_message reply; /* Per-device reply structure. */ | 115 | struct ap_message reply; /* Per-device reply structure. */ |
| 110 | int max_exp_bit_length; | 116 | int max_exp_bit_length; |
| 117 | |||
| 118 | debug_info_t *dbf_area; /* debugging */ | ||
| 111 | }; | 119 | }; |
| 112 | 120 | ||
| 121 | /* transport layer rescanning */ | ||
| 122 | extern atomic_t zcrypt_rescan_req; | ||
| 123 | |||
| 113 | struct zcrypt_device *zcrypt_device_alloc(size_t); | 124 | struct zcrypt_device *zcrypt_device_alloc(size_t); |
| 114 | void zcrypt_device_free(struct zcrypt_device *); | 125 | void zcrypt_device_free(struct zcrypt_device *); |
| 115 | void zcrypt_device_get(struct zcrypt_device *); | 126 | void zcrypt_device_get(struct zcrypt_device *); |
| 116 | int zcrypt_device_put(struct zcrypt_device *); | 127 | int zcrypt_device_put(struct zcrypt_device *); |
| 117 | int zcrypt_device_register(struct zcrypt_device *); | 128 | int zcrypt_device_register(struct zcrypt_device *); |
| 118 | void zcrypt_device_unregister(struct zcrypt_device *); | 129 | void zcrypt_device_unregister(struct zcrypt_device *); |
| 130 | void zcrypt_msgtype_register(struct zcrypt_ops *); | ||
| 131 | void zcrypt_msgtype_unregister(struct zcrypt_ops *); | ||
| 132 | struct zcrypt_ops *zcrypt_msgtype_request(unsigned char *, int); | ||
| 133 | void zcrypt_msgtype_release(struct zcrypt_ops *); | ||
| 119 | int zcrypt_api_init(void); | 134 | int zcrypt_api_init(void); |
| 120 | void zcrypt_api_exit(void); | 135 | void zcrypt_api_exit(void); |
| 121 | 136 | ||
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index 744c668f586c..1e849d6e1dfe 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c | |||
| @@ -1,13 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * zcrypt 2.1.0 | 2 | * zcrypt 2.1.0 |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2001, 2006 | 4 | * Copyright IBM Corp. 2001, 2012 |
| 5 | * Author(s): Robert Burroughs | 5 | * Author(s): Robert Burroughs |
| 6 | * Eric Rossman (edrossma@us.ibm.com) | 6 | * Eric Rossman (edrossma@us.ibm.com) |
| 7 | * | 7 | * |
| 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) |
| 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 10 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | 10 | * Ralph Wuerthner <rwuerthn@de.ibm.com> |
| 11 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 11 | * | 12 | * |
| 12 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
| 13 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
| @@ -35,6 +36,7 @@ | |||
| 35 | #include "zcrypt_api.h" | 36 | #include "zcrypt_api.h" |
| 36 | #include "zcrypt_error.h" | 37 | #include "zcrypt_error.h" |
| 37 | #include "zcrypt_cex2a.h" | 38 | #include "zcrypt_cex2a.h" |
| 39 | #include "zcrypt_msgtype50.h" | ||
| 38 | 40 | ||
| 39 | #define CEX2A_MIN_MOD_SIZE 1 /* 8 bits */ | 41 | #define CEX2A_MIN_MOD_SIZE 1 /* 8 bits */ |
| 40 | #define CEX2A_MAX_MOD_SIZE 256 /* 2048 bits */ | 42 | #define CEX2A_MAX_MOD_SIZE 256 /* 2048 bits */ |
| @@ -63,14 +65,12 @@ static struct ap_device_id zcrypt_cex2a_ids[] = { | |||
| 63 | 65 | ||
| 64 | MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_ids); | 66 | MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_ids); |
| 65 | MODULE_AUTHOR("IBM Corporation"); | 67 | MODULE_AUTHOR("IBM Corporation"); |
| 66 | MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, " | 68 | MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, " \ |
| 67 | "Copyright IBM Corp. 2001, 2006"); | 69 | "Copyright IBM Corp. 2001, 2012"); |
| 68 | MODULE_LICENSE("GPL"); | 70 | MODULE_LICENSE("GPL"); |
| 69 | 71 | ||
| 70 | static int zcrypt_cex2a_probe(struct ap_device *ap_dev); | 72 | static int zcrypt_cex2a_probe(struct ap_device *ap_dev); |
| 71 | static void zcrypt_cex2a_remove(struct ap_device *ap_dev); | 73 | static void zcrypt_cex2a_remove(struct ap_device *ap_dev); |
| 72 | static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *, | ||
| 73 | struct ap_message *); | ||
| 74 | 74 | ||
| 75 | static struct ap_driver zcrypt_cex2a_driver = { | 75 | static struct ap_driver zcrypt_cex2a_driver = { |
| 76 | .probe = zcrypt_cex2a_probe, | 76 | .probe = zcrypt_cex2a_probe, |
| @@ -80,344 +80,6 @@ static struct ap_driver zcrypt_cex2a_driver = { | |||
| 80 | }; | 80 | }; |
| 81 | 81 | ||
| 82 | /** | 82 | /** |
| 83 | * Convert a ICAMEX message to a type50 MEX message. | ||
| 84 | * | ||
| 85 | * @zdev: crypto device pointer | ||
| 86 | * @zreq: crypto request pointer | ||
| 87 | * @mex: pointer to user input data | ||
| 88 | * | ||
| 89 | * Returns 0 on success or -EFAULT. | ||
| 90 | */ | ||
| 91 | static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev, | ||
| 92 | struct ap_message *ap_msg, | ||
| 93 | struct ica_rsa_modexpo *mex) | ||
| 94 | { | ||
| 95 | unsigned char *mod, *exp, *inp; | ||
| 96 | int mod_len; | ||
| 97 | |||
| 98 | mod_len = mex->inputdatalength; | ||
| 99 | |||
| 100 | if (mod_len <= 128) { | ||
| 101 | struct type50_meb1_msg *meb1 = ap_msg->message; | ||
| 102 | memset(meb1, 0, sizeof(*meb1)); | ||
| 103 | ap_msg->length = sizeof(*meb1); | ||
| 104 | meb1->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 105 | meb1->header.msg_len = sizeof(*meb1); | ||
| 106 | meb1->keyblock_type = TYPE50_MEB1_FMT; | ||
| 107 | mod = meb1->modulus + sizeof(meb1->modulus) - mod_len; | ||
| 108 | exp = meb1->exponent + sizeof(meb1->exponent) - mod_len; | ||
| 109 | inp = meb1->message + sizeof(meb1->message) - mod_len; | ||
| 110 | } else if (mod_len <= 256) { | ||
| 111 | struct type50_meb2_msg *meb2 = ap_msg->message; | ||
| 112 | memset(meb2, 0, sizeof(*meb2)); | ||
| 113 | ap_msg->length = sizeof(*meb2); | ||
| 114 | meb2->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 115 | meb2->header.msg_len = sizeof(*meb2); | ||
| 116 | meb2->keyblock_type = TYPE50_MEB2_FMT; | ||
| 117 | mod = meb2->modulus + sizeof(meb2->modulus) - mod_len; | ||
| 118 | exp = meb2->exponent + sizeof(meb2->exponent) - mod_len; | ||
| 119 | inp = meb2->message + sizeof(meb2->message) - mod_len; | ||
| 120 | } else { | ||
| 121 | /* mod_len > 256 = 4096 bit RSA Key */ | ||
| 122 | struct type50_meb3_msg *meb3 = ap_msg->message; | ||
| 123 | memset(meb3, 0, sizeof(*meb3)); | ||
| 124 | ap_msg->length = sizeof(*meb3); | ||
| 125 | meb3->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 126 | meb3->header.msg_len = sizeof(*meb3); | ||
| 127 | meb3->keyblock_type = TYPE50_MEB3_FMT; | ||
| 128 | mod = meb3->modulus + sizeof(meb3->modulus) - mod_len; | ||
| 129 | exp = meb3->exponent + sizeof(meb3->exponent) - mod_len; | ||
| 130 | inp = meb3->message + sizeof(meb3->message) - mod_len; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (copy_from_user(mod, mex->n_modulus, mod_len) || | ||
| 134 | copy_from_user(exp, mex->b_key, mod_len) || | ||
| 135 | copy_from_user(inp, mex->inputdata, mod_len)) | ||
| 136 | return -EFAULT; | ||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | /** | ||
| 141 | * Convert a ICACRT message to a type50 CRT message. | ||
| 142 | * | ||
| 143 | * @zdev: crypto device pointer | ||
| 144 | * @zreq: crypto request pointer | ||
| 145 | * @crt: pointer to user input data | ||
| 146 | * | ||
| 147 | * Returns 0 on success or -EFAULT. | ||
| 148 | */ | ||
| 149 | static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, | ||
| 150 | struct ap_message *ap_msg, | ||
| 151 | struct ica_rsa_modexpo_crt *crt) | ||
| 152 | { | ||
| 153 | int mod_len, short_len, long_len, long_offset, limit; | ||
| 154 | unsigned char *p, *q, *dp, *dq, *u, *inp; | ||
| 155 | |||
| 156 | mod_len = crt->inputdatalength; | ||
| 157 | short_len = mod_len / 2; | ||
| 158 | long_len = mod_len / 2 + 8; | ||
| 159 | |||
| 160 | /* | ||
| 161 | * CEX2A cannot handle p, dp, or U > 128 bytes. | ||
| 162 | * If we have one of these, we need to do extra checking. | ||
| 163 | * For CEX3A the limit is 256 bytes. | ||
| 164 | */ | ||
| 165 | if (zdev->max_mod_size == CEX3A_MAX_MOD_SIZE) | ||
| 166 | limit = 256; | ||
| 167 | else | ||
| 168 | limit = 128; | ||
| 169 | |||
| 170 | if (long_len > limit) { | ||
| 171 | /* | ||
| 172 | * zcrypt_rsa_crt already checked for the leading | ||
| 173 | * zeroes of np_prime, bp_key and u_mult_inc. | ||
| 174 | */ | ||
| 175 | long_offset = long_len - limit; | ||
| 176 | long_len = limit; | ||
| 177 | } else | ||
| 178 | long_offset = 0; | ||
| 179 | |||
| 180 | /* | ||
| 181 | * Instead of doing extra work for p, dp, U > 64 bytes, we'll just use | ||
| 182 | * the larger message structure. | ||
| 183 | */ | ||
| 184 | if (long_len <= 64) { | ||
| 185 | struct type50_crb1_msg *crb1 = ap_msg->message; | ||
| 186 | memset(crb1, 0, sizeof(*crb1)); | ||
| 187 | ap_msg->length = sizeof(*crb1); | ||
| 188 | crb1->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 189 | crb1->header.msg_len = sizeof(*crb1); | ||
| 190 | crb1->keyblock_type = TYPE50_CRB1_FMT; | ||
| 191 | p = crb1->p + sizeof(crb1->p) - long_len; | ||
| 192 | q = crb1->q + sizeof(crb1->q) - short_len; | ||
| 193 | dp = crb1->dp + sizeof(crb1->dp) - long_len; | ||
| 194 | dq = crb1->dq + sizeof(crb1->dq) - short_len; | ||
| 195 | u = crb1->u + sizeof(crb1->u) - long_len; | ||
| 196 | inp = crb1->message + sizeof(crb1->message) - mod_len; | ||
| 197 | } else if (long_len <= 128) { | ||
| 198 | struct type50_crb2_msg *crb2 = ap_msg->message; | ||
| 199 | memset(crb2, 0, sizeof(*crb2)); | ||
| 200 | ap_msg->length = sizeof(*crb2); | ||
| 201 | crb2->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 202 | crb2->header.msg_len = sizeof(*crb2); | ||
| 203 | crb2->keyblock_type = TYPE50_CRB2_FMT; | ||
| 204 | p = crb2->p + sizeof(crb2->p) - long_len; | ||
| 205 | q = crb2->q + sizeof(crb2->q) - short_len; | ||
| 206 | dp = crb2->dp + sizeof(crb2->dp) - long_len; | ||
| 207 | dq = crb2->dq + sizeof(crb2->dq) - short_len; | ||
| 208 | u = crb2->u + sizeof(crb2->u) - long_len; | ||
| 209 | inp = crb2->message + sizeof(crb2->message) - mod_len; | ||
| 210 | } else { | ||
| 211 | /* long_len >= 256 */ | ||
| 212 | struct type50_crb3_msg *crb3 = ap_msg->message; | ||
| 213 | memset(crb3, 0, sizeof(*crb3)); | ||
| 214 | ap_msg->length = sizeof(*crb3); | ||
| 215 | crb3->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 216 | crb3->header.msg_len = sizeof(*crb3); | ||
| 217 | crb3->keyblock_type = TYPE50_CRB3_FMT; | ||
| 218 | p = crb3->p + sizeof(crb3->p) - long_len; | ||
| 219 | q = crb3->q + sizeof(crb3->q) - short_len; | ||
| 220 | dp = crb3->dp + sizeof(crb3->dp) - long_len; | ||
| 221 | dq = crb3->dq + sizeof(crb3->dq) - short_len; | ||
| 222 | u = crb3->u + sizeof(crb3->u) - long_len; | ||
| 223 | inp = crb3->message + sizeof(crb3->message) - mod_len; | ||
| 224 | } | ||
| 225 | |||
| 226 | if (copy_from_user(p, crt->np_prime + long_offset, long_len) || | ||
| 227 | copy_from_user(q, crt->nq_prime, short_len) || | ||
| 228 | copy_from_user(dp, crt->bp_key + long_offset, long_len) || | ||
| 229 | copy_from_user(dq, crt->bq_key, short_len) || | ||
| 230 | copy_from_user(u, crt->u_mult_inv + long_offset, long_len) || | ||
| 231 | copy_from_user(inp, crt->inputdata, mod_len)) | ||
| 232 | return -EFAULT; | ||
| 233 | |||
| 234 | return 0; | ||
| 235 | } | ||
| 236 | |||
| 237 | /** | ||
| 238 | * Copy results from a type 80 reply message back to user space. | ||
| 239 | * | ||
| 240 | * @zdev: crypto device pointer | ||
| 241 | * @reply: reply AP message. | ||
| 242 | * @data: pointer to user output data | ||
| 243 | * @length: size of user output data | ||
| 244 | * | ||
| 245 | * Returns 0 on success or -EFAULT. | ||
| 246 | */ | ||
| 247 | static int convert_type80(struct zcrypt_device *zdev, | ||
| 248 | struct ap_message *reply, | ||
| 249 | char __user *outputdata, | ||
| 250 | unsigned int outputdatalength) | ||
| 251 | { | ||
| 252 | struct type80_hdr *t80h = reply->message; | ||
| 253 | unsigned char *data; | ||
| 254 | |||
| 255 | if (t80h->len < sizeof(*t80h) + outputdatalength) { | ||
| 256 | /* The result is too short, the CEX2A card may not do that.. */ | ||
| 257 | zdev->online = 0; | ||
| 258 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 259 | } | ||
| 260 | if (zdev->user_space_type == ZCRYPT_CEX2A) | ||
| 261 | BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE); | ||
| 262 | else | ||
| 263 | BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE); | ||
| 264 | data = reply->message + t80h->len - outputdatalength; | ||
| 265 | if (copy_to_user(outputdata, data, outputdatalength)) | ||
| 266 | return -EFAULT; | ||
| 267 | return 0; | ||
| 268 | } | ||
| 269 | |||
| 270 | static int convert_response(struct zcrypt_device *zdev, | ||
| 271 | struct ap_message *reply, | ||
| 272 | char __user *outputdata, | ||
| 273 | unsigned int outputdatalength) | ||
| 274 | { | ||
| 275 | /* Response type byte is the second byte in the response. */ | ||
| 276 | switch (((unsigned char *) reply->message)[1]) { | ||
| 277 | case TYPE82_RSP_CODE: | ||
| 278 | case TYPE88_RSP_CODE: | ||
| 279 | return convert_error(zdev, reply); | ||
| 280 | case TYPE80_RSP_CODE: | ||
| 281 | return convert_type80(zdev, reply, | ||
| 282 | outputdata, outputdatalength); | ||
| 283 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 284 | zdev->online = 0; | ||
| 285 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | /** | ||
| 290 | * This function is called from the AP bus code after a crypto request | ||
| 291 | * "msg" has finished with the reply message "reply". | ||
| 292 | * It is called from tasklet context. | ||
| 293 | * @ap_dev: pointer to the AP device | ||
| 294 | * @msg: pointer to the AP message | ||
| 295 | * @reply: pointer to the AP reply message | ||
| 296 | */ | ||
| 297 | static void zcrypt_cex2a_receive(struct ap_device *ap_dev, | ||
| 298 | struct ap_message *msg, | ||
| 299 | struct ap_message *reply) | ||
| 300 | { | ||
| 301 | static struct error_hdr error_reply = { | ||
| 302 | .type = TYPE82_RSP_CODE, | ||
| 303 | .reply_code = REP82_ERROR_MACHINE_FAILURE, | ||
| 304 | }; | ||
| 305 | struct type80_hdr *t80h; | ||
| 306 | int length; | ||
| 307 | |||
| 308 | /* Copy the reply message to the request message buffer. */ | ||
| 309 | if (IS_ERR(reply)) { | ||
| 310 | memcpy(msg->message, &error_reply, sizeof(error_reply)); | ||
| 311 | goto out; | ||
| 312 | } | ||
| 313 | t80h = reply->message; | ||
| 314 | if (t80h->type == TYPE80_RSP_CODE) { | ||
| 315 | if (ap_dev->device_type == AP_DEVICE_TYPE_CEX2A) | ||
| 316 | length = min(CEX2A_MAX_RESPONSE_SIZE, (int) t80h->len); | ||
| 317 | else | ||
| 318 | length = min(CEX3A_MAX_RESPONSE_SIZE, (int) t80h->len); | ||
| 319 | memcpy(msg->message, reply->message, length); | ||
| 320 | } else | ||
| 321 | memcpy(msg->message, reply->message, sizeof error_reply); | ||
| 322 | out: | ||
| 323 | complete((struct completion *) msg->private); | ||
| 324 | } | ||
| 325 | |||
| 326 | static atomic_t zcrypt_step = ATOMIC_INIT(0); | ||
| 327 | |||
| 328 | /** | ||
| 329 | * The request distributor calls this function if it picked the CEX2A | ||
| 330 | * device to handle a modexpo request. | ||
| 331 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 332 | * CEX2A device to the request distributor | ||
| 333 | * @mex: pointer to the modexpo request buffer | ||
| 334 | */ | ||
| 335 | static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev, | ||
| 336 | struct ica_rsa_modexpo *mex) | ||
| 337 | { | ||
| 338 | struct ap_message ap_msg; | ||
| 339 | struct completion work; | ||
| 340 | int rc; | ||
| 341 | |||
| 342 | ap_init_message(&ap_msg); | ||
| 343 | if (zdev->user_space_type == ZCRYPT_CEX2A) | ||
| 344 | ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL); | ||
| 345 | else | ||
| 346 | ap_msg.message = kmalloc(CEX3A_MAX_MESSAGE_SIZE, GFP_KERNEL); | ||
| 347 | if (!ap_msg.message) | ||
| 348 | return -ENOMEM; | ||
| 349 | ap_msg.receive = zcrypt_cex2a_receive; | ||
| 350 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 351 | atomic_inc_return(&zcrypt_step); | ||
| 352 | ap_msg.private = &work; | ||
| 353 | rc = ICAMEX_msg_to_type50MEX_msg(zdev, &ap_msg, mex); | ||
| 354 | if (rc) | ||
| 355 | goto out_free; | ||
| 356 | init_completion(&work); | ||
| 357 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 358 | rc = wait_for_completion_interruptible(&work); | ||
| 359 | if (rc == 0) | ||
| 360 | rc = convert_response(zdev, &ap_msg, mex->outputdata, | ||
| 361 | mex->outputdatalength); | ||
| 362 | else | ||
| 363 | /* Signal pending. */ | ||
| 364 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 365 | out_free: | ||
| 366 | kfree(ap_msg.message); | ||
| 367 | return rc; | ||
| 368 | } | ||
| 369 | |||
| 370 | /** | ||
| 371 | * The request distributor calls this function if it picked the CEX2A | ||
| 372 | * device to handle a modexpo_crt request. | ||
| 373 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 374 | * CEX2A device to the request distributor | ||
| 375 | * @crt: pointer to the modexpoc_crt request buffer | ||
| 376 | */ | ||
| 377 | static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev, | ||
| 378 | struct ica_rsa_modexpo_crt *crt) | ||
| 379 | { | ||
| 380 | struct ap_message ap_msg; | ||
| 381 | struct completion work; | ||
| 382 | int rc; | ||
| 383 | |||
| 384 | ap_init_message(&ap_msg); | ||
| 385 | if (zdev->user_space_type == ZCRYPT_CEX2A) | ||
| 386 | ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL); | ||
| 387 | else | ||
| 388 | ap_msg.message = kmalloc(CEX3A_MAX_MESSAGE_SIZE, GFP_KERNEL); | ||
| 389 | if (!ap_msg.message) | ||
| 390 | return -ENOMEM; | ||
| 391 | ap_msg.receive = zcrypt_cex2a_receive; | ||
| 392 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 393 | atomic_inc_return(&zcrypt_step); | ||
| 394 | ap_msg.private = &work; | ||
| 395 | rc = ICACRT_msg_to_type50CRT_msg(zdev, &ap_msg, crt); | ||
| 396 | if (rc) | ||
| 397 | goto out_free; | ||
| 398 | init_completion(&work); | ||
| 399 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 400 | rc = wait_for_completion_interruptible(&work); | ||
| 401 | if (rc == 0) | ||
| 402 | rc = convert_response(zdev, &ap_msg, crt->outputdata, | ||
| 403 | crt->outputdatalength); | ||
| 404 | else | ||
| 405 | /* Signal pending. */ | ||
| 406 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 407 | out_free: | ||
| 408 | kfree(ap_msg.message); | ||
| 409 | return rc; | ||
| 410 | } | ||
| 411 | |||
| 412 | /** | ||
| 413 | * The crypto operations for a CEX2A card. | ||
| 414 | */ | ||
| 415 | static struct zcrypt_ops zcrypt_cex2a_ops = { | ||
| 416 | .rsa_modexpo = zcrypt_cex2a_modexpo, | ||
| 417 | .rsa_modexpo_crt = zcrypt_cex2a_modexpo_crt, | ||
| 418 | }; | ||
| 419 | |||
| 420 | /** | ||
| 421 | * Probe function for CEX2A cards. It always accepts the AP device | 83 | * Probe function for CEX2A cards. It always accepts the AP device |
| 422 | * since the bus_match already checked the hardware type. | 84 | * since the bus_match already checked the hardware type. |
| 423 | * @ap_dev: pointer to the AP device. | 85 | * @ap_dev: pointer to the AP device. |
| @@ -449,7 +111,8 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) | |||
| 449 | zdev->min_mod_size = CEX2A_MIN_MOD_SIZE; | 111 | zdev->min_mod_size = CEX2A_MIN_MOD_SIZE; |
| 450 | zdev->max_mod_size = CEX2A_MAX_MOD_SIZE; | 112 | zdev->max_mod_size = CEX2A_MAX_MOD_SIZE; |
| 451 | zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; | 113 | zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; |
| 452 | if (ap_4096_commands_available(ap_dev->qid)) { | 114 | if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) && |
| 115 | ap_test_bit(&ap_dev->functions, AP_FUNC_CRT4K)) { | ||
| 453 | zdev->max_mod_size = CEX3A_MAX_MOD_SIZE; | 116 | zdev->max_mod_size = CEX3A_MAX_MOD_SIZE; |
| 454 | zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE; | 117 | zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE; |
| 455 | } | 118 | } |
| @@ -457,16 +120,18 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) | |||
| 457 | zdev->speed_rating = CEX3A_SPEED_RATING; | 120 | zdev->speed_rating = CEX3A_SPEED_RATING; |
| 458 | break; | 121 | break; |
| 459 | } | 122 | } |
| 460 | if (zdev != NULL) { | 123 | if (!zdev) |
| 461 | zdev->ap_dev = ap_dev; | 124 | return -ENODEV; |
| 462 | zdev->ops = &zcrypt_cex2a_ops; | 125 | zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME, |
| 463 | zdev->online = 1; | 126 | MSGTYPE50_VARIANT_DEFAULT); |
| 464 | ap_dev->reply = &zdev->reply; | 127 | zdev->ap_dev = ap_dev; |
| 465 | ap_dev->private = zdev; | 128 | zdev->online = 1; |
| 466 | rc = zcrypt_device_register(zdev); | 129 | ap_dev->reply = &zdev->reply; |
| 467 | } | 130 | ap_dev->private = zdev; |
| 131 | rc = zcrypt_device_register(zdev); | ||
| 468 | if (rc) { | 132 | if (rc) { |
| 469 | ap_dev->private = NULL; | 133 | ap_dev->private = NULL; |
| 134 | zcrypt_msgtype_release(zdev->ops); | ||
| 470 | zcrypt_device_free(zdev); | 135 | zcrypt_device_free(zdev); |
| 471 | } | 136 | } |
| 472 | return rc; | 137 | return rc; |
| @@ -479,8 +144,10 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) | |||
| 479 | static void zcrypt_cex2a_remove(struct ap_device *ap_dev) | 144 | static void zcrypt_cex2a_remove(struct ap_device *ap_dev) |
| 480 | { | 145 | { |
| 481 | struct zcrypt_device *zdev = ap_dev->private; | 146 | struct zcrypt_device *zdev = ap_dev->private; |
| 147 | struct zcrypt_ops *zops = zdev->ops; | ||
| 482 | 148 | ||
| 483 | zcrypt_device_unregister(zdev); | 149 | zcrypt_device_unregister(zdev); |
| 150 | zcrypt_msgtype_release(zops); | ||
| 484 | } | 151 | } |
| 485 | 152 | ||
| 486 | int __init zcrypt_cex2a_init(void) | 153 | int __init zcrypt_cex2a_init(void) |
diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c new file mode 100644 index 000000000000..ce1226398ac9 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_cex4.c | |||
| @@ -0,0 +1,149 @@ | |||
| 1 | /* | ||
| 2 | * Copyright IBM Corp. 2012 | ||
| 3 | * Author(s): Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/module.h> | ||
| 7 | #include <linux/slab.h> | ||
| 8 | #include <linux/init.h> | ||
| 9 | #include <linux/err.h> | ||
| 10 | #include <linux/atomic.h> | ||
| 11 | #include <linux/uaccess.h> | ||
| 12 | |||
| 13 | #include "ap_bus.h" | ||
| 14 | #include "zcrypt_api.h" | ||
| 15 | #include "zcrypt_msgtype6.h" | ||
| 16 | #include "zcrypt_msgtype50.h" | ||
| 17 | #include "zcrypt_error.h" | ||
| 18 | #include "zcrypt_cex4.h" | ||
| 19 | |||
| 20 | #define CEX4A_MIN_MOD_SIZE 1 /* 8 bits */ | ||
| 21 | #define CEX4A_MAX_MOD_SIZE_2K 256 /* 2048 bits */ | ||
| 22 | #define CEX4A_MAX_MOD_SIZE_4K 512 /* 4096 bits */ | ||
| 23 | |||
| 24 | #define CEX4C_MIN_MOD_SIZE 16 /* 256 bits */ | ||
| 25 | #define CEX4C_MAX_MOD_SIZE 512 /* 4096 bits */ | ||
| 26 | |||
| 27 | #define CEX4A_SPEED_RATING 900 /* TODO new card, new speed rating */ | ||
| 28 | #define CEX4C_SPEED_RATING 6500 /* TODO new card, new speed rating */ | ||
| 29 | |||
| 30 | #define CEX4A_MAX_MESSAGE_SIZE MSGTYPE50_CRB3_MAX_MSG_SIZE | ||
| 31 | #define CEX4C_MAX_MESSAGE_SIZE MSGTYPE06_MAX_MSG_SIZE | ||
| 32 | |||
| 33 | #define CEX4_CLEANUP_TIME (15*HZ) | ||
| 34 | |||
| 35 | static struct ap_device_id zcrypt_cex4_ids[] = { | ||
| 36 | { AP_DEVICE(AP_DEVICE_TYPE_CEX4) }, | ||
| 37 | { /* end of list */ }, | ||
| 38 | }; | ||
| 39 | |||
| 40 | MODULE_DEVICE_TABLE(ap, zcrypt_cex4_ids); | ||
| 41 | MODULE_AUTHOR("IBM Corporation"); | ||
| 42 | MODULE_DESCRIPTION("CEX4 Cryptographic Card device driver, " \ | ||
| 43 | "Copyright IBM Corp. 2012"); | ||
| 44 | MODULE_LICENSE("GPL"); | ||
| 45 | |||
| 46 | static int zcrypt_cex4_probe(struct ap_device *ap_dev); | ||
| 47 | static void zcrypt_cex4_remove(struct ap_device *ap_dev); | ||
| 48 | |||
| 49 | static struct ap_driver zcrypt_cex4_driver = { | ||
| 50 | .probe = zcrypt_cex4_probe, | ||
| 51 | .remove = zcrypt_cex4_remove, | ||
| 52 | .ids = zcrypt_cex4_ids, | ||
| 53 | .request_timeout = CEX4_CLEANUP_TIME, | ||
| 54 | }; | ||
| 55 | |||
| 56 | /** | ||
| 57 | * Probe function for CEX4 cards. It always accepts the AP device | ||
| 58 | * since the bus_match already checked the hardware type. | ||
| 59 | * @ap_dev: pointer to the AP device. | ||
| 60 | */ | ||
| 61 | static int zcrypt_cex4_probe(struct ap_device *ap_dev) | ||
| 62 | { | ||
| 63 | struct zcrypt_device *zdev = NULL; | ||
| 64 | int rc = 0; | ||
| 65 | |||
| 66 | switch (ap_dev->device_type) { | ||
| 67 | case AP_DEVICE_TYPE_CEX4: | ||
| 68 | if (ap_test_bit(&ap_dev->functions, AP_FUNC_ACCEL)) { | ||
| 69 | zdev = zcrypt_device_alloc(CEX4A_MAX_MESSAGE_SIZE); | ||
| 70 | if (!zdev) | ||
| 71 | return -ENOMEM; | ||
| 72 | zdev->type_string = "CEX4A"; | ||
| 73 | zdev->user_space_type = ZCRYPT_CEX3A; | ||
| 74 | zdev->min_mod_size = CEX4A_MIN_MOD_SIZE; | ||
| 75 | if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) && | ||
| 76 | ap_test_bit(&ap_dev->functions, AP_FUNC_CRT4K)) { | ||
| 77 | zdev->max_mod_size = | ||
| 78 | CEX4A_MAX_MOD_SIZE_4K; | ||
| 79 | zdev->max_exp_bit_length = | ||
| 80 | CEX4A_MAX_MOD_SIZE_4K; | ||
| 81 | } else { | ||
| 82 | zdev->max_mod_size = | ||
| 83 | CEX4A_MAX_MOD_SIZE_2K; | ||
| 84 | zdev->max_exp_bit_length = | ||
| 85 | CEX4A_MAX_MOD_SIZE_2K; | ||
| 86 | } | ||
| 87 | zdev->short_crt = 1; | ||
| 88 | zdev->speed_rating = CEX4A_SPEED_RATING; | ||
| 89 | zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME, | ||
| 90 | MSGTYPE50_VARIANT_DEFAULT); | ||
| 91 | } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_COPRO)) { | ||
| 92 | zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE); | ||
| 93 | if (!zdev) | ||
| 94 | return -ENOMEM; | ||
| 95 | zdev->type_string = "CEX4C"; | ||
| 96 | zdev->user_space_type = ZCRYPT_CEX3C; | ||
| 97 | zdev->min_mod_size = CEX4C_MIN_MOD_SIZE; | ||
| 98 | zdev->max_mod_size = CEX4C_MAX_MOD_SIZE; | ||
| 99 | zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; | ||
| 100 | zdev->short_crt = 0; | ||
| 101 | zdev->speed_rating = CEX4C_SPEED_RATING; | ||
| 102 | zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, | ||
| 103 | MSGTYPE06_VARIANT_DEFAULT); | ||
| 104 | } | ||
| 105 | break; | ||
| 106 | } | ||
| 107 | if (!zdev) | ||
| 108 | return -ENODEV; | ||
| 109 | zdev->ap_dev = ap_dev; | ||
| 110 | zdev->online = 1; | ||
| 111 | ap_dev->reply = &zdev->reply; | ||
| 112 | ap_dev->private = zdev; | ||
| 113 | rc = zcrypt_device_register(zdev); | ||
| 114 | if (rc) { | ||
| 115 | zcrypt_msgtype_release(zdev->ops); | ||
| 116 | ap_dev->private = NULL; | ||
| 117 | zcrypt_device_free(zdev); | ||
| 118 | } | ||
| 119 | return rc; | ||
| 120 | } | ||
| 121 | |||
| 122 | /** | ||
| 123 | * This is called to remove the extended CEX4 driver information | ||
| 124 | * if an AP device is removed. | ||
| 125 | */ | ||
| 126 | static void zcrypt_cex4_remove(struct ap_device *ap_dev) | ||
| 127 | { | ||
| 128 | struct zcrypt_device *zdev = ap_dev->private; | ||
| 129 | struct zcrypt_ops *zops; | ||
| 130 | |||
| 131 | if (zdev) { | ||
| 132 | zops = zdev->ops; | ||
| 133 | zcrypt_device_unregister(zdev); | ||
| 134 | zcrypt_msgtype_release(zops); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | int __init zcrypt_cex4_init(void) | ||
| 139 | { | ||
| 140 | return ap_driver_register(&zcrypt_cex4_driver, THIS_MODULE, "cex4"); | ||
| 141 | } | ||
| 142 | |||
| 143 | void __exit zcrypt_cex4_exit(void) | ||
| 144 | { | ||
| 145 | ap_driver_unregister(&zcrypt_cex4_driver); | ||
| 146 | } | ||
| 147 | |||
| 148 | module_init(zcrypt_cex4_init); | ||
| 149 | module_exit(zcrypt_cex4_exit); | ||
diff --git a/drivers/s390/crypto/zcrypt_cex4.h b/drivers/s390/crypto/zcrypt_cex4.h new file mode 100644 index 000000000000..719571375ccc --- /dev/null +++ b/drivers/s390/crypto/zcrypt_cex4.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | /* | ||
| 2 | * Copyright IBM Corp. 2012 | ||
| 3 | * Author(s): Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef _ZCRYPT_CEX4_H_ | ||
| 7 | #define _ZCRYPT_CEX4_H_ | ||
| 8 | |||
| 9 | int zcrypt_cex4_init(void); | ||
| 10 | void zcrypt_cex4_exit(void); | ||
| 11 | |||
| 12 | #endif /* _ZCRYPT_CEX4_H_ */ | ||
diff --git a/drivers/s390/crypto/zcrypt_debug.h b/drivers/s390/crypto/zcrypt_debug.h new file mode 100644 index 000000000000..841ea72e4a4e --- /dev/null +++ b/drivers/s390/crypto/zcrypt_debug.h | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | /* | ||
| 2 | * Copyright IBM Corp. 2012 | ||
| 3 | * Author(s): Holger Dengler (hd@linux.vnet.ibm.com) | ||
| 4 | */ | ||
| 5 | #ifndef ZCRYPT_DEBUG_H | ||
| 6 | #define ZCRYPT_DEBUG_H | ||
| 7 | |||
| 8 | #include <asm/debug.h> | ||
| 9 | #include "zcrypt_api.h" | ||
| 10 | |||
| 11 | /* that gives us 15 characters in the text event views */ | ||
| 12 | #define ZCRYPT_DBF_LEN 16 | ||
| 13 | |||
| 14 | /* sort out low debug levels early to avoid wasted sprints */ | ||
| 15 | static inline int zcrypt_dbf_passes(debug_info_t *dbf_grp, int level) | ||
| 16 | { | ||
| 17 | return (level <= dbf_grp->level); | ||
| 18 | } | ||
| 19 | |||
| 20 | #define DBF_ERR 3 /* error conditions */ | ||
| 21 | #define DBF_WARN 4 /* warning conditions */ | ||
| 22 | #define DBF_INFO 6 /* informational */ | ||
| 23 | |||
| 24 | #define RC2WARN(rc) ((rc) ? DBF_WARN : DBF_INFO) | ||
| 25 | |||
| 26 | #define ZCRYPT_DBF_COMMON(level, text...) \ | ||
| 27 | do { \ | ||
| 28 | if (zcrypt_dbf_passes(zcrypt_dbf_common, level)) { \ | ||
| 29 | char debug_buffer[ZCRYPT_DBF_LEN]; \ | ||
| 30 | snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \ | ||
| 31 | debug_text_event(zcrypt_dbf_common, level, \ | ||
| 32 | debug_buffer); \ | ||
| 33 | } \ | ||
| 34 | } while (0) | ||
| 35 | |||
| 36 | #define ZCRYPT_DBF_DEVICES(level, text...) \ | ||
| 37 | do { \ | ||
| 38 | if (zcrypt_dbf_passes(zcrypt_dbf_devices, level)) { \ | ||
| 39 | char debug_buffer[ZCRYPT_DBF_LEN]; \ | ||
| 40 | snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \ | ||
| 41 | debug_text_event(zcrypt_dbf_devices, level, \ | ||
| 42 | debug_buffer); \ | ||
| 43 | } \ | ||
| 44 | } while (0) | ||
| 45 | |||
| 46 | #define ZCRYPT_DBF_DEV(level, device, text...) \ | ||
| 47 | do { \ | ||
| 48 | if (zcrypt_dbf_passes(device->dbf_area, level)) { \ | ||
| 49 | char debug_buffer[ZCRYPT_DBF_LEN]; \ | ||
| 50 | snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \ | ||
| 51 | debug_text_event(device->dbf_area, level, \ | ||
| 52 | debug_buffer); \ | ||
| 53 | } \ | ||
| 54 | } while (0) | ||
| 55 | |||
| 56 | int zcrypt_debug_init(void); | ||
| 57 | void zcrypt_debug_exit(void); | ||
| 58 | |||
| 59 | #endif /* ZCRYPT_DEBUG_H */ | ||
diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h index 0965e2626d18..0079b6617211 100644 --- a/drivers/s390/crypto/zcrypt_error.h +++ b/drivers/s390/crypto/zcrypt_error.h | |||
| @@ -26,6 +26,8 @@ | |||
| 26 | #ifndef _ZCRYPT_ERROR_H_ | 26 | #ifndef _ZCRYPT_ERROR_H_ |
| 27 | #define _ZCRYPT_ERROR_H_ | 27 | #define _ZCRYPT_ERROR_H_ |
| 28 | 28 | ||
| 29 | #include <linux/atomic.h> | ||
| 30 | #include "zcrypt_debug.h" | ||
| 29 | #include "zcrypt_api.h" | 31 | #include "zcrypt_api.h" |
| 30 | 32 | ||
| 31 | /** | 33 | /** |
| @@ -108,16 +110,27 @@ static inline int convert_error(struct zcrypt_device *zdev, | |||
| 108 | * and then repeat the request. | 110 | * and then repeat the request. |
| 109 | */ | 111 | */ |
| 110 | WARN_ON(1); | 112 | WARN_ON(1); |
| 113 | atomic_set(&zcrypt_rescan_req, 1); | ||
| 111 | zdev->online = 0; | 114 | zdev->online = 0; |
| 115 | ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", | ||
| 116 | zdev->ap_dev->qid, | ||
| 117 | zdev->online, ehdr->reply_code); | ||
| 112 | return -EAGAIN; | 118 | return -EAGAIN; |
| 113 | case REP82_ERROR_TRANSPORT_FAIL: | 119 | case REP82_ERROR_TRANSPORT_FAIL: |
| 114 | case REP82_ERROR_MACHINE_FAILURE: | 120 | case REP82_ERROR_MACHINE_FAILURE: |
| 115 | // REP88_ERROR_MODULE_FAILURE // '10' CEX2A | 121 | // REP88_ERROR_MODULE_FAILURE // '10' CEX2A |
| 116 | /* If a card fails disable it and repeat the request. */ | 122 | /* If a card fails disable it and repeat the request. */ |
| 123 | atomic_set(&zcrypt_rescan_req, 1); | ||
| 117 | zdev->online = 0; | 124 | zdev->online = 0; |
| 125 | ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", | ||
| 126 | zdev->ap_dev->qid, | ||
| 127 | zdev->online, ehdr->reply_code); | ||
| 118 | return -EAGAIN; | 128 | return -EAGAIN; |
| 119 | default: | 129 | default: |
| 120 | zdev->online = 0; | 130 | zdev->online = 0; |
| 131 | ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", | ||
| 132 | zdev->ap_dev->qid, | ||
| 133 | zdev->online, ehdr->reply_code); | ||
| 121 | return -EAGAIN; /* repeat the request on a different device. */ | 134 | return -EAGAIN; /* repeat the request on a different device. */ |
| 122 | } | 135 | } |
| 123 | } | 136 | } |
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c new file mode 100644 index 000000000000..035b6dc31b71 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_msgtype50.c | |||
| @@ -0,0 +1,531 @@ | |||
| 1 | /* | ||
| 2 | * zcrypt 2.1.0 | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2001, 2012 | ||
| 5 | * Author(s): Robert Burroughs | ||
| 6 | * Eric Rossman (edrossma@us.ibm.com) | ||
| 7 | * | ||
| 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | ||
| 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 10 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | ||
| 11 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or modify | ||
| 14 | * it under the terms of the GNU General Public License as published by | ||
| 15 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 16 | * any later version. | ||
| 17 | * | ||
| 18 | * This program is distributed in the hope that it will be useful, | ||
| 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 21 | * GNU General Public License for more details. | ||
| 22 | * | ||
| 23 | * You should have received a copy of the GNU General Public License | ||
| 24 | * along with this program; if not, write to the Free Software | ||
| 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/slab.h> | ||
| 30 | #include <linux/init.h> | ||
| 31 | #include <linux/err.h> | ||
| 32 | #include <linux/atomic.h> | ||
| 33 | #include <linux/uaccess.h> | ||
| 34 | |||
| 35 | #include "ap_bus.h" | ||
| 36 | #include "zcrypt_api.h" | ||
| 37 | #include "zcrypt_error.h" | ||
| 38 | #include "zcrypt_msgtype50.h" | ||
| 39 | |||
| 40 | #define CEX3A_MAX_MOD_SIZE 512 /* 4096 bits */ | ||
| 41 | |||
| 42 | #define CEX2A_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */ | ||
| 43 | |||
| 44 | #define CEX3A_MAX_RESPONSE_SIZE 0x210 /* 512 bit modulus | ||
| 45 | * (max outputdatalength) + | ||
| 46 | * type80_hdr*/ | ||
| 47 | |||
| 48 | MODULE_AUTHOR("IBM Corporation"); | ||
| 49 | MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \ | ||
| 50 | "Copyright IBM Corp. 2001, 2012"); | ||
| 51 | MODULE_LICENSE("GPL"); | ||
| 52 | |||
| 53 | static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *, | ||
| 54 | struct ap_message *); | ||
| 55 | |||
| 56 | /** | ||
| 57 | * The type 50 message family is associated with a CEX2A card. | ||
| 58 | * | ||
| 59 | * The four members of the family are described below. | ||
| 60 | * | ||
| 61 | * Note that all unsigned char arrays are right-justified and left-padded | ||
| 62 | * with zeroes. | ||
| 63 | * | ||
| 64 | * Note that all reserved fields must be zeroes. | ||
| 65 | */ | ||
| 66 | struct type50_hdr { | ||
| 67 | unsigned char reserved1; | ||
| 68 | unsigned char msg_type_code; /* 0x50 */ | ||
| 69 | unsigned short msg_len; | ||
| 70 | unsigned char reserved2; | ||
| 71 | unsigned char ignored; | ||
| 72 | unsigned short reserved3; | ||
| 73 | } __packed; | ||
| 74 | |||
| 75 | #define TYPE50_TYPE_CODE 0x50 | ||
| 76 | |||
| 77 | #define TYPE50_MEB1_FMT 0x0001 | ||
| 78 | #define TYPE50_MEB2_FMT 0x0002 | ||
| 79 | #define TYPE50_MEB3_FMT 0x0003 | ||
| 80 | #define TYPE50_CRB1_FMT 0x0011 | ||
| 81 | #define TYPE50_CRB2_FMT 0x0012 | ||
| 82 | #define TYPE50_CRB3_FMT 0x0013 | ||
| 83 | |||
| 84 | /* Mod-Exp, with a small modulus */ | ||
| 85 | struct type50_meb1_msg { | ||
| 86 | struct type50_hdr header; | ||
| 87 | unsigned short keyblock_type; /* 0x0001 */ | ||
| 88 | unsigned char reserved[6]; | ||
| 89 | unsigned char exponent[128]; | ||
| 90 | unsigned char modulus[128]; | ||
| 91 | unsigned char message[128]; | ||
| 92 | } __packed; | ||
| 93 | |||
| 94 | /* Mod-Exp, with a large modulus */ | ||
| 95 | struct type50_meb2_msg { | ||
| 96 | struct type50_hdr header; | ||
| 97 | unsigned short keyblock_type; /* 0x0002 */ | ||
| 98 | unsigned char reserved[6]; | ||
| 99 | unsigned char exponent[256]; | ||
| 100 | unsigned char modulus[256]; | ||
| 101 | unsigned char message[256]; | ||
| 102 | } __packed; | ||
| 103 | |||
| 104 | /* Mod-Exp, with a larger modulus */ | ||
| 105 | struct type50_meb3_msg { | ||
| 106 | struct type50_hdr header; | ||
| 107 | unsigned short keyblock_type; /* 0x0003 */ | ||
| 108 | unsigned char reserved[6]; | ||
| 109 | unsigned char exponent[512]; | ||
| 110 | unsigned char modulus[512]; | ||
| 111 | unsigned char message[512]; | ||
| 112 | } __packed; | ||
| 113 | |||
| 114 | /* CRT, with a small modulus */ | ||
| 115 | struct type50_crb1_msg { | ||
| 116 | struct type50_hdr header; | ||
| 117 | unsigned short keyblock_type; /* 0x0011 */ | ||
| 118 | unsigned char reserved[6]; | ||
| 119 | unsigned char p[64]; | ||
| 120 | unsigned char q[64]; | ||
| 121 | unsigned char dp[64]; | ||
| 122 | unsigned char dq[64]; | ||
| 123 | unsigned char u[64]; | ||
| 124 | unsigned char message[128]; | ||
| 125 | } __packed; | ||
| 126 | |||
| 127 | /* CRT, with a large modulus */ | ||
| 128 | struct type50_crb2_msg { | ||
| 129 | struct type50_hdr header; | ||
| 130 | unsigned short keyblock_type; /* 0x0012 */ | ||
| 131 | unsigned char reserved[6]; | ||
| 132 | unsigned char p[128]; | ||
| 133 | unsigned char q[128]; | ||
| 134 | unsigned char dp[128]; | ||
| 135 | unsigned char dq[128]; | ||
| 136 | unsigned char u[128]; | ||
| 137 | unsigned char message[256]; | ||
| 138 | } __packed; | ||
| 139 | |||
| 140 | /* CRT, with a larger modulus */ | ||
| 141 | struct type50_crb3_msg { | ||
| 142 | struct type50_hdr header; | ||
| 143 | unsigned short keyblock_type; /* 0x0013 */ | ||
| 144 | unsigned char reserved[6]; | ||
| 145 | unsigned char p[256]; | ||
| 146 | unsigned char q[256]; | ||
| 147 | unsigned char dp[256]; | ||
| 148 | unsigned char dq[256]; | ||
| 149 | unsigned char u[256]; | ||
| 150 | unsigned char message[512]; | ||
| 151 | } __packed; | ||
| 152 | |||
| 153 | /** | ||
| 154 | * The type 80 response family is associated with a CEX2A card. | ||
| 155 | * | ||
| 156 | * Note that all unsigned char arrays are right-justified and left-padded | ||
| 157 | * with zeroes. | ||
| 158 | * | ||
| 159 | * Note that all reserved fields must be zeroes. | ||
| 160 | */ | ||
| 161 | |||
| 162 | #define TYPE80_RSP_CODE 0x80 | ||
| 163 | |||
| 164 | struct type80_hdr { | ||
| 165 | unsigned char reserved1; | ||
| 166 | unsigned char type; /* 0x80 */ | ||
| 167 | unsigned short len; | ||
| 168 | unsigned char code; /* 0x00 */ | ||
| 169 | unsigned char reserved2[3]; | ||
| 170 | unsigned char reserved3[8]; | ||
| 171 | } __packed; | ||
| 172 | |||
| 173 | /** | ||
| 174 | * Convert a ICAMEX message to a type50 MEX message. | ||
| 175 | * | ||
| 176 | * @zdev: crypto device pointer | ||
| 177 | * @zreq: crypto request pointer | ||
| 178 | * @mex: pointer to user input data | ||
| 179 | * | ||
| 180 | * Returns 0 on success or -EFAULT. | ||
| 181 | */ | ||
| 182 | static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev, | ||
| 183 | struct ap_message *ap_msg, | ||
| 184 | struct ica_rsa_modexpo *mex) | ||
| 185 | { | ||
| 186 | unsigned char *mod, *exp, *inp; | ||
| 187 | int mod_len; | ||
| 188 | |||
| 189 | mod_len = mex->inputdatalength; | ||
| 190 | |||
| 191 | if (mod_len <= 128) { | ||
| 192 | struct type50_meb1_msg *meb1 = ap_msg->message; | ||
| 193 | memset(meb1, 0, sizeof(*meb1)); | ||
| 194 | ap_msg->length = sizeof(*meb1); | ||
| 195 | meb1->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 196 | meb1->header.msg_len = sizeof(*meb1); | ||
| 197 | meb1->keyblock_type = TYPE50_MEB1_FMT; | ||
| 198 | mod = meb1->modulus + sizeof(meb1->modulus) - mod_len; | ||
| 199 | exp = meb1->exponent + sizeof(meb1->exponent) - mod_len; | ||
| 200 | inp = meb1->message + sizeof(meb1->message) - mod_len; | ||
| 201 | } else if (mod_len <= 256) { | ||
| 202 | struct type50_meb2_msg *meb2 = ap_msg->message; | ||
| 203 | memset(meb2, 0, sizeof(*meb2)); | ||
| 204 | ap_msg->length = sizeof(*meb2); | ||
| 205 | meb2->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 206 | meb2->header.msg_len = sizeof(*meb2); | ||
| 207 | meb2->keyblock_type = TYPE50_MEB2_FMT; | ||
| 208 | mod = meb2->modulus + sizeof(meb2->modulus) - mod_len; | ||
| 209 | exp = meb2->exponent + sizeof(meb2->exponent) - mod_len; | ||
| 210 | inp = meb2->message + sizeof(meb2->message) - mod_len; | ||
| 211 | } else { | ||
| 212 | /* mod_len > 256 = 4096 bit RSA Key */ | ||
| 213 | struct type50_meb3_msg *meb3 = ap_msg->message; | ||
| 214 | memset(meb3, 0, sizeof(*meb3)); | ||
| 215 | ap_msg->length = sizeof(*meb3); | ||
| 216 | meb3->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 217 | meb3->header.msg_len = sizeof(*meb3); | ||
| 218 | meb3->keyblock_type = TYPE50_MEB3_FMT; | ||
| 219 | mod = meb3->modulus + sizeof(meb3->modulus) - mod_len; | ||
| 220 | exp = meb3->exponent + sizeof(meb3->exponent) - mod_len; | ||
| 221 | inp = meb3->message + sizeof(meb3->message) - mod_len; | ||
| 222 | } | ||
| 223 | |||
| 224 | if (copy_from_user(mod, mex->n_modulus, mod_len) || | ||
| 225 | copy_from_user(exp, mex->b_key, mod_len) || | ||
| 226 | copy_from_user(inp, mex->inputdata, mod_len)) | ||
| 227 | return -EFAULT; | ||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 231 | /** | ||
| 232 | * Convert a ICACRT message to a type50 CRT message. | ||
| 233 | * | ||
| 234 | * @zdev: crypto device pointer | ||
| 235 | * @zreq: crypto request pointer | ||
| 236 | * @crt: pointer to user input data | ||
| 237 | * | ||
| 238 | * Returns 0 on success or -EFAULT. | ||
| 239 | */ | ||
| 240 | static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, | ||
| 241 | struct ap_message *ap_msg, | ||
| 242 | struct ica_rsa_modexpo_crt *crt) | ||
| 243 | { | ||
| 244 | int mod_len, short_len, long_len, long_offset, limit; | ||
| 245 | unsigned char *p, *q, *dp, *dq, *u, *inp; | ||
| 246 | |||
| 247 | mod_len = crt->inputdatalength; | ||
| 248 | short_len = mod_len / 2; | ||
| 249 | long_len = mod_len / 2 + 8; | ||
| 250 | |||
| 251 | /* | ||
| 252 | * CEX2A cannot handle p, dp, or U > 128 bytes. | ||
| 253 | * If we have one of these, we need to do extra checking. | ||
| 254 | * For CEX3A the limit is 256 bytes. | ||
| 255 | */ | ||
| 256 | if (zdev->max_mod_size == CEX3A_MAX_MOD_SIZE) | ||
| 257 | limit = 256; | ||
| 258 | else | ||
| 259 | limit = 128; | ||
| 260 | |||
| 261 | if (long_len > limit) { | ||
| 262 | /* | ||
| 263 | * zcrypt_rsa_crt already checked for the leading | ||
| 264 | * zeroes of np_prime, bp_key and u_mult_inc. | ||
| 265 | */ | ||
| 266 | long_offset = long_len - limit; | ||
| 267 | long_len = limit; | ||
| 268 | } else | ||
| 269 | long_offset = 0; | ||
| 270 | |||
| 271 | /* | ||
| 272 | * Instead of doing extra work for p, dp, U > 64 bytes, we'll just use | ||
| 273 | * the larger message structure. | ||
| 274 | */ | ||
| 275 | if (long_len <= 64) { | ||
| 276 | struct type50_crb1_msg *crb1 = ap_msg->message; | ||
| 277 | memset(crb1, 0, sizeof(*crb1)); | ||
| 278 | ap_msg->length = sizeof(*crb1); | ||
| 279 | crb1->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 280 | crb1->header.msg_len = sizeof(*crb1); | ||
| 281 | crb1->keyblock_type = TYPE50_CRB1_FMT; | ||
| 282 | p = crb1->p + sizeof(crb1->p) - long_len; | ||
| 283 | q = crb1->q + sizeof(crb1->q) - short_len; | ||
| 284 | dp = crb1->dp + sizeof(crb1->dp) - long_len; | ||
| 285 | dq = crb1->dq + sizeof(crb1->dq) - short_len; | ||
| 286 | u = crb1->u + sizeof(crb1->u) - long_len; | ||
| 287 | inp = crb1->message + sizeof(crb1->message) - mod_len; | ||
| 288 | } else if (long_len <= 128) { | ||
| 289 | struct type50_crb2_msg *crb2 = ap_msg->message; | ||
| 290 | memset(crb2, 0, sizeof(*crb2)); | ||
| 291 | ap_msg->length = sizeof(*crb2); | ||
| 292 | crb2->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 293 | crb2->header.msg_len = sizeof(*crb2); | ||
| 294 | crb2->keyblock_type = TYPE50_CRB2_FMT; | ||
| 295 | p = crb2->p + sizeof(crb2->p) - long_len; | ||
| 296 | q = crb2->q + sizeof(crb2->q) - short_len; | ||
| 297 | dp = crb2->dp + sizeof(crb2->dp) - long_len; | ||
| 298 | dq = crb2->dq + sizeof(crb2->dq) - short_len; | ||
| 299 | u = crb2->u + sizeof(crb2->u) - long_len; | ||
| 300 | inp = crb2->message + sizeof(crb2->message) - mod_len; | ||
| 301 | } else { | ||
| 302 | /* long_len >= 256 */ | ||
| 303 | struct type50_crb3_msg *crb3 = ap_msg->message; | ||
| 304 | memset(crb3, 0, sizeof(*crb3)); | ||
| 305 | ap_msg->length = sizeof(*crb3); | ||
| 306 | crb3->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 307 | crb3->header.msg_len = sizeof(*crb3); | ||
| 308 | crb3->keyblock_type = TYPE50_CRB3_FMT; | ||
| 309 | p = crb3->p + sizeof(crb3->p) - long_len; | ||
| 310 | q = crb3->q + sizeof(crb3->q) - short_len; | ||
| 311 | dp = crb3->dp + sizeof(crb3->dp) - long_len; | ||
| 312 | dq = crb3->dq + sizeof(crb3->dq) - short_len; | ||
| 313 | u = crb3->u + sizeof(crb3->u) - long_len; | ||
| 314 | inp = crb3->message + sizeof(crb3->message) - mod_len; | ||
| 315 | } | ||
| 316 | |||
| 317 | if (copy_from_user(p, crt->np_prime + long_offset, long_len) || | ||
| 318 | copy_from_user(q, crt->nq_prime, short_len) || | ||
| 319 | copy_from_user(dp, crt->bp_key + long_offset, long_len) || | ||
| 320 | copy_from_user(dq, crt->bq_key, short_len) || | ||
| 321 | copy_from_user(u, crt->u_mult_inv + long_offset, long_len) || | ||
| 322 | copy_from_user(inp, crt->inputdata, mod_len)) | ||
| 323 | return -EFAULT; | ||
| 324 | |||
| 325 | return 0; | ||
| 326 | } | ||
| 327 | |||
| 328 | /** | ||
| 329 | * Copy results from a type 80 reply message back to user space. | ||
| 330 | * | ||
| 331 | * @zdev: crypto device pointer | ||
| 332 | * @reply: reply AP message. | ||
| 333 | * @data: pointer to user output data | ||
| 334 | * @length: size of user output data | ||
| 335 | * | ||
| 336 | * Returns 0 on success or -EFAULT. | ||
| 337 | */ | ||
| 338 | static int convert_type80(struct zcrypt_device *zdev, | ||
| 339 | struct ap_message *reply, | ||
| 340 | char __user *outputdata, | ||
| 341 | unsigned int outputdatalength) | ||
| 342 | { | ||
| 343 | struct type80_hdr *t80h = reply->message; | ||
| 344 | unsigned char *data; | ||
| 345 | |||
| 346 | if (t80h->len < sizeof(*t80h) + outputdatalength) { | ||
| 347 | /* The result is too short, the CEX2A card may not do that.. */ | ||
| 348 | zdev->online = 0; | ||
| 349 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 350 | } | ||
| 351 | if (zdev->user_space_type == ZCRYPT_CEX2A) | ||
| 352 | BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE); | ||
| 353 | else | ||
| 354 | BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE); | ||
| 355 | data = reply->message + t80h->len - outputdatalength; | ||
| 356 | if (copy_to_user(outputdata, data, outputdatalength)) | ||
| 357 | return -EFAULT; | ||
| 358 | return 0; | ||
| 359 | } | ||
| 360 | |||
| 361 | static int convert_response(struct zcrypt_device *zdev, | ||
| 362 | struct ap_message *reply, | ||
| 363 | char __user *outputdata, | ||
| 364 | unsigned int outputdatalength) | ||
| 365 | { | ||
| 366 | /* Response type byte is the second byte in the response. */ | ||
| 367 | switch (((unsigned char *) reply->message)[1]) { | ||
| 368 | case TYPE82_RSP_CODE: | ||
| 369 | case TYPE88_RSP_CODE: | ||
| 370 | return convert_error(zdev, reply); | ||
| 371 | case TYPE80_RSP_CODE: | ||
| 372 | return convert_type80(zdev, reply, | ||
| 373 | outputdata, outputdatalength); | ||
| 374 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 375 | zdev->online = 0; | ||
| 376 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 380 | /** | ||
| 381 | * This function is called from the AP bus code after a crypto request | ||
| 382 | * "msg" has finished with the reply message "reply". | ||
| 383 | * It is called from tasklet context. | ||
| 384 | * @ap_dev: pointer to the AP device | ||
| 385 | * @msg: pointer to the AP message | ||
| 386 | * @reply: pointer to the AP reply message | ||
| 387 | */ | ||
| 388 | static void zcrypt_cex2a_receive(struct ap_device *ap_dev, | ||
| 389 | struct ap_message *msg, | ||
| 390 | struct ap_message *reply) | ||
| 391 | { | ||
| 392 | static struct error_hdr error_reply = { | ||
| 393 | .type = TYPE82_RSP_CODE, | ||
| 394 | .reply_code = REP82_ERROR_MACHINE_FAILURE, | ||
| 395 | }; | ||
| 396 | struct type80_hdr *t80h; | ||
| 397 | int length; | ||
| 398 | |||
| 399 | /* Copy the reply message to the request message buffer. */ | ||
| 400 | if (IS_ERR(reply)) { | ||
| 401 | memcpy(msg->message, &error_reply, sizeof(error_reply)); | ||
| 402 | goto out; | ||
| 403 | } | ||
| 404 | t80h = reply->message; | ||
| 405 | if (t80h->type == TYPE80_RSP_CODE) { | ||
| 406 | if (ap_dev->device_type == AP_DEVICE_TYPE_CEX2A) | ||
| 407 | length = min_t(int, | ||
| 408 | CEX2A_MAX_RESPONSE_SIZE, t80h->len); | ||
| 409 | else | ||
| 410 | length = min_t(int, | ||
| 411 | CEX3A_MAX_RESPONSE_SIZE, t80h->len); | ||
| 412 | memcpy(msg->message, reply->message, length); | ||
| 413 | } else | ||
| 414 | memcpy(msg->message, reply->message, sizeof(error_reply)); | ||
| 415 | out: | ||
| 416 | complete((struct completion *) msg->private); | ||
| 417 | } | ||
| 418 | |||
| 419 | static atomic_t zcrypt_step = ATOMIC_INIT(0); | ||
| 420 | |||
| 421 | /** | ||
| 422 | * The request distributor calls this function if it picked the CEX2A | ||
| 423 | * device to handle a modexpo request. | ||
| 424 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 425 | * CEX2A device to the request distributor | ||
| 426 | * @mex: pointer to the modexpo request buffer | ||
| 427 | */ | ||
| 428 | static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev, | ||
| 429 | struct ica_rsa_modexpo *mex) | ||
| 430 | { | ||
| 431 | struct ap_message ap_msg; | ||
| 432 | struct completion work; | ||
| 433 | int rc; | ||
| 434 | |||
| 435 | ap_init_message(&ap_msg); | ||
| 436 | if (zdev->user_space_type == ZCRYPT_CEX2A) | ||
| 437 | ap_msg.message = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, | ||
| 438 | GFP_KERNEL); | ||
| 439 | else | ||
| 440 | ap_msg.message = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE, | ||
| 441 | GFP_KERNEL); | ||
| 442 | if (!ap_msg.message) | ||
| 443 | return -ENOMEM; | ||
| 444 | ap_msg.receive = zcrypt_cex2a_receive; | ||
| 445 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 446 | atomic_inc_return(&zcrypt_step); | ||
| 447 | ap_msg.private = &work; | ||
| 448 | rc = ICAMEX_msg_to_type50MEX_msg(zdev, &ap_msg, mex); | ||
| 449 | if (rc) | ||
| 450 | goto out_free; | ||
| 451 | init_completion(&work); | ||
| 452 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 453 | rc = wait_for_completion_interruptible(&work); | ||
| 454 | if (rc == 0) | ||
| 455 | rc = convert_response(zdev, &ap_msg, mex->outputdata, | ||
| 456 | mex->outputdatalength); | ||
| 457 | else | ||
| 458 | /* Signal pending. */ | ||
| 459 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 460 | out_free: | ||
| 461 | kfree(ap_msg.message); | ||
| 462 | return rc; | ||
| 463 | } | ||
| 464 | |||
| 465 | /** | ||
| 466 | * The request distributor calls this function if it picked the CEX2A | ||
| 467 | * device to handle a modexpo_crt request. | ||
| 468 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 469 | * CEX2A device to the request distributor | ||
| 470 | * @crt: pointer to the modexpoc_crt request buffer | ||
| 471 | */ | ||
| 472 | static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev, | ||
| 473 | struct ica_rsa_modexpo_crt *crt) | ||
| 474 | { | ||
| 475 | struct ap_message ap_msg; | ||
| 476 | struct completion work; | ||
| 477 | int rc; | ||
| 478 | |||
| 479 | ap_init_message(&ap_msg); | ||
| 480 | if (zdev->user_space_type == ZCRYPT_CEX2A) | ||
| 481 | ap_msg.message = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, | ||
| 482 | GFP_KERNEL); | ||
| 483 | else | ||
| 484 | ap_msg.message = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE, | ||
| 485 | GFP_KERNEL); | ||
| 486 | if (!ap_msg.message) | ||
| 487 | return -ENOMEM; | ||
| 488 | ap_msg.receive = zcrypt_cex2a_receive; | ||
| 489 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 490 | atomic_inc_return(&zcrypt_step); | ||
| 491 | ap_msg.private = &work; | ||
| 492 | rc = ICACRT_msg_to_type50CRT_msg(zdev, &ap_msg, crt); | ||
| 493 | if (rc) | ||
| 494 | goto out_free; | ||
| 495 | init_completion(&work); | ||
| 496 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 497 | rc = wait_for_completion_interruptible(&work); | ||
| 498 | if (rc == 0) | ||
| 499 | rc = convert_response(zdev, &ap_msg, crt->outputdata, | ||
| 500 | crt->outputdatalength); | ||
| 501 | else | ||
| 502 | /* Signal pending. */ | ||
| 503 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 504 | out_free: | ||
| 505 | kfree(ap_msg.message); | ||
| 506 | return rc; | ||
| 507 | } | ||
| 508 | |||
| 509 | /** | ||
| 510 | * The crypto operations for message type 50. | ||
| 511 | */ | ||
| 512 | static struct zcrypt_ops zcrypt_msgtype50_ops = { | ||
| 513 | .rsa_modexpo = zcrypt_cex2a_modexpo, | ||
| 514 | .rsa_modexpo_crt = zcrypt_cex2a_modexpo_crt, | ||
| 515 | .owner = THIS_MODULE, | ||
| 516 | .variant = MSGTYPE50_VARIANT_DEFAULT, | ||
| 517 | }; | ||
| 518 | |||
| 519 | int __init zcrypt_msgtype50_init(void) | ||
| 520 | { | ||
| 521 | zcrypt_msgtype_register(&zcrypt_msgtype50_ops); | ||
| 522 | return 0; | ||
| 523 | } | ||
| 524 | |||
| 525 | void __exit zcrypt_msgtype50_exit(void) | ||
| 526 | { | ||
| 527 | zcrypt_msgtype_unregister(&zcrypt_msgtype50_ops); | ||
| 528 | } | ||
| 529 | |||
| 530 | module_init(zcrypt_msgtype50_init); | ||
| 531 | module_exit(zcrypt_msgtype50_exit); | ||
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.h b/drivers/s390/crypto/zcrypt_msgtype50.h new file mode 100644 index 000000000000..e56dc72c7733 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_msgtype50.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | /* | ||
| 2 | * zcrypt 2.1.0 | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2001, 2012 | ||
| 5 | * Author(s): Robert Burroughs | ||
| 6 | * Eric Rossman (edrossma@us.ibm.com) | ||
| 7 | * | ||
| 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | ||
| 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 10 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License as published by | ||
| 14 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 15 | * any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 25 | */ | ||
| 26 | |||
| 27 | #ifndef _ZCRYPT_MSGTYPE50_H_ | ||
| 28 | #define _ZCRYPT_MSGTYPE50_H_ | ||
| 29 | |||
| 30 | #define MSGTYPE50_NAME "zcrypt_msgtype50" | ||
| 31 | #define MSGTYPE50_VARIANT_DEFAULT 0 | ||
| 32 | |||
| 33 | #define MSGTYPE50_CRB2_MAX_MSG_SIZE 0x390 /*sizeof(struct type50_crb2_msg)*/ | ||
| 34 | #define MSGTYPE50_CRB3_MAX_MSG_SIZE 0x710 /*sizeof(struct type50_crb3_msg)*/ | ||
| 35 | |||
| 36 | int zcrypt_msgtype50_init(void); | ||
| 37 | void zcrypt_msgtype50_exit(void); | ||
| 38 | |||
| 39 | #endif /* _ZCRYPT_MSGTYPE50_H_ */ | ||
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c new file mode 100644 index 000000000000..7d97fa5a26d0 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_msgtype6.c | |||
| @@ -0,0 +1,856 @@ | |||
| 1 | /* | ||
| 2 | * zcrypt 2.1.0 | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2001, 2012 | ||
| 5 | * Author(s): Robert Burroughs | ||
| 6 | * Eric Rossman (edrossma@us.ibm.com) | ||
| 7 | * | ||
| 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | ||
| 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 10 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | ||
| 11 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or modify | ||
| 14 | * it under the terms of the GNU General Public License as published by | ||
| 15 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 16 | * any later version. | ||
| 17 | * | ||
| 18 | * This program is distributed in the hope that it will be useful, | ||
| 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 21 | * GNU General Public License for more details. | ||
| 22 | * | ||
| 23 | * You should have received a copy of the GNU General Public License | ||
| 24 | * along with this program; if not, write to the Free Software | ||
| 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/init.h> | ||
| 30 | #include <linux/err.h> | ||
| 31 | #include <linux/delay.h> | ||
| 32 | #include <linux/slab.h> | ||
| 33 | #include <linux/atomic.h> | ||
| 34 | #include <linux/uaccess.h> | ||
| 35 | |||
| 36 | #include "ap_bus.h" | ||
| 37 | #include "zcrypt_api.h" | ||
| 38 | #include "zcrypt_error.h" | ||
| 39 | #include "zcrypt_msgtype6.h" | ||
| 40 | #include "zcrypt_cca_key.h" | ||
| 41 | |||
| 42 | #define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */ | ||
| 43 | #define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */ | ||
| 44 | |||
| 45 | #define CEIL4(x) ((((x)+3)/4)*4) | ||
| 46 | |||
| 47 | struct response_type { | ||
| 48 | struct completion work; | ||
| 49 | int type; | ||
| 50 | }; | ||
| 51 | #define PCIXCC_RESPONSE_TYPE_ICA 0 | ||
| 52 | #define PCIXCC_RESPONSE_TYPE_XCRB 1 | ||
| 53 | |||
| 54 | MODULE_AUTHOR("IBM Corporation"); | ||
| 55 | MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \ | ||
| 56 | "Copyright IBM Corp. 2001, 2012"); | ||
| 57 | MODULE_LICENSE("GPL"); | ||
| 58 | |||
| 59 | static void zcrypt_msgtype6_receive(struct ap_device *, struct ap_message *, | ||
| 60 | struct ap_message *); | ||
| 61 | |||
| 62 | /** | ||
| 63 | * CPRB | ||
| 64 | * Note that all shorts, ints and longs are little-endian. | ||
| 65 | * All pointer fields are 32-bits long, and mean nothing | ||
| 66 | * | ||
| 67 | * A request CPRB is followed by a request_parameter_block. | ||
| 68 | * | ||
| 69 | * The request (or reply) parameter block is organized thus: | ||
| 70 | * function code | ||
| 71 | * VUD block | ||
| 72 | * key block | ||
| 73 | */ | ||
| 74 | struct CPRB { | ||
| 75 | unsigned short cprb_len; /* CPRB length */ | ||
| 76 | unsigned char cprb_ver_id; /* CPRB version id. */ | ||
| 77 | unsigned char pad_000; /* Alignment pad byte. */ | ||
| 78 | unsigned char srpi_rtcode[4]; /* SRPI return code LELONG */ | ||
| 79 | unsigned char srpi_verb; /* SRPI verb type */ | ||
| 80 | unsigned char flags; /* flags */ | ||
| 81 | unsigned char func_id[2]; /* function id */ | ||
| 82 | unsigned char checkpoint_flag; /* */ | ||
| 83 | unsigned char resv2; /* reserved */ | ||
| 84 | unsigned short req_parml; /* request parameter buffer */ | ||
| 85 | /* length 16-bit little endian */ | ||
| 86 | unsigned char req_parmp[4]; /* request parameter buffer * | ||
| 87 | * pointer (means nothing: the * | ||
| 88 | * parameter buffer follows * | ||
| 89 | * the CPRB). */ | ||
| 90 | unsigned char req_datal[4]; /* request data buffer */ | ||
| 91 | /* length ULELONG */ | ||
| 92 | unsigned char req_datap[4]; /* request data buffer */ | ||
| 93 | /* pointer */ | ||
| 94 | unsigned short rpl_parml; /* reply parameter buffer */ | ||
| 95 | /* length 16-bit little endian */ | ||
| 96 | unsigned char pad_001[2]; /* Alignment pad bytes. ULESHORT */ | ||
| 97 | unsigned char rpl_parmp[4]; /* reply parameter buffer * | ||
| 98 | * pointer (means nothing: the * | ||
| 99 | * parameter buffer follows * | ||
| 100 | * the CPRB). */ | ||
| 101 | unsigned char rpl_datal[4]; /* reply data buffer len ULELONG */ | ||
| 102 | unsigned char rpl_datap[4]; /* reply data buffer */ | ||
| 103 | /* pointer */ | ||
| 104 | unsigned short ccp_rscode; /* server reason code ULESHORT */ | ||
| 105 | unsigned short ccp_rtcode; /* server return code ULESHORT */ | ||
| 106 | unsigned char repd_parml[2]; /* replied parameter len ULESHORT*/ | ||
| 107 | unsigned char mac_data_len[2]; /* Mac Data Length ULESHORT */ | ||
| 108 | unsigned char repd_datal[4]; /* replied data length ULELONG */ | ||
| 109 | unsigned char req_pc[2]; /* PC identifier */ | ||
| 110 | unsigned char res_origin[8]; /* resource origin */ | ||
| 111 | unsigned char mac_value[8]; /* Mac Value */ | ||
| 112 | unsigned char logon_id[8]; /* Logon Identifier */ | ||
| 113 | unsigned char usage_domain[2]; /* cdx */ | ||
| 114 | unsigned char resv3[18]; /* reserved for requestor */ | ||
| 115 | unsigned short svr_namel; /* server name length ULESHORT */ | ||
| 116 | unsigned char svr_name[8]; /* server name */ | ||
| 117 | } __packed; | ||
| 118 | |||
| 119 | struct function_and_rules_block { | ||
| 120 | unsigned char function_code[2]; | ||
| 121 | unsigned short ulen; | ||
| 122 | unsigned char only_rule[8]; | ||
| 123 | } __packed; | ||
| 124 | |||
| 125 | /** | ||
| 126 | * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C | ||
| 127 | * card in a type6 message. The 3 fields that must be filled in at execution | ||
| 128 | * time are req_parml, rpl_parml and usage_domain. | ||
| 129 | * Everything about this interface is ascii/big-endian, since the | ||
| 130 | * device does *not* have 'Intel inside'. | ||
| 131 | * | ||
| 132 | * The CPRBX is followed immediately by the parm block. | ||
| 133 | * The parm block contains: | ||
| 134 | * - function code ('PD' 0x5044 or 'PK' 0x504B) | ||
| 135 | * - rule block (one of:) | ||
| 136 | * + 0x000A 'PKCS-1.2' (MCL2 'PD') | ||
| 137 | * + 0x000A 'ZERO-PAD' (MCL2 'PK') | ||
| 138 | * + 0x000A 'ZERO-PAD' (MCL3 'PD' or CEX2C 'PD') | ||
| 139 | * + 0x000A 'MRP ' (MCL3 'PK' or CEX2C 'PK') | ||
| 140 | * - VUD block | ||
| 141 | */ | ||
| 142 | static struct CPRBX static_cprbx = { | ||
| 143 | .cprb_len = 0x00DC, | ||
| 144 | .cprb_ver_id = 0x02, | ||
| 145 | .func_id = {0x54, 0x32}, | ||
| 146 | }; | ||
| 147 | |||
| 148 | /** | ||
| 149 | * Convert a ICAMEX message to a type6 MEX message. | ||
| 150 | * | ||
| 151 | * @zdev: crypto device pointer | ||
| 152 | * @ap_msg: pointer to AP message | ||
| 153 | * @mex: pointer to user input data | ||
| 154 | * | ||
| 155 | * Returns 0 on success or -EFAULT. | ||
| 156 | */ | ||
| 157 | static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev, | ||
| 158 | struct ap_message *ap_msg, | ||
| 159 | struct ica_rsa_modexpo *mex) | ||
| 160 | { | ||
| 161 | static struct type6_hdr static_type6_hdrX = { | ||
| 162 | .type = 0x06, | ||
| 163 | .offset1 = 0x00000058, | ||
| 164 | .agent_id = {'C', 'A',}, | ||
| 165 | .function_code = {'P', 'K'}, | ||
| 166 | }; | ||
| 167 | static struct function_and_rules_block static_pke_fnr = { | ||
| 168 | .function_code = {'P', 'K'}, | ||
| 169 | .ulen = 10, | ||
| 170 | .only_rule = {'M', 'R', 'P', ' ', ' ', ' ', ' ', ' '} | ||
| 171 | }; | ||
| 172 | static struct function_and_rules_block static_pke_fnr_MCL2 = { | ||
| 173 | .function_code = {'P', 'K'}, | ||
| 174 | .ulen = 10, | ||
| 175 | .only_rule = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'} | ||
| 176 | }; | ||
| 177 | struct { | ||
| 178 | struct type6_hdr hdr; | ||
| 179 | struct CPRBX cprbx; | ||
| 180 | struct function_and_rules_block fr; | ||
| 181 | unsigned short length; | ||
| 182 | char text[0]; | ||
| 183 | } __packed * msg = ap_msg->message; | ||
| 184 | int size; | ||
| 185 | |||
| 186 | /* VUD.ciphertext */ | ||
| 187 | msg->length = mex->inputdatalength + 2; | ||
| 188 | if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength)) | ||
| 189 | return -EFAULT; | ||
| 190 | |||
| 191 | /* Set up key which is located after the variable length text. */ | ||
| 192 | size = zcrypt_type6_mex_key_en(mex, msg->text+mex->inputdatalength, 1); | ||
| 193 | if (size < 0) | ||
| 194 | return size; | ||
| 195 | size += sizeof(*msg) + mex->inputdatalength; | ||
| 196 | |||
| 197 | /* message header, cprbx and f&r */ | ||
| 198 | msg->hdr = static_type6_hdrX; | ||
| 199 | msg->hdr.ToCardLen1 = size - sizeof(msg->hdr); | ||
| 200 | msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); | ||
| 201 | |||
| 202 | msg->cprbx = static_cprbx; | ||
| 203 | msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); | ||
| 204 | msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1; | ||
| 205 | |||
| 206 | msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ? | ||
| 207 | static_pke_fnr_MCL2 : static_pke_fnr; | ||
| 208 | |||
| 209 | msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx); | ||
| 210 | |||
| 211 | ap_msg->length = size; | ||
| 212 | return 0; | ||
| 213 | } | ||
| 214 | |||
| 215 | /** | ||
| 216 | * Convert a ICACRT message to a type6 CRT message. | ||
| 217 | * | ||
| 218 | * @zdev: crypto device pointer | ||
| 219 | * @ap_msg: pointer to AP message | ||
| 220 | * @crt: pointer to user input data | ||
| 221 | * | ||
| 222 | * Returns 0 on success or -EFAULT. | ||
| 223 | */ | ||
| 224 | static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev, | ||
| 225 | struct ap_message *ap_msg, | ||
| 226 | struct ica_rsa_modexpo_crt *crt) | ||
| 227 | { | ||
| 228 | static struct type6_hdr static_type6_hdrX = { | ||
| 229 | .type = 0x06, | ||
| 230 | .offset1 = 0x00000058, | ||
| 231 | .agent_id = {'C', 'A',}, | ||
| 232 | .function_code = {'P', 'D'}, | ||
| 233 | }; | ||
| 234 | static struct function_and_rules_block static_pkd_fnr = { | ||
| 235 | .function_code = {'P', 'D'}, | ||
| 236 | .ulen = 10, | ||
| 237 | .only_rule = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'} | ||
| 238 | }; | ||
| 239 | |||
| 240 | static struct function_and_rules_block static_pkd_fnr_MCL2 = { | ||
| 241 | .function_code = {'P', 'D'}, | ||
| 242 | .ulen = 10, | ||
| 243 | .only_rule = {'P', 'K', 'C', 'S', '-', '1', '.', '2'} | ||
| 244 | }; | ||
| 245 | struct { | ||
| 246 | struct type6_hdr hdr; | ||
| 247 | struct CPRBX cprbx; | ||
| 248 | struct function_and_rules_block fr; | ||
| 249 | unsigned short length; | ||
| 250 | char text[0]; | ||
| 251 | } __packed * msg = ap_msg->message; | ||
| 252 | int size; | ||
| 253 | |||
| 254 | /* VUD.ciphertext */ | ||
| 255 | msg->length = crt->inputdatalength + 2; | ||
| 256 | if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength)) | ||
| 257 | return -EFAULT; | ||
| 258 | |||
| 259 | /* Set up key which is located after the variable length text. */ | ||
| 260 | size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 1); | ||
| 261 | if (size < 0) | ||
| 262 | return size; | ||
| 263 | size += sizeof(*msg) + crt->inputdatalength; /* total size of msg */ | ||
| 264 | |||
| 265 | /* message header, cprbx and f&r */ | ||
| 266 | msg->hdr = static_type6_hdrX; | ||
| 267 | msg->hdr.ToCardLen1 = size - sizeof(msg->hdr); | ||
| 268 | msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); | ||
| 269 | |||
| 270 | msg->cprbx = static_cprbx; | ||
| 271 | msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); | ||
| 272 | msg->cprbx.req_parml = msg->cprbx.rpl_msgbl = | ||
| 273 | size - sizeof(msg->hdr) - sizeof(msg->cprbx); | ||
| 274 | |||
| 275 | msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ? | ||
| 276 | static_pkd_fnr_MCL2 : static_pkd_fnr; | ||
| 277 | |||
| 278 | ap_msg->length = size; | ||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | /** | ||
| 283 | * Convert a XCRB message to a type6 CPRB message. | ||
| 284 | * | ||
| 285 | * @zdev: crypto device pointer | ||
| 286 | * @ap_msg: pointer to AP message | ||
| 287 | * @xcRB: pointer to user input data | ||
| 288 | * | ||
| 289 | * Returns 0 on success or -EFAULT, -EINVAL. | ||
| 290 | */ | ||
| 291 | struct type86_fmt2_msg { | ||
| 292 | struct type86_hdr hdr; | ||
| 293 | struct type86_fmt2_ext fmt2; | ||
| 294 | } __packed; | ||
| 295 | |||
| 296 | static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, | ||
| 297 | struct ap_message *ap_msg, | ||
| 298 | struct ica_xcRB *xcRB) | ||
| 299 | { | ||
| 300 | static struct type6_hdr static_type6_hdrX = { | ||
| 301 | .type = 0x06, | ||
| 302 | .offset1 = 0x00000058, | ||
| 303 | }; | ||
| 304 | struct { | ||
| 305 | struct type6_hdr hdr; | ||
| 306 | struct CPRBX cprbx; | ||
| 307 | } __packed * msg = ap_msg->message; | ||
| 308 | |||
| 309 | int rcblen = CEIL4(xcRB->request_control_blk_length); | ||
| 310 | int replylen; | ||
| 311 | char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen; | ||
| 312 | char *function_code; | ||
| 313 | |||
| 314 | /* length checks */ | ||
| 315 | ap_msg->length = sizeof(struct type6_hdr) + | ||
| 316 | CEIL4(xcRB->request_control_blk_length) + | ||
| 317 | xcRB->request_data_length; | ||
| 318 | if (ap_msg->length > MSGTYPE06_MAX_MSG_SIZE) | ||
| 319 | return -EINVAL; | ||
| 320 | replylen = sizeof(struct type86_fmt2_msg) + | ||
| 321 | CEIL4(xcRB->reply_control_blk_length) + | ||
| 322 | xcRB->reply_data_length; | ||
| 323 | if (replylen > MSGTYPE06_MAX_MSG_SIZE) | ||
| 324 | return -EINVAL; | ||
| 325 | |||
| 326 | /* prepare type6 header */ | ||
| 327 | msg->hdr = static_type6_hdrX; | ||
| 328 | memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID)); | ||
| 329 | msg->hdr.ToCardLen1 = xcRB->request_control_blk_length; | ||
| 330 | if (xcRB->request_data_length) { | ||
| 331 | msg->hdr.offset2 = msg->hdr.offset1 + rcblen; | ||
| 332 | msg->hdr.ToCardLen2 = xcRB->request_data_length; | ||
| 333 | } | ||
| 334 | msg->hdr.FromCardLen1 = xcRB->reply_control_blk_length; | ||
| 335 | msg->hdr.FromCardLen2 = xcRB->reply_data_length; | ||
| 336 | |||
| 337 | /* prepare CPRB */ | ||
| 338 | if (copy_from_user(&(msg->cprbx), xcRB->request_control_blk_addr, | ||
| 339 | xcRB->request_control_blk_length)) | ||
| 340 | return -EFAULT; | ||
| 341 | if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) > | ||
| 342 | xcRB->request_control_blk_length) | ||
| 343 | return -EINVAL; | ||
| 344 | function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len; | ||
| 345 | memcpy(msg->hdr.function_code, function_code, | ||
| 346 | sizeof(msg->hdr.function_code)); | ||
| 347 | |||
| 348 | if (memcmp(function_code, "US", 2) == 0) | ||
| 349 | ap_msg->special = 1; | ||
| 350 | else | ||
| 351 | ap_msg->special = 0; | ||
| 352 | |||
| 353 | /* copy data block */ | ||
| 354 | if (xcRB->request_data_length && | ||
| 355 | copy_from_user(req_data, xcRB->request_data_address, | ||
| 356 | xcRB->request_data_length)) | ||
| 357 | return -EFAULT; | ||
| 358 | return 0; | ||
| 359 | } | ||
| 360 | |||
| 361 | /** | ||
| 362 | * Copy results from a type 86 ICA reply message back to user space. | ||
| 363 | * | ||
| 364 | * @zdev: crypto device pointer | ||
| 365 | * @reply: reply AP message. | ||
| 366 | * @data: pointer to user output data | ||
| 367 | * @length: size of user output data | ||
| 368 | * | ||
| 369 | * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. | ||
| 370 | */ | ||
| 371 | struct type86x_reply { | ||
| 372 | struct type86_hdr hdr; | ||
| 373 | struct type86_fmt2_ext fmt2; | ||
| 374 | struct CPRBX cprbx; | ||
| 375 | unsigned char pad[4]; /* 4 byte function code/rules block ? */ | ||
| 376 | unsigned short length; | ||
| 377 | char text[0]; | ||
| 378 | } __packed; | ||
| 379 | |||
| 380 | static int convert_type86_ica(struct zcrypt_device *zdev, | ||
| 381 | struct ap_message *reply, | ||
| 382 | char __user *outputdata, | ||
| 383 | unsigned int outputdatalength) | ||
| 384 | { | ||
| 385 | static unsigned char static_pad[] = { | ||
| 386 | 0x00, 0x02, | ||
| 387 | 0x1B, 0x7B, 0x5D, 0xB5, 0x75, 0x01, 0x3D, 0xFD, | ||
| 388 | 0x8D, 0xD1, 0xC7, 0x03, 0x2D, 0x09, 0x23, 0x57, | ||
| 389 | 0x89, 0x49, 0xB9, 0x3F, 0xBB, 0x99, 0x41, 0x5B, | ||
| 390 | 0x75, 0x21, 0x7B, 0x9D, 0x3B, 0x6B, 0x51, 0x39, | ||
| 391 | 0xBB, 0x0D, 0x35, 0xB9, 0x89, 0x0F, 0x93, 0xA5, | ||
| 392 | 0x0B, 0x47, 0xF1, 0xD3, 0xBB, 0xCB, 0xF1, 0x9D, | ||
| 393 | 0x23, 0x73, 0x71, 0xFF, 0xF3, 0xF5, 0x45, 0xFB, | ||
| 394 | 0x61, 0x29, 0x23, 0xFD, 0xF1, 0x29, 0x3F, 0x7F, | ||
| 395 | 0x17, 0xB7, 0x1B, 0xA9, 0x19, 0xBD, 0x57, 0xA9, | ||
| 396 | 0xD7, 0x95, 0xA3, 0xCB, 0xED, 0x1D, 0xDB, 0x45, | ||
| 397 | 0x7D, 0x11, 0xD1, 0x51, 0x1B, 0xED, 0x71, 0xE9, | ||
| 398 | 0xB1, 0xD1, 0xAB, 0xAB, 0x21, 0x2B, 0x1B, 0x9F, | ||
| 399 | 0x3B, 0x9F, 0xF7, 0xF7, 0xBD, 0x63, 0xEB, 0xAD, | ||
| 400 | 0xDF, 0xB3, 0x6F, 0x5B, 0xDB, 0x8D, 0xA9, 0x5D, | ||
| 401 | 0xE3, 0x7D, 0x77, 0x49, 0x47, 0xF5, 0xA7, 0xFD, | ||
| 402 | 0xAB, 0x2F, 0x27, 0x35, 0x77, 0xD3, 0x49, 0xC9, | ||
| 403 | 0x09, 0xEB, 0xB1, 0xF9, 0xBF, 0x4B, 0xCB, 0x2B, | ||
| 404 | 0xEB, 0xEB, 0x05, 0xFF, 0x7D, 0xC7, 0x91, 0x8B, | ||
| 405 | 0x09, 0x83, 0xB9, 0xB9, 0x69, 0x33, 0x39, 0x6B, | ||
| 406 | 0x79, 0x75, 0x19, 0xBF, 0xBB, 0x07, 0x1D, 0xBD, | ||
| 407 | 0x29, 0xBF, 0x39, 0x95, 0x93, 0x1D, 0x35, 0xC7, | ||
| 408 | 0xC9, 0x4D, 0xE5, 0x97, 0x0B, 0x43, 0x9B, 0xF1, | ||
| 409 | 0x16, 0x93, 0x03, 0x1F, 0xA5, 0xFB, 0xDB, 0xF3, | ||
| 410 | 0x27, 0x4F, 0x27, 0x61, 0x05, 0x1F, 0xB9, 0x23, | ||
| 411 | 0x2F, 0xC3, 0x81, 0xA9, 0x23, 0x71, 0x55, 0x55, | ||
| 412 | 0xEB, 0xED, 0x41, 0xE5, 0xF3, 0x11, 0xF1, 0x43, | ||
| 413 | 0x69, 0x03, 0xBD, 0x0B, 0x37, 0x0F, 0x51, 0x8F, | ||
| 414 | 0x0B, 0xB5, 0x89, 0x5B, 0x67, 0xA9, 0xD9, 0x4F, | ||
| 415 | 0x01, 0xF9, 0x21, 0x77, 0x37, 0x73, 0x79, 0xC5, | ||
| 416 | 0x7F, 0x51, 0xC1, 0xCF, 0x97, 0xA1, 0x75, 0xAD, | ||
| 417 | 0x35, 0x9D, 0xD3, 0xD3, 0xA7, 0x9D, 0x5D, 0x41, | ||
| 418 | 0x6F, 0x65, 0x1B, 0xCF, 0xA9, 0x87, 0x91, 0x09 | ||
| 419 | }; | ||
| 420 | struct type86x_reply *msg = reply->message; | ||
| 421 | unsigned short service_rc, service_rs; | ||
| 422 | unsigned int reply_len, pad_len; | ||
| 423 | char *data; | ||
| 424 | |||
| 425 | service_rc = msg->cprbx.ccp_rtcode; | ||
| 426 | if (unlikely(service_rc != 0)) { | ||
| 427 | service_rs = msg->cprbx.ccp_rscode; | ||
| 428 | if (service_rc == 8 && service_rs == 66) | ||
| 429 | return -EINVAL; | ||
| 430 | if (service_rc == 8 && service_rs == 65) | ||
| 431 | return -EINVAL; | ||
| 432 | if (service_rc == 8 && service_rs == 770) | ||
| 433 | return -EINVAL; | ||
| 434 | if (service_rc == 8 && service_rs == 783) { | ||
| 435 | zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; | ||
| 436 | return -EAGAIN; | ||
| 437 | } | ||
| 438 | if (service_rc == 12 && service_rs == 769) | ||
| 439 | return -EINVAL; | ||
| 440 | if (service_rc == 8 && service_rs == 72) | ||
| 441 | return -EINVAL; | ||
| 442 | zdev->online = 0; | ||
| 443 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 444 | } | ||
| 445 | data = msg->text; | ||
| 446 | reply_len = msg->length - 2; | ||
| 447 | if (reply_len > outputdatalength) | ||
| 448 | return -EINVAL; | ||
| 449 | /* | ||
| 450 | * For all encipher requests, the length of the ciphertext (reply_len) | ||
| 451 | * will always equal the modulus length. For MEX decipher requests | ||
| 452 | * the output needs to get padded. Minimum pad size is 10. | ||
| 453 | * | ||
| 454 | * Currently, the cases where padding will be added is for: | ||
| 455 | * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support | ||
| 456 | * ZERO-PAD and CRT is only supported for PKD requests) | ||
| 457 | * - PCICC, always | ||
| 458 | */ | ||
| 459 | pad_len = outputdatalength - reply_len; | ||
| 460 | if (pad_len > 0) { | ||
| 461 | if (pad_len < 10) | ||
| 462 | return -EINVAL; | ||
| 463 | /* 'restore' padding left in the PCICC/PCIXCC card. */ | ||
| 464 | if (copy_to_user(outputdata, static_pad, pad_len - 1)) | ||
| 465 | return -EFAULT; | ||
| 466 | if (put_user(0, outputdata + pad_len - 1)) | ||
| 467 | return -EFAULT; | ||
| 468 | } | ||
| 469 | /* Copy the crypto response to user space. */ | ||
| 470 | if (copy_to_user(outputdata + pad_len, data, reply_len)) | ||
| 471 | return -EFAULT; | ||
| 472 | return 0; | ||
| 473 | } | ||
| 474 | |||
| 475 | /** | ||
| 476 | * Copy results from a type 86 XCRB reply message back to user space. | ||
| 477 | * | ||
| 478 | * @zdev: crypto device pointer | ||
| 479 | * @reply: reply AP message. | ||
| 480 | * @xcRB: pointer to XCRB | ||
| 481 | * | ||
| 482 | * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. | ||
| 483 | */ | ||
| 484 | static int convert_type86_xcrb(struct zcrypt_device *zdev, | ||
| 485 | struct ap_message *reply, | ||
| 486 | struct ica_xcRB *xcRB) | ||
| 487 | { | ||
| 488 | struct type86_fmt2_msg *msg = reply->message; | ||
| 489 | char *data = reply->message; | ||
| 490 | |||
| 491 | /* Copy CPRB to user */ | ||
| 492 | if (copy_to_user(xcRB->reply_control_blk_addr, | ||
| 493 | data + msg->fmt2.offset1, msg->fmt2.count1)) | ||
| 494 | return -EFAULT; | ||
| 495 | xcRB->reply_control_blk_length = msg->fmt2.count1; | ||
| 496 | |||
| 497 | /* Copy data buffer to user */ | ||
| 498 | if (msg->fmt2.count2) | ||
| 499 | if (copy_to_user(xcRB->reply_data_addr, | ||
| 500 | data + msg->fmt2.offset2, msg->fmt2.count2)) | ||
| 501 | return -EFAULT; | ||
| 502 | xcRB->reply_data_length = msg->fmt2.count2; | ||
| 503 | return 0; | ||
| 504 | } | ||
| 505 | |||
| 506 | static int convert_type86_rng(struct zcrypt_device *zdev, | ||
| 507 | struct ap_message *reply, | ||
| 508 | char *buffer) | ||
| 509 | { | ||
| 510 | struct { | ||
| 511 | struct type86_hdr hdr; | ||
| 512 | struct type86_fmt2_ext fmt2; | ||
| 513 | struct CPRBX cprbx; | ||
| 514 | } __packed * msg = reply->message; | ||
| 515 | char *data = reply->message; | ||
| 516 | |||
| 517 | if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0) | ||
| 518 | return -EINVAL; | ||
| 519 | memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2); | ||
| 520 | return msg->fmt2.count2; | ||
| 521 | } | ||
| 522 | |||
| 523 | static int convert_response_ica(struct zcrypt_device *zdev, | ||
| 524 | struct ap_message *reply, | ||
| 525 | char __user *outputdata, | ||
| 526 | unsigned int outputdatalength) | ||
| 527 | { | ||
| 528 | struct type86x_reply *msg = reply->message; | ||
| 529 | |||
| 530 | /* Response type byte is the second byte in the response. */ | ||
| 531 | switch (((unsigned char *) reply->message)[1]) { | ||
| 532 | case TYPE82_RSP_CODE: | ||
| 533 | case TYPE88_RSP_CODE: | ||
| 534 | return convert_error(zdev, reply); | ||
| 535 | case TYPE86_RSP_CODE: | ||
| 536 | if (msg->cprbx.ccp_rtcode && | ||
| 537 | (msg->cprbx.ccp_rscode == 0x14f) && | ||
| 538 | (outputdatalength > 256)) { | ||
| 539 | if (zdev->max_exp_bit_length <= 17) { | ||
| 540 | zdev->max_exp_bit_length = 17; | ||
| 541 | return -EAGAIN; | ||
| 542 | } else | ||
| 543 | return -EINVAL; | ||
| 544 | } | ||
| 545 | if (msg->hdr.reply_code) | ||
| 546 | return convert_error(zdev, reply); | ||
| 547 | if (msg->cprbx.cprb_ver_id == 0x02) | ||
| 548 | return convert_type86_ica(zdev, reply, | ||
| 549 | outputdata, outputdatalength); | ||
| 550 | /* Fall through, no break, incorrect cprb version is an unknown | ||
| 551 | * response */ | ||
| 552 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 553 | zdev->online = 0; | ||
| 554 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 555 | } | ||
| 556 | } | ||
| 557 | |||
| 558 | static int convert_response_xcrb(struct zcrypt_device *zdev, | ||
| 559 | struct ap_message *reply, | ||
| 560 | struct ica_xcRB *xcRB) | ||
| 561 | { | ||
| 562 | struct type86x_reply *msg = reply->message; | ||
| 563 | |||
| 564 | /* Response type byte is the second byte in the response. */ | ||
| 565 | switch (((unsigned char *) reply->message)[1]) { | ||
| 566 | case TYPE82_RSP_CODE: | ||
| 567 | case TYPE88_RSP_CODE: | ||
| 568 | xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ | ||
| 569 | return convert_error(zdev, reply); | ||
| 570 | case TYPE86_RSP_CODE: | ||
| 571 | if (msg->hdr.reply_code) { | ||
| 572 | memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32)); | ||
| 573 | return convert_error(zdev, reply); | ||
| 574 | } | ||
| 575 | if (msg->cprbx.cprb_ver_id == 0x02) | ||
| 576 | return convert_type86_xcrb(zdev, reply, xcRB); | ||
| 577 | /* Fall through, no break, incorrect cprb version is an unknown | ||
| 578 | * response */ | ||
| 579 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 580 | xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ | ||
| 581 | zdev->online = 0; | ||
| 582 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 583 | } | ||
| 584 | } | ||
| 585 | |||
| 586 | static int convert_response_rng(struct zcrypt_device *zdev, | ||
| 587 | struct ap_message *reply, | ||
| 588 | char *data) | ||
| 589 | { | ||
| 590 | struct type86x_reply *msg = reply->message; | ||
| 591 | |||
| 592 | switch (msg->hdr.type) { | ||
| 593 | case TYPE82_RSP_CODE: | ||
| 594 | case TYPE88_RSP_CODE: | ||
| 595 | return -EINVAL; | ||
| 596 | case TYPE86_RSP_CODE: | ||
| 597 | if (msg->hdr.reply_code) | ||
| 598 | return -EINVAL; | ||
| 599 | if (msg->cprbx.cprb_ver_id == 0x02) | ||
| 600 | return convert_type86_rng(zdev, reply, data); | ||
| 601 | /* Fall through, no break, incorrect cprb version is an unknown | ||
| 602 | * response */ | ||
| 603 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 604 | zdev->online = 0; | ||
| 605 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 606 | } | ||
| 607 | } | ||
| 608 | |||
| 609 | /** | ||
| 610 | * This function is called from the AP bus code after a crypto request | ||
| 611 | * "msg" has finished with the reply message "reply". | ||
| 612 | * It is called from tasklet context. | ||
| 613 | * @ap_dev: pointer to the AP device | ||
| 614 | * @msg: pointer to the AP message | ||
| 615 | * @reply: pointer to the AP reply message | ||
| 616 | */ | ||
| 617 | static void zcrypt_msgtype6_receive(struct ap_device *ap_dev, | ||
| 618 | struct ap_message *msg, | ||
| 619 | struct ap_message *reply) | ||
| 620 | { | ||
| 621 | static struct error_hdr error_reply = { | ||
| 622 | .type = TYPE82_RSP_CODE, | ||
| 623 | .reply_code = REP82_ERROR_MACHINE_FAILURE, | ||
| 624 | }; | ||
| 625 | struct response_type *resp_type = | ||
| 626 | (struct response_type *) msg->private; | ||
| 627 | struct type86x_reply *t86r; | ||
| 628 | int length; | ||
| 629 | |||
| 630 | /* Copy the reply message to the request message buffer. */ | ||
| 631 | if (IS_ERR(reply)) { | ||
| 632 | memcpy(msg->message, &error_reply, sizeof(error_reply)); | ||
| 633 | goto out; | ||
| 634 | } | ||
| 635 | t86r = reply->message; | ||
| 636 | if (t86r->hdr.type == TYPE86_RSP_CODE && | ||
| 637 | t86r->cprbx.cprb_ver_id == 0x02) { | ||
| 638 | switch (resp_type->type) { | ||
| 639 | case PCIXCC_RESPONSE_TYPE_ICA: | ||
| 640 | length = sizeof(struct type86x_reply) | ||
| 641 | + t86r->length - 2; | ||
| 642 | length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length); | ||
| 643 | memcpy(msg->message, reply->message, length); | ||
| 644 | break; | ||
| 645 | case PCIXCC_RESPONSE_TYPE_XCRB: | ||
| 646 | length = t86r->fmt2.offset2 + t86r->fmt2.count2; | ||
| 647 | length = min(MSGTYPE06_MAX_MSG_SIZE, length); | ||
| 648 | memcpy(msg->message, reply->message, length); | ||
| 649 | break; | ||
| 650 | default: | ||
| 651 | memcpy(msg->message, &error_reply, | ||
| 652 | sizeof(error_reply)); | ||
| 653 | } | ||
| 654 | } else | ||
| 655 | memcpy(msg->message, reply->message, sizeof(error_reply)); | ||
| 656 | out: | ||
| 657 | complete(&(resp_type->work)); | ||
| 658 | } | ||
| 659 | |||
| 660 | static atomic_t zcrypt_step = ATOMIC_INIT(0); | ||
| 661 | |||
| 662 | /** | ||
| 663 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 664 | * device to handle a modexpo request. | ||
| 665 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 666 | * PCIXCC/CEX2C device to the request distributor | ||
| 667 | * @mex: pointer to the modexpo request buffer | ||
| 668 | */ | ||
| 669 | static long zcrypt_msgtype6_modexpo(struct zcrypt_device *zdev, | ||
| 670 | struct ica_rsa_modexpo *mex) | ||
| 671 | { | ||
| 672 | struct ap_message ap_msg; | ||
| 673 | struct response_type resp_type = { | ||
| 674 | .type = PCIXCC_RESPONSE_TYPE_ICA, | ||
| 675 | }; | ||
| 676 | int rc; | ||
| 677 | |||
| 678 | ap_init_message(&ap_msg); | ||
| 679 | ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); | ||
| 680 | if (!ap_msg.message) | ||
| 681 | return -ENOMEM; | ||
| 682 | ap_msg.receive = zcrypt_msgtype6_receive; | ||
| 683 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 684 | atomic_inc_return(&zcrypt_step); | ||
| 685 | ap_msg.private = &resp_type; | ||
| 686 | rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex); | ||
| 687 | if (rc) | ||
| 688 | goto out_free; | ||
| 689 | init_completion(&resp_type.work); | ||
| 690 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 691 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 692 | if (rc == 0) | ||
| 693 | rc = convert_response_ica(zdev, &ap_msg, mex->outputdata, | ||
| 694 | mex->outputdatalength); | ||
| 695 | else | ||
| 696 | /* Signal pending. */ | ||
| 697 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 698 | out_free: | ||
| 699 | free_page((unsigned long) ap_msg.message); | ||
| 700 | return rc; | ||
| 701 | } | ||
| 702 | |||
| 703 | /** | ||
| 704 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 705 | * device to handle a modexpo_crt request. | ||
| 706 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 707 | * PCIXCC/CEX2C device to the request distributor | ||
| 708 | * @crt: pointer to the modexpoc_crt request buffer | ||
| 709 | */ | ||
| 710 | static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev, | ||
| 711 | struct ica_rsa_modexpo_crt *crt) | ||
| 712 | { | ||
| 713 | struct ap_message ap_msg; | ||
| 714 | struct response_type resp_type = { | ||
| 715 | .type = PCIXCC_RESPONSE_TYPE_ICA, | ||
| 716 | }; | ||
| 717 | int rc; | ||
| 718 | |||
| 719 | ap_init_message(&ap_msg); | ||
| 720 | ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); | ||
| 721 | if (!ap_msg.message) | ||
| 722 | return -ENOMEM; | ||
| 723 | ap_msg.receive = zcrypt_msgtype6_receive; | ||
| 724 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 725 | atomic_inc_return(&zcrypt_step); | ||
| 726 | ap_msg.private = &resp_type; | ||
| 727 | rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt); | ||
| 728 | if (rc) | ||
| 729 | goto out_free; | ||
| 730 | init_completion(&resp_type.work); | ||
| 731 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 732 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 733 | if (rc == 0) | ||
| 734 | rc = convert_response_ica(zdev, &ap_msg, crt->outputdata, | ||
| 735 | crt->outputdatalength); | ||
| 736 | else | ||
| 737 | /* Signal pending. */ | ||
| 738 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 739 | out_free: | ||
| 740 | free_page((unsigned long) ap_msg.message); | ||
| 741 | return rc; | ||
| 742 | } | ||
| 743 | |||
| 744 | /** | ||
| 745 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 746 | * device to handle a send_cprb request. | ||
| 747 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 748 | * PCIXCC/CEX2C device to the request distributor | ||
| 749 | * @xcRB: pointer to the send_cprb request buffer | ||
| 750 | */ | ||
| 751 | static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev, | ||
| 752 | struct ica_xcRB *xcRB) | ||
| 753 | { | ||
| 754 | struct ap_message ap_msg; | ||
| 755 | struct response_type resp_type = { | ||
| 756 | .type = PCIXCC_RESPONSE_TYPE_XCRB, | ||
| 757 | }; | ||
| 758 | int rc; | ||
| 759 | |||
| 760 | ap_init_message(&ap_msg); | ||
| 761 | ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); | ||
| 762 | if (!ap_msg.message) | ||
| 763 | return -ENOMEM; | ||
| 764 | ap_msg.receive = zcrypt_msgtype6_receive; | ||
| 765 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 766 | atomic_inc_return(&zcrypt_step); | ||
| 767 | ap_msg.private = &resp_type; | ||
| 768 | rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB); | ||
| 769 | if (rc) | ||
| 770 | goto out_free; | ||
| 771 | init_completion(&resp_type.work); | ||
| 772 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 773 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 774 | if (rc == 0) | ||
| 775 | rc = convert_response_xcrb(zdev, &ap_msg, xcRB); | ||
| 776 | else | ||
| 777 | /* Signal pending. */ | ||
| 778 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 779 | out_free: | ||
| 780 | kzfree(ap_msg.message); | ||
| 781 | return rc; | ||
| 782 | } | ||
| 783 | |||
| 784 | /** | ||
| 785 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 786 | * device to generate random data. | ||
| 787 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 788 | * PCIXCC/CEX2C device to the request distributor | ||
| 789 | * @buffer: pointer to a memory page to return random data | ||
| 790 | */ | ||
| 791 | |||
| 792 | static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev, | ||
| 793 | char *buffer) | ||
| 794 | { | ||
| 795 | struct ap_message ap_msg; | ||
| 796 | struct response_type resp_type = { | ||
| 797 | .type = PCIXCC_RESPONSE_TYPE_XCRB, | ||
| 798 | }; | ||
| 799 | int rc; | ||
| 800 | |||
| 801 | ap_init_message(&ap_msg); | ||
| 802 | ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); | ||
| 803 | if (!ap_msg.message) | ||
| 804 | return -ENOMEM; | ||
| 805 | ap_msg.receive = zcrypt_msgtype6_receive; | ||
| 806 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 807 | atomic_inc_return(&zcrypt_step); | ||
| 808 | ap_msg.private = &resp_type; | ||
| 809 | rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE); | ||
| 810 | init_completion(&resp_type.work); | ||
| 811 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 812 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 813 | if (rc == 0) | ||
| 814 | rc = convert_response_rng(zdev, &ap_msg, buffer); | ||
| 815 | else | ||
| 816 | /* Signal pending. */ | ||
| 817 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 818 | kfree(ap_msg.message); | ||
| 819 | return rc; | ||
| 820 | } | ||
| 821 | |||
| 822 | /** | ||
| 823 | * The crypto operations for a PCIXCC/CEX2C card. | ||
| 824 | */ | ||
| 825 | static struct zcrypt_ops zcrypt_msgtype6_norng_ops = { | ||
| 826 | .owner = THIS_MODULE, | ||
| 827 | .variant = MSGTYPE06_VARIANT_NORNG, | ||
| 828 | .rsa_modexpo = zcrypt_msgtype6_modexpo, | ||
| 829 | .rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt, | ||
| 830 | .send_cprb = zcrypt_msgtype6_send_cprb, | ||
| 831 | }; | ||
| 832 | |||
| 833 | static struct zcrypt_ops zcrypt_msgtype6_ops = { | ||
| 834 | .owner = THIS_MODULE, | ||
| 835 | .variant = MSGTYPE06_VARIANT_DEFAULT, | ||
| 836 | .rsa_modexpo = zcrypt_msgtype6_modexpo, | ||
| 837 | .rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt, | ||
| 838 | .send_cprb = zcrypt_msgtype6_send_cprb, | ||
| 839 | .rng = zcrypt_msgtype6_rng, | ||
| 840 | }; | ||
| 841 | |||
| 842 | int __init zcrypt_msgtype6_init(void) | ||
| 843 | { | ||
| 844 | zcrypt_msgtype_register(&zcrypt_msgtype6_norng_ops); | ||
| 845 | zcrypt_msgtype_register(&zcrypt_msgtype6_ops); | ||
| 846 | return 0; | ||
| 847 | } | ||
| 848 | |||
| 849 | void __exit zcrypt_msgtype6_exit(void) | ||
| 850 | { | ||
| 851 | zcrypt_msgtype_unregister(&zcrypt_msgtype6_norng_ops); | ||
| 852 | zcrypt_msgtype_unregister(&zcrypt_msgtype6_ops); | ||
| 853 | } | ||
| 854 | |||
| 855 | module_init(zcrypt_msgtype6_init); | ||
| 856 | module_exit(zcrypt_msgtype6_exit); | ||
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h new file mode 100644 index 000000000000..1e500d3c0735 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_msgtype6.h | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | /* | ||
| 2 | * zcrypt 2.1.0 | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2001, 2012 | ||
| 5 | * Author(s): Robert Burroughs | ||
| 6 | * Eric Rossman (edrossma@us.ibm.com) | ||
| 7 | * | ||
| 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | ||
| 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 10 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License as published by | ||
| 14 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 15 | * any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 25 | */ | ||
| 26 | |||
| 27 | #ifndef _ZCRYPT_MSGTYPE6_H_ | ||
| 28 | #define _ZCRYPT_MSGTYPE6_H_ | ||
| 29 | |||
| 30 | #include <asm/zcrypt.h> | ||
| 31 | |||
| 32 | #define MSGTYPE06_NAME "zcrypt_msgtype6" | ||
| 33 | #define MSGTYPE06_VARIANT_DEFAULT 0 | ||
| 34 | #define MSGTYPE06_VARIANT_NORNG 1 | ||
| 35 | |||
| 36 | #define MSGTYPE06_MAX_MSG_SIZE (12*1024) | ||
| 37 | |||
| 38 | /** | ||
| 39 | * The type 6 message family is associated with PCICC or PCIXCC cards. | ||
| 40 | * | ||
| 41 | * It contains a message header followed by a CPRB, both of which | ||
| 42 | * are described below. | ||
| 43 | * | ||
| 44 | * Note that all reserved fields must be zeroes. | ||
| 45 | */ | ||
| 46 | struct type6_hdr { | ||
| 47 | unsigned char reserved1; /* 0x00 */ | ||
| 48 | unsigned char type; /* 0x06 */ | ||
| 49 | unsigned char reserved2[2]; /* 0x0000 */ | ||
| 50 | unsigned char right[4]; /* 0x00000000 */ | ||
| 51 | unsigned char reserved3[2]; /* 0x0000 */ | ||
| 52 | unsigned char reserved4[2]; /* 0x0000 */ | ||
| 53 | unsigned char apfs[4]; /* 0x00000000 */ | ||
| 54 | unsigned int offset1; /* 0x00000058 (offset to CPRB) */ | ||
| 55 | unsigned int offset2; /* 0x00000000 */ | ||
| 56 | unsigned int offset3; /* 0x00000000 */ | ||
| 57 | unsigned int offset4; /* 0x00000000 */ | ||
| 58 | unsigned char agent_id[16]; /* PCICC: */ | ||
| 59 | /* 0x0100 */ | ||
| 60 | /* 0x4343412d4150504c202020 */ | ||
| 61 | /* 0x010101 */ | ||
| 62 | /* PCIXCC: */ | ||
| 63 | /* 0x4341000000000000 */ | ||
| 64 | /* 0x0000000000000000 */ | ||
| 65 | unsigned char rqid[2]; /* rqid. internal to 603 */ | ||
| 66 | unsigned char reserved5[2]; /* 0x0000 */ | ||
| 67 | unsigned char function_code[2]; /* for PKD, 0x5044 (ascii 'PD') */ | ||
| 68 | unsigned char reserved6[2]; /* 0x0000 */ | ||
| 69 | unsigned int ToCardLen1; /* (request CPRB len + 3) & -4 */ | ||
| 70 | unsigned int ToCardLen2; /* db len 0x00000000 for PKD */ | ||
| 71 | unsigned int ToCardLen3; /* 0x00000000 */ | ||
| 72 | unsigned int ToCardLen4; /* 0x00000000 */ | ||
| 73 | unsigned int FromCardLen1; /* response buffer length */ | ||
| 74 | unsigned int FromCardLen2; /* db len 0x00000000 for PKD */ | ||
| 75 | unsigned int FromCardLen3; /* 0x00000000 */ | ||
| 76 | unsigned int FromCardLen4; /* 0x00000000 */ | ||
| 77 | } __packed; | ||
| 78 | |||
| 79 | /** | ||
| 80 | * The type 86 message family is associated with PCICC and PCIXCC cards. | ||
| 81 | * | ||
| 82 | * It contains a message header followed by a CPRB. The CPRB is | ||
| 83 | * the same as the request CPRB, which is described above. | ||
| 84 | * | ||
| 85 | * If format is 1, an error condition exists and no data beyond | ||
| 86 | * the 8-byte message header is of interest. | ||
| 87 | * | ||
| 88 | * The non-error message is shown below. | ||
| 89 | * | ||
| 90 | * Note that all reserved fields must be zeroes. | ||
| 91 | */ | ||
| 92 | struct type86_hdr { | ||
| 93 | unsigned char reserved1; /* 0x00 */ | ||
| 94 | unsigned char type; /* 0x86 */ | ||
| 95 | unsigned char format; /* 0x01 (error) or 0x02 (ok) */ | ||
| 96 | unsigned char reserved2; /* 0x00 */ | ||
| 97 | unsigned char reply_code; /* reply code (see above) */ | ||
| 98 | unsigned char reserved3[3]; /* 0x000000 */ | ||
| 99 | } __packed; | ||
| 100 | |||
| 101 | #define TYPE86_RSP_CODE 0x86 | ||
| 102 | #define TYPE86_FMT2 0x02 | ||
| 103 | |||
| 104 | struct type86_fmt2_ext { | ||
| 105 | unsigned char reserved[4]; /* 0x00000000 */ | ||
| 106 | unsigned char apfs[4]; /* final status */ | ||
| 107 | unsigned int count1; /* length of CPRB + parameters */ | ||
| 108 | unsigned int offset1; /* offset to CPRB */ | ||
| 109 | unsigned int count2; /* 0x00000000 */ | ||
| 110 | unsigned int offset2; /* db offset 0x00000000 for PKD */ | ||
| 111 | unsigned int count3; /* 0x00000000 */ | ||
| 112 | unsigned int offset3; /* 0x00000000 */ | ||
| 113 | unsigned int count4; /* 0x00000000 */ | ||
| 114 | unsigned int offset4; /* 0x00000000 */ | ||
| 115 | } __packed; | ||
| 116 | |||
| 117 | /** | ||
| 118 | * Prepare a type6 CPRB message for random number generation | ||
| 119 | * | ||
| 120 | * @ap_dev: AP device pointer | ||
| 121 | * @ap_msg: pointer to AP message | ||
| 122 | */ | ||
| 123 | static inline void rng_type6CPRB_msgX(struct ap_device *ap_dev, | ||
| 124 | struct ap_message *ap_msg, | ||
| 125 | unsigned random_number_length) | ||
| 126 | { | ||
| 127 | struct { | ||
| 128 | struct type6_hdr hdr; | ||
| 129 | struct CPRBX cprbx; | ||
| 130 | char function_code[2]; | ||
| 131 | short int rule_length; | ||
| 132 | char rule[8]; | ||
| 133 | short int verb_length; | ||
| 134 | short int key_length; | ||
| 135 | } __packed * msg = ap_msg->message; | ||
| 136 | static struct type6_hdr static_type6_hdrX = { | ||
| 137 | .type = 0x06, | ||
| 138 | .offset1 = 0x00000058, | ||
| 139 | .agent_id = {'C', 'A'}, | ||
| 140 | .function_code = {'R', 'L'}, | ||
| 141 | .ToCardLen1 = sizeof(*msg) - sizeof(msg->hdr), | ||
| 142 | .FromCardLen1 = sizeof(*msg) - sizeof(msg->hdr), | ||
| 143 | }; | ||
| 144 | static struct CPRBX local_cprbx = { | ||
| 145 | .cprb_len = 0x00dc, | ||
| 146 | .cprb_ver_id = 0x02, | ||
| 147 | .func_id = {0x54, 0x32}, | ||
| 148 | .req_parml = sizeof(*msg) - sizeof(msg->hdr) - | ||
| 149 | sizeof(msg->cprbx), | ||
| 150 | .rpl_msgbl = sizeof(*msg) - sizeof(msg->hdr), | ||
| 151 | }; | ||
| 152 | |||
| 153 | msg->hdr = static_type6_hdrX; | ||
| 154 | msg->hdr.FromCardLen2 = random_number_length, | ||
| 155 | msg->cprbx = local_cprbx; | ||
| 156 | msg->cprbx.rpl_datal = random_number_length, | ||
| 157 | msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid); | ||
| 158 | memcpy(msg->function_code, msg->hdr.function_code, 0x02); | ||
| 159 | msg->rule_length = 0x0a; | ||
| 160 | memcpy(msg->rule, "RANDOM ", 8); | ||
| 161 | msg->verb_length = 0x02; | ||
| 162 | msg->key_length = 0x02; | ||
| 163 | ap_msg->length = sizeof(*msg); | ||
| 164 | } | ||
| 165 | |||
| 166 | int zcrypt_msgtype6_init(void); | ||
| 167 | void zcrypt_msgtype6_exit(void); | ||
| 168 | |||
| 169 | #endif /* _ZCRYPT_MSGTYPE6_H_ */ | ||
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index ccb4f8b60c75..c7275e303a0d 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c | |||
| @@ -1,13 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * zcrypt 2.1.0 | 2 | * zcrypt 2.1.0 |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2001, 2006 | 4 | * Copyright IBM Corp. 2001, 2012 |
| 5 | * Author(s): Robert Burroughs | 5 | * Author(s): Robert Burroughs |
| 6 | * Eric Rossman (edrossma@us.ibm.com) | 6 | * Eric Rossman (edrossma@us.ibm.com) |
| 7 | * | 7 | * |
| 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) |
| 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 10 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | 10 | * Ralph Wuerthner <rwuerthn@de.ibm.com> |
| 11 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 11 | * | 12 | * |
| 12 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
| 13 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
| @@ -35,9 +36,10 @@ | |||
| 35 | #include "ap_bus.h" | 36 | #include "ap_bus.h" |
| 36 | #include "zcrypt_api.h" | 37 | #include "zcrypt_api.h" |
| 37 | #include "zcrypt_error.h" | 38 | #include "zcrypt_error.h" |
| 38 | #include "zcrypt_pcicc.h" | 39 | #include "zcrypt_msgtype6.h" |
| 39 | #include "zcrypt_pcixcc.h" | 40 | #include "zcrypt_pcixcc.h" |
| 40 | #include "zcrypt_cca_key.h" | 41 | #include "zcrypt_cca_key.h" |
| 42 | #include "zcrypt_msgtype6.h" | ||
| 41 | 43 | ||
| 42 | #define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */ | 44 | #define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */ |
| 43 | #define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */ | 45 | #define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */ |
| @@ -75,14 +77,12 @@ static struct ap_device_id zcrypt_pcixcc_ids[] = { | |||
| 75 | 77 | ||
| 76 | MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids); | 78 | MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids); |
| 77 | MODULE_AUTHOR("IBM Corporation"); | 79 | MODULE_AUTHOR("IBM Corporation"); |
| 78 | MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, " | 80 | MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, " \ |
| 79 | "Copyright IBM Corp. 2001, 2006"); | 81 | "Copyright IBM Corp. 2001, 2012"); |
| 80 | MODULE_LICENSE("GPL"); | 82 | MODULE_LICENSE("GPL"); |
| 81 | 83 | ||
| 82 | static int zcrypt_pcixcc_probe(struct ap_device *ap_dev); | 84 | static int zcrypt_pcixcc_probe(struct ap_device *ap_dev); |
| 83 | static void zcrypt_pcixcc_remove(struct ap_device *ap_dev); | 85 | static void zcrypt_pcixcc_remove(struct ap_device *ap_dev); |
| 84 | static void zcrypt_pcixcc_receive(struct ap_device *, struct ap_message *, | ||
| 85 | struct ap_message *); | ||
| 86 | 86 | ||
| 87 | static struct ap_driver zcrypt_pcixcc_driver = { | 87 | static struct ap_driver zcrypt_pcixcc_driver = { |
| 88 | .probe = zcrypt_pcixcc_probe, | 88 | .probe = zcrypt_pcixcc_probe, |
| @@ -92,766 +92,6 @@ static struct ap_driver zcrypt_pcixcc_driver = { | |||
| 92 | }; | 92 | }; |
| 93 | 93 | ||
| 94 | /** | 94 | /** |
| 95 | * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C | ||
| 96 | * card in a type6 message. The 3 fields that must be filled in at execution | ||
| 97 | * time are req_parml, rpl_parml and usage_domain. | ||
| 98 | * Everything about this interface is ascii/big-endian, since the | ||
| 99 | * device does *not* have 'Intel inside'. | ||
| 100 | * | ||
| 101 | * The CPRBX is followed immediately by the parm block. | ||
| 102 | * The parm block contains: | ||
| 103 | * - function code ('PD' 0x5044 or 'PK' 0x504B) | ||
| 104 | * - rule block (one of:) | ||
| 105 | * + 0x000A 'PKCS-1.2' (MCL2 'PD') | ||
| 106 | * + 0x000A 'ZERO-PAD' (MCL2 'PK') | ||
| 107 | * + 0x000A 'ZERO-PAD' (MCL3 'PD' or CEX2C 'PD') | ||
| 108 | * + 0x000A 'MRP ' (MCL3 'PK' or CEX2C 'PK') | ||
| 109 | * - VUD block | ||
| 110 | */ | ||
| 111 | static struct CPRBX static_cprbx = { | ||
| 112 | .cprb_len = 0x00DC, | ||
| 113 | .cprb_ver_id = 0x02, | ||
| 114 | .func_id = {0x54,0x32}, | ||
| 115 | }; | ||
| 116 | |||
| 117 | /** | ||
| 118 | * Convert a ICAMEX message to a type6 MEX message. | ||
| 119 | * | ||
| 120 | * @zdev: crypto device pointer | ||
| 121 | * @ap_msg: pointer to AP message | ||
| 122 | * @mex: pointer to user input data | ||
| 123 | * | ||
| 124 | * Returns 0 on success or -EFAULT. | ||
| 125 | */ | ||
| 126 | static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev, | ||
| 127 | struct ap_message *ap_msg, | ||
| 128 | struct ica_rsa_modexpo *mex) | ||
| 129 | { | ||
| 130 | static struct type6_hdr static_type6_hdrX = { | ||
| 131 | .type = 0x06, | ||
| 132 | .offset1 = 0x00000058, | ||
| 133 | .agent_id = {'C','A',}, | ||
| 134 | .function_code = {'P','K'}, | ||
| 135 | }; | ||
| 136 | static struct function_and_rules_block static_pke_fnr = { | ||
| 137 | .function_code = {'P','K'}, | ||
| 138 | .ulen = 10, | ||
| 139 | .only_rule = {'M','R','P',' ',' ',' ',' ',' '} | ||
| 140 | }; | ||
| 141 | static struct function_and_rules_block static_pke_fnr_MCL2 = { | ||
| 142 | .function_code = {'P','K'}, | ||
| 143 | .ulen = 10, | ||
| 144 | .only_rule = {'Z','E','R','O','-','P','A','D'} | ||
| 145 | }; | ||
| 146 | struct { | ||
| 147 | struct type6_hdr hdr; | ||
| 148 | struct CPRBX cprbx; | ||
| 149 | struct function_and_rules_block fr; | ||
| 150 | unsigned short length; | ||
| 151 | char text[0]; | ||
| 152 | } __attribute__((packed)) *msg = ap_msg->message; | ||
| 153 | int size; | ||
| 154 | |||
| 155 | /* VUD.ciphertext */ | ||
| 156 | msg->length = mex->inputdatalength + 2; | ||
| 157 | if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength)) | ||
| 158 | return -EFAULT; | ||
| 159 | |||
| 160 | /* Set up key which is located after the variable length text. */ | ||
| 161 | size = zcrypt_type6_mex_key_en(mex, msg->text+mex->inputdatalength, 1); | ||
| 162 | if (size < 0) | ||
| 163 | return size; | ||
| 164 | size += sizeof(*msg) + mex->inputdatalength; | ||
| 165 | |||
| 166 | /* message header, cprbx and f&r */ | ||
| 167 | msg->hdr = static_type6_hdrX; | ||
| 168 | msg->hdr.ToCardLen1 = size - sizeof(msg->hdr); | ||
| 169 | msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); | ||
| 170 | |||
| 171 | msg->cprbx = static_cprbx; | ||
| 172 | msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); | ||
| 173 | msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1; | ||
| 174 | |||
| 175 | msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ? | ||
| 176 | static_pke_fnr_MCL2 : static_pke_fnr; | ||
| 177 | |||
| 178 | msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx); | ||
| 179 | |||
| 180 | ap_msg->length = size; | ||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | /** | ||
| 185 | * Convert a ICACRT message to a type6 CRT message. | ||
| 186 | * | ||
| 187 | * @zdev: crypto device pointer | ||
| 188 | * @ap_msg: pointer to AP message | ||
| 189 | * @crt: pointer to user input data | ||
| 190 | * | ||
| 191 | * Returns 0 on success or -EFAULT. | ||
| 192 | */ | ||
| 193 | static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev, | ||
| 194 | struct ap_message *ap_msg, | ||
| 195 | struct ica_rsa_modexpo_crt *crt) | ||
| 196 | { | ||
| 197 | static struct type6_hdr static_type6_hdrX = { | ||
| 198 | .type = 0x06, | ||
| 199 | .offset1 = 0x00000058, | ||
| 200 | .agent_id = {'C','A',}, | ||
| 201 | .function_code = {'P','D'}, | ||
| 202 | }; | ||
| 203 | static struct function_and_rules_block static_pkd_fnr = { | ||
| 204 | .function_code = {'P','D'}, | ||
| 205 | .ulen = 10, | ||
| 206 | .only_rule = {'Z','E','R','O','-','P','A','D'} | ||
| 207 | }; | ||
| 208 | |||
| 209 | static struct function_and_rules_block static_pkd_fnr_MCL2 = { | ||
| 210 | .function_code = {'P','D'}, | ||
| 211 | .ulen = 10, | ||
| 212 | .only_rule = {'P','K','C','S','-','1','.','2'} | ||
| 213 | }; | ||
| 214 | struct { | ||
| 215 | struct type6_hdr hdr; | ||
| 216 | struct CPRBX cprbx; | ||
| 217 | struct function_and_rules_block fr; | ||
| 218 | unsigned short length; | ||
| 219 | char text[0]; | ||
| 220 | } __attribute__((packed)) *msg = ap_msg->message; | ||
| 221 | int size; | ||
| 222 | |||
| 223 | /* VUD.ciphertext */ | ||
| 224 | msg->length = crt->inputdatalength + 2; | ||
| 225 | if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength)) | ||
| 226 | return -EFAULT; | ||
| 227 | |||
| 228 | /* Set up key which is located after the variable length text. */ | ||
| 229 | size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 1); | ||
| 230 | if (size < 0) | ||
| 231 | return size; | ||
| 232 | size += sizeof(*msg) + crt->inputdatalength; /* total size of msg */ | ||
| 233 | |||
| 234 | /* message header, cprbx and f&r */ | ||
| 235 | msg->hdr = static_type6_hdrX; | ||
| 236 | msg->hdr.ToCardLen1 = size - sizeof(msg->hdr); | ||
| 237 | msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); | ||
| 238 | |||
| 239 | msg->cprbx = static_cprbx; | ||
| 240 | msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); | ||
| 241 | msg->cprbx.req_parml = msg->cprbx.rpl_msgbl = | ||
| 242 | size - sizeof(msg->hdr) - sizeof(msg->cprbx); | ||
| 243 | |||
| 244 | msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ? | ||
| 245 | static_pkd_fnr_MCL2 : static_pkd_fnr; | ||
| 246 | |||
| 247 | ap_msg->length = size; | ||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | |||
| 251 | /** | ||
| 252 | * Convert a XCRB message to a type6 CPRB message. | ||
| 253 | * | ||
| 254 | * @zdev: crypto device pointer | ||
| 255 | * @ap_msg: pointer to AP message | ||
| 256 | * @xcRB: pointer to user input data | ||
| 257 | * | ||
| 258 | * Returns 0 on success or -EFAULT, -EINVAL. | ||
| 259 | */ | ||
| 260 | struct type86_fmt2_msg { | ||
| 261 | struct type86_hdr hdr; | ||
| 262 | struct type86_fmt2_ext fmt2; | ||
| 263 | } __attribute__((packed)); | ||
| 264 | |||
| 265 | static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, | ||
| 266 | struct ap_message *ap_msg, | ||
| 267 | struct ica_xcRB *xcRB) | ||
| 268 | { | ||
| 269 | static struct type6_hdr static_type6_hdrX = { | ||
| 270 | .type = 0x06, | ||
| 271 | .offset1 = 0x00000058, | ||
| 272 | }; | ||
| 273 | struct { | ||
| 274 | struct type6_hdr hdr; | ||
| 275 | struct CPRBX cprbx; | ||
| 276 | } __attribute__((packed)) *msg = ap_msg->message; | ||
| 277 | |||
| 278 | int rcblen = CEIL4(xcRB->request_control_blk_length); | ||
| 279 | int replylen; | ||
| 280 | char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen; | ||
| 281 | char *function_code; | ||
| 282 | |||
| 283 | /* length checks */ | ||
| 284 | ap_msg->length = sizeof(struct type6_hdr) + | ||
| 285 | CEIL4(xcRB->request_control_blk_length) + | ||
| 286 | xcRB->request_data_length; | ||
| 287 | if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE) | ||
| 288 | return -EINVAL; | ||
| 289 | replylen = sizeof(struct type86_fmt2_msg) + | ||
| 290 | CEIL4(xcRB->reply_control_blk_length) + | ||
| 291 | xcRB->reply_data_length; | ||
| 292 | if (replylen > PCIXCC_MAX_XCRB_MESSAGE_SIZE) | ||
| 293 | return -EINVAL; | ||
| 294 | |||
| 295 | /* prepare type6 header */ | ||
| 296 | msg->hdr = static_type6_hdrX; | ||
| 297 | memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID)); | ||
| 298 | msg->hdr.ToCardLen1 = xcRB->request_control_blk_length; | ||
| 299 | if (xcRB->request_data_length) { | ||
| 300 | msg->hdr.offset2 = msg->hdr.offset1 + rcblen; | ||
| 301 | msg->hdr.ToCardLen2 = xcRB->request_data_length; | ||
| 302 | } | ||
| 303 | msg->hdr.FromCardLen1 = xcRB->reply_control_blk_length; | ||
| 304 | msg->hdr.FromCardLen2 = xcRB->reply_data_length; | ||
| 305 | |||
| 306 | /* prepare CPRB */ | ||
| 307 | if (copy_from_user(&(msg->cprbx), xcRB->request_control_blk_addr, | ||
| 308 | xcRB->request_control_blk_length)) | ||
| 309 | return -EFAULT; | ||
| 310 | if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) > | ||
| 311 | xcRB->request_control_blk_length) | ||
| 312 | return -EINVAL; | ||
| 313 | function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len; | ||
| 314 | memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code)); | ||
| 315 | |||
| 316 | if (memcmp(function_code, "US", 2) == 0) | ||
| 317 | ap_msg->special = 1; | ||
| 318 | else | ||
| 319 | ap_msg->special = 0; | ||
| 320 | |||
| 321 | /* copy data block */ | ||
| 322 | if (xcRB->request_data_length && | ||
| 323 | copy_from_user(req_data, xcRB->request_data_address, | ||
| 324 | xcRB->request_data_length)) | ||
| 325 | return -EFAULT; | ||
| 326 | return 0; | ||
| 327 | } | ||
| 328 | |||
| 329 | /** | ||
| 330 | * Prepare a type6 CPRB message for random number generation | ||
| 331 | * | ||
| 332 | * @ap_dev: AP device pointer | ||
| 333 | * @ap_msg: pointer to AP message | ||
| 334 | */ | ||
| 335 | static void rng_type6CPRB_msgX(struct ap_device *ap_dev, | ||
| 336 | struct ap_message *ap_msg, | ||
| 337 | unsigned random_number_length) | ||
| 338 | { | ||
| 339 | struct { | ||
| 340 | struct type6_hdr hdr; | ||
| 341 | struct CPRBX cprbx; | ||
| 342 | char function_code[2]; | ||
| 343 | short int rule_length; | ||
| 344 | char rule[8]; | ||
| 345 | short int verb_length; | ||
| 346 | short int key_length; | ||
| 347 | } __attribute__((packed)) *msg = ap_msg->message; | ||
| 348 | static struct type6_hdr static_type6_hdrX = { | ||
| 349 | .type = 0x06, | ||
| 350 | .offset1 = 0x00000058, | ||
| 351 | .agent_id = {'C', 'A'}, | ||
| 352 | .function_code = {'R', 'L'}, | ||
| 353 | .ToCardLen1 = sizeof *msg - sizeof(msg->hdr), | ||
| 354 | .FromCardLen1 = sizeof *msg - sizeof(msg->hdr), | ||
| 355 | }; | ||
| 356 | static struct CPRBX local_cprbx = { | ||
| 357 | .cprb_len = 0x00dc, | ||
| 358 | .cprb_ver_id = 0x02, | ||
| 359 | .func_id = {0x54, 0x32}, | ||
| 360 | .req_parml = sizeof *msg - sizeof(msg->hdr) - | ||
| 361 | sizeof(msg->cprbx), | ||
| 362 | .rpl_msgbl = sizeof *msg - sizeof(msg->hdr), | ||
| 363 | }; | ||
| 364 | |||
| 365 | msg->hdr = static_type6_hdrX; | ||
| 366 | msg->hdr.FromCardLen2 = random_number_length, | ||
| 367 | msg->cprbx = local_cprbx; | ||
| 368 | msg->cprbx.rpl_datal = random_number_length, | ||
| 369 | msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid); | ||
| 370 | memcpy(msg->function_code, msg->hdr.function_code, 0x02); | ||
| 371 | msg->rule_length = 0x0a; | ||
| 372 | memcpy(msg->rule, "RANDOM ", 8); | ||
| 373 | msg->verb_length = 0x02; | ||
| 374 | msg->key_length = 0x02; | ||
| 375 | ap_msg->length = sizeof *msg; | ||
| 376 | } | ||
| 377 | |||
| 378 | /** | ||
| 379 | * Copy results from a type 86 ICA reply message back to user space. | ||
| 380 | * | ||
| 381 | * @zdev: crypto device pointer | ||
| 382 | * @reply: reply AP message. | ||
| 383 | * @data: pointer to user output data | ||
| 384 | * @length: size of user output data | ||
| 385 | * | ||
| 386 | * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. | ||
| 387 | */ | ||
| 388 | struct type86x_reply { | ||
| 389 | struct type86_hdr hdr; | ||
| 390 | struct type86_fmt2_ext fmt2; | ||
| 391 | struct CPRBX cprbx; | ||
| 392 | unsigned char pad[4]; /* 4 byte function code/rules block ? */ | ||
| 393 | unsigned short length; | ||
| 394 | char text[0]; | ||
| 395 | } __attribute__((packed)); | ||
| 396 | |||
| 397 | static int convert_type86_ica(struct zcrypt_device *zdev, | ||
| 398 | struct ap_message *reply, | ||
| 399 | char __user *outputdata, | ||
| 400 | unsigned int outputdatalength) | ||
| 401 | { | ||
| 402 | static unsigned char static_pad[] = { | ||
| 403 | 0x00,0x02, | ||
| 404 | 0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD, | ||
| 405 | 0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57, | ||
| 406 | 0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B, | ||
| 407 | 0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39, | ||
| 408 | 0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5, | ||
| 409 | 0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D, | ||
| 410 | 0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB, | ||
| 411 | 0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F, | ||
| 412 | 0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9, | ||
| 413 | 0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45, | ||
| 414 | 0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9, | ||
| 415 | 0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F, | ||
| 416 | 0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD, | ||
| 417 | 0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D, | ||
| 418 | 0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD, | ||
| 419 | 0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9, | ||
| 420 | 0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B, | ||
| 421 | 0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B, | ||
| 422 | 0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B, | ||
| 423 | 0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD, | ||
| 424 | 0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7, | ||
| 425 | 0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1, | ||
| 426 | 0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3, | ||
| 427 | 0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23, | ||
| 428 | 0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55, | ||
| 429 | 0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43, | ||
| 430 | 0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F, | ||
| 431 | 0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F, | ||
| 432 | 0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5, | ||
| 433 | 0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD, | ||
| 434 | 0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41, | ||
| 435 | 0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09 | ||
| 436 | }; | ||
| 437 | struct type86x_reply *msg = reply->message; | ||
| 438 | unsigned short service_rc, service_rs; | ||
| 439 | unsigned int reply_len, pad_len; | ||
| 440 | char *data; | ||
| 441 | |||
| 442 | service_rc = msg->cprbx.ccp_rtcode; | ||
| 443 | if (unlikely(service_rc != 0)) { | ||
| 444 | service_rs = msg->cprbx.ccp_rscode; | ||
| 445 | if (service_rc == 8 && service_rs == 66) | ||
| 446 | return -EINVAL; | ||
| 447 | if (service_rc == 8 && service_rs == 65) | ||
| 448 | return -EINVAL; | ||
| 449 | if (service_rc == 8 && service_rs == 770) | ||
| 450 | return -EINVAL; | ||
| 451 | if (service_rc == 8 && service_rs == 783) { | ||
| 452 | zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; | ||
| 453 | return -EAGAIN; | ||
| 454 | } | ||
| 455 | if (service_rc == 12 && service_rs == 769) | ||
| 456 | return -EINVAL; | ||
| 457 | if (service_rc == 8 && service_rs == 72) | ||
| 458 | return -EINVAL; | ||
| 459 | zdev->online = 0; | ||
| 460 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 461 | } | ||
| 462 | data = msg->text; | ||
| 463 | reply_len = msg->length - 2; | ||
| 464 | if (reply_len > outputdatalength) | ||
| 465 | return -EINVAL; | ||
| 466 | /* | ||
| 467 | * For all encipher requests, the length of the ciphertext (reply_len) | ||
| 468 | * will always equal the modulus length. For MEX decipher requests | ||
| 469 | * the output needs to get padded. Minimum pad size is 10. | ||
| 470 | * | ||
| 471 | * Currently, the cases where padding will be added is for: | ||
| 472 | * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support | ||
| 473 | * ZERO-PAD and CRT is only supported for PKD requests) | ||
| 474 | * - PCICC, always | ||
| 475 | */ | ||
| 476 | pad_len = outputdatalength - reply_len; | ||
| 477 | if (pad_len > 0) { | ||
| 478 | if (pad_len < 10) | ||
| 479 | return -EINVAL; | ||
| 480 | /* 'restore' padding left in the PCICC/PCIXCC card. */ | ||
| 481 | if (copy_to_user(outputdata, static_pad, pad_len - 1)) | ||
| 482 | return -EFAULT; | ||
| 483 | if (put_user(0, outputdata + pad_len - 1)) | ||
| 484 | return -EFAULT; | ||
| 485 | } | ||
| 486 | /* Copy the crypto response to user space. */ | ||
| 487 | if (copy_to_user(outputdata + pad_len, data, reply_len)) | ||
| 488 | return -EFAULT; | ||
| 489 | return 0; | ||
| 490 | } | ||
| 491 | |||
| 492 | /** | ||
| 493 | * Copy results from a type 86 XCRB reply message back to user space. | ||
| 494 | * | ||
| 495 | * @zdev: crypto device pointer | ||
| 496 | * @reply: reply AP message. | ||
| 497 | * @xcRB: pointer to XCRB | ||
| 498 | * | ||
| 499 | * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. | ||
| 500 | */ | ||
| 501 | static int convert_type86_xcrb(struct zcrypt_device *zdev, | ||
| 502 | struct ap_message *reply, | ||
| 503 | struct ica_xcRB *xcRB) | ||
| 504 | { | ||
| 505 | struct type86_fmt2_msg *msg = reply->message; | ||
| 506 | char *data = reply->message; | ||
| 507 | |||
| 508 | /* Copy CPRB to user */ | ||
| 509 | if (copy_to_user(xcRB->reply_control_blk_addr, | ||
| 510 | data + msg->fmt2.offset1, msg->fmt2.count1)) | ||
| 511 | return -EFAULT; | ||
| 512 | xcRB->reply_control_blk_length = msg->fmt2.count1; | ||
| 513 | |||
| 514 | /* Copy data buffer to user */ | ||
| 515 | if (msg->fmt2.count2) | ||
| 516 | if (copy_to_user(xcRB->reply_data_addr, | ||
| 517 | data + msg->fmt2.offset2, msg->fmt2.count2)) | ||
| 518 | return -EFAULT; | ||
| 519 | xcRB->reply_data_length = msg->fmt2.count2; | ||
| 520 | return 0; | ||
| 521 | } | ||
| 522 | |||
| 523 | static int convert_type86_rng(struct zcrypt_device *zdev, | ||
| 524 | struct ap_message *reply, | ||
| 525 | char *buffer) | ||
| 526 | { | ||
| 527 | struct { | ||
| 528 | struct type86_hdr hdr; | ||
| 529 | struct type86_fmt2_ext fmt2; | ||
| 530 | struct CPRBX cprbx; | ||
| 531 | } __attribute__((packed)) *msg = reply->message; | ||
| 532 | char *data = reply->message; | ||
| 533 | |||
| 534 | if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0) | ||
| 535 | return -EINVAL; | ||
| 536 | memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2); | ||
| 537 | return msg->fmt2.count2; | ||
| 538 | } | ||
| 539 | |||
| 540 | static int convert_response_ica(struct zcrypt_device *zdev, | ||
| 541 | struct ap_message *reply, | ||
| 542 | char __user *outputdata, | ||
| 543 | unsigned int outputdatalength) | ||
| 544 | { | ||
| 545 | struct type86x_reply *msg = reply->message; | ||
| 546 | |||
| 547 | /* Response type byte is the second byte in the response. */ | ||
| 548 | switch (((unsigned char *) reply->message)[1]) { | ||
| 549 | case TYPE82_RSP_CODE: | ||
| 550 | case TYPE88_RSP_CODE: | ||
| 551 | return convert_error(zdev, reply); | ||
| 552 | case TYPE86_RSP_CODE: | ||
| 553 | if (msg->cprbx.ccp_rtcode && | ||
| 554 | (msg->cprbx.ccp_rscode == 0x14f) && | ||
| 555 | (outputdatalength > 256)) { | ||
| 556 | if (zdev->max_exp_bit_length <= 17) { | ||
| 557 | zdev->max_exp_bit_length = 17; | ||
| 558 | return -EAGAIN; | ||
| 559 | } else | ||
| 560 | return -EINVAL; | ||
| 561 | } | ||
| 562 | if (msg->hdr.reply_code) | ||
| 563 | return convert_error(zdev, reply); | ||
| 564 | if (msg->cprbx.cprb_ver_id == 0x02) | ||
| 565 | return convert_type86_ica(zdev, reply, | ||
| 566 | outputdata, outputdatalength); | ||
| 567 | /* Fall through, no break, incorrect cprb version is an unknown | ||
| 568 | * response */ | ||
| 569 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 570 | zdev->online = 0; | ||
| 571 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 572 | } | ||
| 573 | } | ||
| 574 | |||
| 575 | static int convert_response_xcrb(struct zcrypt_device *zdev, | ||
| 576 | struct ap_message *reply, | ||
| 577 | struct ica_xcRB *xcRB) | ||
| 578 | { | ||
| 579 | struct type86x_reply *msg = reply->message; | ||
| 580 | |||
| 581 | /* Response type byte is the second byte in the response. */ | ||
| 582 | switch (((unsigned char *) reply->message)[1]) { | ||
| 583 | case TYPE82_RSP_CODE: | ||
| 584 | case TYPE88_RSP_CODE: | ||
| 585 | xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ | ||
| 586 | return convert_error(zdev, reply); | ||
| 587 | case TYPE86_RSP_CODE: | ||
| 588 | if (msg->hdr.reply_code) { | ||
| 589 | memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32)); | ||
| 590 | return convert_error(zdev, reply); | ||
| 591 | } | ||
| 592 | if (msg->cprbx.cprb_ver_id == 0x02) | ||
| 593 | return convert_type86_xcrb(zdev, reply, xcRB); | ||
| 594 | /* Fall through, no break, incorrect cprb version is an unknown | ||
| 595 | * response */ | ||
| 596 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 597 | xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ | ||
| 598 | zdev->online = 0; | ||
| 599 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 600 | } | ||
| 601 | } | ||
| 602 | |||
| 603 | static int convert_response_rng(struct zcrypt_device *zdev, | ||
| 604 | struct ap_message *reply, | ||
| 605 | char *data) | ||
| 606 | { | ||
| 607 | struct type86x_reply *msg = reply->message; | ||
| 608 | |||
| 609 | switch (msg->hdr.type) { | ||
| 610 | case TYPE82_RSP_CODE: | ||
| 611 | case TYPE88_RSP_CODE: | ||
| 612 | return -EINVAL; | ||
| 613 | case TYPE86_RSP_CODE: | ||
| 614 | if (msg->hdr.reply_code) | ||
| 615 | return -EINVAL; | ||
| 616 | if (msg->cprbx.cprb_ver_id == 0x02) | ||
| 617 | return convert_type86_rng(zdev, reply, data); | ||
| 618 | /* Fall through, no break, incorrect cprb version is an unknown | ||
| 619 | * response */ | ||
| 620 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 621 | zdev->online = 0; | ||
| 622 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 623 | } | ||
| 624 | } | ||
| 625 | |||
| 626 | /** | ||
| 627 | * This function is called from the AP bus code after a crypto request | ||
| 628 | * "msg" has finished with the reply message "reply". | ||
| 629 | * It is called from tasklet context. | ||
| 630 | * @ap_dev: pointer to the AP device | ||
| 631 | * @msg: pointer to the AP message | ||
| 632 | * @reply: pointer to the AP reply message | ||
| 633 | */ | ||
| 634 | static void zcrypt_pcixcc_receive(struct ap_device *ap_dev, | ||
| 635 | struct ap_message *msg, | ||
| 636 | struct ap_message *reply) | ||
| 637 | { | ||
| 638 | static struct error_hdr error_reply = { | ||
| 639 | .type = TYPE82_RSP_CODE, | ||
| 640 | .reply_code = REP82_ERROR_MACHINE_FAILURE, | ||
| 641 | }; | ||
| 642 | struct response_type *resp_type = | ||
| 643 | (struct response_type *) msg->private; | ||
| 644 | struct type86x_reply *t86r; | ||
| 645 | int length; | ||
| 646 | |||
| 647 | /* Copy the reply message to the request message buffer. */ | ||
| 648 | if (IS_ERR(reply)) { | ||
| 649 | memcpy(msg->message, &error_reply, sizeof(error_reply)); | ||
| 650 | goto out; | ||
| 651 | } | ||
| 652 | t86r = reply->message; | ||
| 653 | if (t86r->hdr.type == TYPE86_RSP_CODE && | ||
| 654 | t86r->cprbx.cprb_ver_id == 0x02) { | ||
| 655 | switch (resp_type->type) { | ||
| 656 | case PCIXCC_RESPONSE_TYPE_ICA: | ||
| 657 | length = sizeof(struct type86x_reply) | ||
| 658 | + t86r->length - 2; | ||
| 659 | length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length); | ||
| 660 | memcpy(msg->message, reply->message, length); | ||
| 661 | break; | ||
| 662 | case PCIXCC_RESPONSE_TYPE_XCRB: | ||
| 663 | length = t86r->fmt2.offset2 + t86r->fmt2.count2; | ||
| 664 | length = min(PCIXCC_MAX_XCRB_MESSAGE_SIZE, length); | ||
| 665 | memcpy(msg->message, reply->message, length); | ||
| 666 | break; | ||
| 667 | default: | ||
| 668 | memcpy(msg->message, &error_reply, sizeof error_reply); | ||
| 669 | } | ||
| 670 | } else | ||
| 671 | memcpy(msg->message, reply->message, sizeof error_reply); | ||
| 672 | out: | ||
| 673 | complete(&(resp_type->work)); | ||
| 674 | } | ||
| 675 | |||
| 676 | static atomic_t zcrypt_step = ATOMIC_INIT(0); | ||
| 677 | |||
| 678 | /** | ||
| 679 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 680 | * device to handle a modexpo request. | ||
| 681 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 682 | * PCIXCC/CEX2C device to the request distributor | ||
| 683 | * @mex: pointer to the modexpo request buffer | ||
| 684 | */ | ||
| 685 | static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev, | ||
| 686 | struct ica_rsa_modexpo *mex) | ||
| 687 | { | ||
| 688 | struct ap_message ap_msg; | ||
| 689 | struct response_type resp_type = { | ||
| 690 | .type = PCIXCC_RESPONSE_TYPE_ICA, | ||
| 691 | }; | ||
| 692 | int rc; | ||
| 693 | |||
| 694 | ap_init_message(&ap_msg); | ||
| 695 | ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); | ||
| 696 | if (!ap_msg.message) | ||
| 697 | return -ENOMEM; | ||
| 698 | ap_msg.receive = zcrypt_pcixcc_receive; | ||
| 699 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 700 | atomic_inc_return(&zcrypt_step); | ||
| 701 | ap_msg.private = &resp_type; | ||
| 702 | rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex); | ||
| 703 | if (rc) | ||
| 704 | goto out_free; | ||
| 705 | init_completion(&resp_type.work); | ||
| 706 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 707 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 708 | if (rc == 0) | ||
| 709 | rc = convert_response_ica(zdev, &ap_msg, mex->outputdata, | ||
| 710 | mex->outputdatalength); | ||
| 711 | else | ||
| 712 | /* Signal pending. */ | ||
| 713 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 714 | out_free: | ||
| 715 | free_page((unsigned long) ap_msg.message); | ||
| 716 | return rc; | ||
| 717 | } | ||
| 718 | |||
| 719 | /** | ||
| 720 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 721 | * device to handle a modexpo_crt request. | ||
| 722 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 723 | * PCIXCC/CEX2C device to the request distributor | ||
| 724 | * @crt: pointer to the modexpoc_crt request buffer | ||
| 725 | */ | ||
| 726 | static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev, | ||
| 727 | struct ica_rsa_modexpo_crt *crt) | ||
| 728 | { | ||
| 729 | struct ap_message ap_msg; | ||
| 730 | struct response_type resp_type = { | ||
| 731 | .type = PCIXCC_RESPONSE_TYPE_ICA, | ||
| 732 | }; | ||
| 733 | int rc; | ||
| 734 | |||
| 735 | ap_init_message(&ap_msg); | ||
| 736 | ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); | ||
| 737 | if (!ap_msg.message) | ||
| 738 | return -ENOMEM; | ||
| 739 | ap_msg.receive = zcrypt_pcixcc_receive; | ||
| 740 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 741 | atomic_inc_return(&zcrypt_step); | ||
| 742 | ap_msg.private = &resp_type; | ||
| 743 | rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt); | ||
| 744 | if (rc) | ||
| 745 | goto out_free; | ||
| 746 | init_completion(&resp_type.work); | ||
| 747 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 748 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 749 | if (rc == 0) | ||
| 750 | rc = convert_response_ica(zdev, &ap_msg, crt->outputdata, | ||
| 751 | crt->outputdatalength); | ||
| 752 | else | ||
| 753 | /* Signal pending. */ | ||
| 754 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 755 | out_free: | ||
| 756 | free_page((unsigned long) ap_msg.message); | ||
| 757 | return rc; | ||
| 758 | } | ||
| 759 | |||
| 760 | /** | ||
| 761 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 762 | * device to handle a send_cprb request. | ||
| 763 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 764 | * PCIXCC/CEX2C device to the request distributor | ||
| 765 | * @xcRB: pointer to the send_cprb request buffer | ||
| 766 | */ | ||
| 767 | static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, | ||
| 768 | struct ica_xcRB *xcRB) | ||
| 769 | { | ||
| 770 | struct ap_message ap_msg; | ||
| 771 | struct response_type resp_type = { | ||
| 772 | .type = PCIXCC_RESPONSE_TYPE_XCRB, | ||
| 773 | }; | ||
| 774 | int rc; | ||
| 775 | |||
| 776 | ap_init_message(&ap_msg); | ||
| 777 | ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL); | ||
| 778 | if (!ap_msg.message) | ||
| 779 | return -ENOMEM; | ||
| 780 | ap_msg.receive = zcrypt_pcixcc_receive; | ||
| 781 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 782 | atomic_inc_return(&zcrypt_step); | ||
| 783 | ap_msg.private = &resp_type; | ||
| 784 | rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB); | ||
| 785 | if (rc) | ||
| 786 | goto out_free; | ||
| 787 | init_completion(&resp_type.work); | ||
| 788 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 789 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 790 | if (rc == 0) | ||
| 791 | rc = convert_response_xcrb(zdev, &ap_msg, xcRB); | ||
| 792 | else | ||
| 793 | /* Signal pending. */ | ||
| 794 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 795 | out_free: | ||
| 796 | kzfree(ap_msg.message); | ||
| 797 | return rc; | ||
| 798 | } | ||
| 799 | |||
| 800 | /** | ||
| 801 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 802 | * device to generate random data. | ||
| 803 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 804 | * PCIXCC/CEX2C device to the request distributor | ||
| 805 | * @buffer: pointer to a memory page to return random data | ||
| 806 | */ | ||
| 807 | |||
| 808 | static long zcrypt_pcixcc_rng(struct zcrypt_device *zdev, | ||
| 809 | char *buffer) | ||
| 810 | { | ||
| 811 | struct ap_message ap_msg; | ||
| 812 | struct response_type resp_type = { | ||
| 813 | .type = PCIXCC_RESPONSE_TYPE_XCRB, | ||
| 814 | }; | ||
| 815 | int rc; | ||
| 816 | |||
| 817 | ap_init_message(&ap_msg); | ||
| 818 | ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL); | ||
| 819 | if (!ap_msg.message) | ||
| 820 | return -ENOMEM; | ||
| 821 | ap_msg.receive = zcrypt_pcixcc_receive; | ||
| 822 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 823 | atomic_inc_return(&zcrypt_step); | ||
| 824 | ap_msg.private = &resp_type; | ||
| 825 | rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE); | ||
| 826 | init_completion(&resp_type.work); | ||
| 827 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 828 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 829 | if (rc == 0) | ||
| 830 | rc = convert_response_rng(zdev, &ap_msg, buffer); | ||
| 831 | else | ||
| 832 | /* Signal pending. */ | ||
| 833 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 834 | kfree(ap_msg.message); | ||
| 835 | return rc; | ||
| 836 | } | ||
| 837 | |||
| 838 | /** | ||
| 839 | * The crypto operations for a PCIXCC/CEX2C card. | ||
| 840 | */ | ||
| 841 | static struct zcrypt_ops zcrypt_pcixcc_ops = { | ||
| 842 | .rsa_modexpo = zcrypt_pcixcc_modexpo, | ||
| 843 | .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt, | ||
| 844 | .send_cprb = zcrypt_pcixcc_send_cprb, | ||
| 845 | }; | ||
| 846 | |||
| 847 | static struct zcrypt_ops zcrypt_pcixcc_with_rng_ops = { | ||
| 848 | .rsa_modexpo = zcrypt_pcixcc_modexpo, | ||
| 849 | .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt, | ||
| 850 | .send_cprb = zcrypt_pcixcc_send_cprb, | ||
| 851 | .rng = zcrypt_pcixcc_rng, | ||
| 852 | }; | ||
| 853 | |||
| 854 | /** | ||
| 855 | * Micro-code detection function. Its sends a message to a pcixcc card | 95 | * Micro-code detection function. Its sends a message to a pcixcc card |
| 856 | * to find out the microcode level. | 96 | * to find out the microcode level. |
| 857 | * @ap_dev: pointer to the AP device. | 97 | * @ap_dev: pointer to the AP device. |
| @@ -1083,9 +323,11 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) | |||
| 1083 | return rc; | 323 | return rc; |
| 1084 | } | 324 | } |
| 1085 | if (rc) | 325 | if (rc) |
| 1086 | zdev->ops = &zcrypt_pcixcc_with_rng_ops; | 326 | zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, |
| 327 | MSGTYPE06_VARIANT_DEFAULT); | ||
| 1087 | else | 328 | else |
| 1088 | zdev->ops = &zcrypt_pcixcc_ops; | 329 | zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, |
| 330 | MSGTYPE06_VARIANT_NORNG); | ||
| 1089 | ap_dev->reply = &zdev->reply; | 331 | ap_dev->reply = &zdev->reply; |
| 1090 | ap_dev->private = zdev; | 332 | ap_dev->private = zdev; |
| 1091 | rc = zcrypt_device_register(zdev); | 333 | rc = zcrypt_device_register(zdev); |
| @@ -1095,6 +337,7 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) | |||
| 1095 | 337 | ||
| 1096 | out_free: | 338 | out_free: |
| 1097 | ap_dev->private = NULL; | 339 | ap_dev->private = NULL; |
| 340 | zcrypt_msgtype_release(zdev->ops); | ||
| 1098 | zcrypt_device_free(zdev); | 341 | zcrypt_device_free(zdev); |
| 1099 | return rc; | 342 | return rc; |
| 1100 | } | 343 | } |
| @@ -1106,8 +349,10 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) | |||
| 1106 | static void zcrypt_pcixcc_remove(struct ap_device *ap_dev) | 349 | static void zcrypt_pcixcc_remove(struct ap_device *ap_dev) |
| 1107 | { | 350 | { |
| 1108 | struct zcrypt_device *zdev = ap_dev->private; | 351 | struct zcrypt_device *zdev = ap_dev->private; |
| 352 | struct zcrypt_ops *zops = zdev->ops; | ||
| 1109 | 353 | ||
| 1110 | zcrypt_device_unregister(zdev); | 354 | zcrypt_device_unregister(zdev); |
| 355 | zcrypt_msgtype_release(zops); | ||
| 1111 | } | 356 | } |
| 1112 | 357 | ||
| 1113 | int __init zcrypt_pcixcc_init(void) | 358 | int __init zcrypt_pcixcc_init(void) |
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h index c7cdf599e46b..eacafc8962f2 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.h +++ b/drivers/s390/crypto/zcrypt_pcixcc.h | |||
| @@ -1,12 +1,13 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * zcrypt 2.1.0 | 2 | * zcrypt 2.1.0 |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2001, 2006 | 4 | * Copyright IBM Corp. 2001, 2012 |
| 5 | * Author(s): Robert Burroughs | 5 | * Author(s): Robert Burroughs |
| 6 | * Eric Rossman (edrossma@us.ibm.com) | 6 | * Eric Rossman (edrossma@us.ibm.com) |
| 7 | * | 7 | * |
| 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) |
| 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 10 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 10 | * | 11 | * |
| 11 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 7a8b09612c41..cf6da7fafe54 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
| @@ -2993,7 +2993,7 @@ static void qeth_get_trap_id(struct qeth_card *card, struct qeth_trap_id *tid) | |||
| 2993 | struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info; | 2993 | struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info; |
| 2994 | struct sysinfo_3_2_2 *info322 = (struct sysinfo_3_2_2 *)info; | 2994 | struct sysinfo_3_2_2 *info322 = (struct sysinfo_3_2_2 *)info; |
| 2995 | struct ccw_dev_id ccwid; | 2995 | struct ccw_dev_id ccwid; |
| 2996 | int level, rc; | 2996 | int level; |
| 2997 | 2997 | ||
| 2998 | tid->chpid = card->info.chpid; | 2998 | tid->chpid = card->info.chpid; |
| 2999 | ccw_device_get_id(CARD_RDEV(card), &ccwid); | 2999 | ccw_device_get_id(CARD_RDEV(card), &ccwid); |
| @@ -3001,17 +3001,10 @@ static void qeth_get_trap_id(struct qeth_card *card, struct qeth_trap_id *tid) | |||
| 3001 | tid->devno = ccwid.devno; | 3001 | tid->devno = ccwid.devno; |
| 3002 | if (!info) | 3002 | if (!info) |
| 3003 | return; | 3003 | return; |
| 3004 | 3004 | level = stsi(NULL, 0, 0, 0); | |
| 3005 | rc = stsi(NULL, 0, 0, 0); | 3005 | if ((level >= 2) && (stsi(info222, 2, 2, 2) == 0)) |
| 3006 | if (rc == -ENOSYS) | ||
| 3007 | level = rc; | ||
| 3008 | else | ||
| 3009 | level = (((unsigned int) rc) >> 28); | ||
| 3010 | |||
| 3011 | if ((level >= 2) && (stsi(info222, 2, 2, 2) != -ENOSYS)) | ||
| 3012 | tid->lparnr = info222->lpar_number; | 3006 | tid->lparnr = info222->lpar_number; |
| 3013 | 3007 | if ((level >= 3) && (stsi(info322, 3, 2, 2) == 0)) { | |
| 3014 | if ((level >= 3) && (stsi(info322, 3, 2, 2) != -ENOSYS)) { | ||
| 3015 | EBCASC(info322->vm[0].name, sizeof(info322->vm[0].name)); | 3008 | EBCASC(info322->vm[0].name, sizeof(info322->vm[0].name)); |
| 3016 | memcpy(tid->vmname, info322->vm[0].name, sizeof(tid->vmname)); | 3009 | memcpy(tid->vmname, info322->vm[0].name, sizeof(tid->vmname)); |
| 3017 | } | 3010 | } |
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 25417d0e7acb..0bcacf71aef8 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c | |||
| @@ -2888,7 +2888,7 @@ ahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1) | |||
| 2888 | ahd_outb(ahd, CLRINT, CLRSCSIINT); | 2888 | ahd_outb(ahd, CLRINT, CLRSCSIINT); |
| 2889 | ahd_unpause(ahd); | 2889 | ahd_unpause(ahd); |
| 2890 | } else { | 2890 | } else { |
| 2891 | printk("Reseting Channel for LQI Phase error\n"); | 2891 | printk("Resetting Channel for LQI Phase error\n"); |
| 2892 | ahd_dump_card_state(ahd); | 2892 | ahd_dump_card_state(ahd); |
| 2893 | ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); | 2893 | ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); |
| 2894 | } | 2894 | } |
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index 8cdb79c2fcdf..21ad2902e5ce 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c | |||
| @@ -5587,7 +5587,7 @@ static bfa_status_t bfa_dconf_flash_write(struct bfa_dconf_mod_s *dconf); | |||
| 5587 | static void bfa_dconf_init_cb(void *arg, bfa_status_t status); | 5587 | static void bfa_dconf_init_cb(void *arg, bfa_status_t status); |
| 5588 | 5588 | ||
| 5589 | /* | 5589 | /* |
| 5590 | * Begining state of dconf module. Waiting for an event to start. | 5590 | * Beginning state of dconf module. Waiting for an event to start. |
| 5591 | */ | 5591 | */ |
| 5592 | static void | 5592 | static void |
| 5593 | bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event) | 5593 | bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event) |
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index 1a99d4b5b50f..7b916e04ca56 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h | |||
| @@ -530,7 +530,7 @@ struct bfa_diag_results_fwping { | |||
| 530 | 530 | ||
| 531 | struct bfa_diag_qtest_result_s { | 531 | struct bfa_diag_qtest_result_s { |
| 532 | u32 status; | 532 | u32 status; |
| 533 | u16 count; /* sucessful queue test count */ | 533 | u16 count; /* successful queue test count */ |
| 534 | u8 queue; | 534 | u8 queue; |
| 535 | u8 rsvd; /* 64-bit align */ | 535 | u8 rsvd; /* 64-bit align */ |
| 536 | }; | 536 | }; |
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index ae1cb7639d99..e0558656c646 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c | |||
| @@ -908,7 +908,7 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event, | |||
| 908 | return; | 908 | return; |
| 909 | 909 | ||
| 910 | default: | 910 | default: |
| 911 | printk(KERN_ERR PFX "Unkonwn netevent %ld", event); | 911 | printk(KERN_ERR PFX "Unknown netevent %ld", event); |
| 912 | return; | 912 | return; |
| 913 | } | 913 | } |
| 914 | 914 | ||
| @@ -1738,7 +1738,7 @@ static int bnx2fc_ulp_get_stats(void *handle) | |||
| 1738 | /** | 1738 | /** |
| 1739 | * bnx2fc_ulp_start - cnic callback to initialize & start adapter instance | 1739 | * bnx2fc_ulp_start - cnic callback to initialize & start adapter instance |
| 1740 | * | 1740 | * |
| 1741 | * @handle: transport handle pointing to adapter struture | 1741 | * @handle: transport handle pointing to adapter structure |
| 1742 | * | 1742 | * |
| 1743 | * This function maps adapter structure to pcidev structure and initiates | 1743 | * This function maps adapter structure to pcidev structure and initiates |
| 1744 | * firmware handshake to enable/initialize on-chip FCoE components. | 1744 | * firmware handshake to enable/initialize on-chip FCoE components. |
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index 33d6630529de..91eec60252ee 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c | |||
| @@ -1264,6 +1264,9 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba) | |||
| 1264 | int rc = 0; | 1264 | int rc = 0; |
| 1265 | u64 mask64; | 1265 | u64 mask64; |
| 1266 | 1266 | ||
| 1267 | memset(&iscsi_init, 0x00, sizeof(struct iscsi_kwqe_init1)); | ||
| 1268 | memset(&iscsi_init2, 0x00, sizeof(struct iscsi_kwqe_init2)); | ||
| 1269 | |||
| 1267 | bnx2i_adjust_qp_size(hba); | 1270 | bnx2i_adjust_qp_size(hba); |
| 1268 | 1271 | ||
| 1269 | iscsi_init.flags = | 1272 | iscsi_init.flags = |
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h index d3e4d7c6f577..fbf6f0f4b0dd 100644 --- a/drivers/scsi/gdth.h +++ b/drivers/scsi/gdth.h | |||
| @@ -49,15 +49,6 @@ | |||
| 49 | /* GDT_ISA */ | 49 | /* GDT_ISA */ |
| 50 | #define GDT2_ID 0x0120941c /* GDT2000/2020 */ | 50 | #define GDT2_ID 0x0120941c /* GDT2000/2020 */ |
| 51 | 51 | ||
| 52 | /* vendor ID, device IDs (PCI) */ | ||
| 53 | /* these defines should already exist in <linux/pci.h> */ | ||
| 54 | #ifndef PCI_VENDOR_ID_VORTEX | ||
| 55 | #define PCI_VENDOR_ID_VORTEX 0x1119 /* PCI controller vendor ID */ | ||
| 56 | #endif | ||
| 57 | #ifndef PCI_VENDOR_ID_INTEL | ||
| 58 | #define PCI_VENDOR_ID_INTEL 0x8086 | ||
| 59 | #endif | ||
| 60 | |||
| 61 | #ifndef PCI_DEVICE_ID_VORTEX_GDT60x0 | 52 | #ifndef PCI_DEVICE_ID_VORTEX_GDT60x0 |
| 62 | /* GDT_PCI */ | 53 | /* GDT_PCI */ |
| 63 | #define PCI_DEVICE_ID_VORTEX_GDT60x0 0 /* GDT6000/6020/6050 */ | 54 | #define PCI_DEVICE_ID_VORTEX_GDT60x0 0 /* GDT6000/6020/6050 */ |
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 796482badf13..2b4261cb7742 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c | |||
| @@ -1315,8 +1315,9 @@ static void complete_scsi_command(struct CommandList *cp) | |||
| 1315 | } | 1315 | } |
| 1316 | break; | 1316 | break; |
| 1317 | case CMD_PROTOCOL_ERR: | 1317 | case CMD_PROTOCOL_ERR: |
| 1318 | cmd->result = DID_ERROR << 16; | ||
| 1318 | dev_warn(&h->pdev->dev, "cp %p has " | 1319 | dev_warn(&h->pdev->dev, "cp %p has " |
| 1319 | "protocol error \n", cp); | 1320 | "protocol error\n", cp); |
| 1320 | break; | 1321 | break; |
| 1321 | case CMD_HARDWARE_ERR: | 1322 | case CMD_HARDWARE_ERR: |
| 1322 | cmd->result = DID_ERROR << 16; | 1323 | cmd->result = DID_ERROR << 16; |
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index b91fa7aed37c..0a2c5a8ebb82 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c | |||
| @@ -192,7 +192,7 @@ static const struct ipr_chip_t ipr_chip[] = { | |||
| 192 | { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] } | 192 | { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] } |
| 193 | }; | 193 | }; |
| 194 | 194 | ||
| 195 | static int ipr_max_bus_speeds [] = { | 195 | static int ipr_max_bus_speeds[] = { |
| 196 | IPR_80MBs_SCSI_RATE, IPR_U160_SCSI_RATE, IPR_U320_SCSI_RATE | 196 | IPR_80MBs_SCSI_RATE, IPR_U160_SCSI_RATE, IPR_U320_SCSI_RATE |
| 197 | }; | 197 | }; |
| 198 | 198 | ||
| @@ -562,7 +562,7 @@ static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd, | |||
| 562 | trace_entry->u.add_data = add_data; | 562 | trace_entry->u.add_data = add_data; |
| 563 | } | 563 | } |
| 564 | #else | 564 | #else |
| 565 | #define ipr_trc_hook(ipr_cmd, type, add_data) do { } while(0) | 565 | #define ipr_trc_hook(ipr_cmd, type, add_data) do { } while (0) |
| 566 | #endif | 566 | #endif |
| 567 | 567 | ||
| 568 | /** | 568 | /** |
| @@ -1002,7 +1002,7 @@ static void ipr_send_hcam(struct ipr_ioa_cfg *ioa_cfg, u8 type, | |||
| 1002 | **/ | 1002 | **/ |
| 1003 | static void ipr_update_ata_class(struct ipr_resource_entry *res, unsigned int proto) | 1003 | static void ipr_update_ata_class(struct ipr_resource_entry *res, unsigned int proto) |
| 1004 | { | 1004 | { |
| 1005 | switch(proto) { | 1005 | switch (proto) { |
| 1006 | case IPR_PROTO_SATA: | 1006 | case IPR_PROTO_SATA: |
| 1007 | case IPR_PROTO_SAS_STP: | 1007 | case IPR_PROTO_SAS_STP: |
| 1008 | res->ata_class = ATA_DEV_ATA; | 1008 | res->ata_class = ATA_DEV_ATA; |
| @@ -3043,7 +3043,7 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) | |||
| 3043 | } | 3043 | } |
| 3044 | 3044 | ||
| 3045 | #else | 3045 | #else |
| 3046 | #define ipr_get_ioa_dump(ioa_cfg, dump) do { } while(0) | 3046 | #define ipr_get_ioa_dump(ioa_cfg, dump) do { } while (0) |
| 3047 | #endif | 3047 | #endif |
| 3048 | 3048 | ||
| 3049 | /** | 3049 | /** |
| @@ -3055,7 +3055,7 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) | |||
| 3055 | **/ | 3055 | **/ |
| 3056 | static void ipr_release_dump(struct kref *kref) | 3056 | static void ipr_release_dump(struct kref *kref) |
| 3057 | { | 3057 | { |
| 3058 | struct ipr_dump *dump = container_of(kref,struct ipr_dump,kref); | 3058 | struct ipr_dump *dump = container_of(kref, struct ipr_dump, kref); |
| 3059 | struct ipr_ioa_cfg *ioa_cfg = dump->ioa_cfg; | 3059 | struct ipr_ioa_cfg *ioa_cfg = dump->ioa_cfg; |
| 3060 | unsigned long lock_flags = 0; | 3060 | unsigned long lock_flags = 0; |
| 3061 | int i; | 3061 | int i; |
| @@ -3142,7 +3142,7 @@ restart: | |||
| 3142 | break; | 3142 | break; |
| 3143 | } | 3143 | } |
| 3144 | } | 3144 | } |
| 3145 | } while(did_work); | 3145 | } while (did_work); |
| 3146 | 3146 | ||
| 3147 | list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { | 3147 | list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { |
| 3148 | if (res->add_to_ml) { | 3148 | if (res->add_to_ml) { |
| @@ -3268,7 +3268,7 @@ static ssize_t ipr_show_log_level(struct device *dev, | |||
| 3268 | * number of bytes printed to buffer | 3268 | * number of bytes printed to buffer |
| 3269 | **/ | 3269 | **/ |
| 3270 | static ssize_t ipr_store_log_level(struct device *dev, | 3270 | static ssize_t ipr_store_log_level(struct device *dev, |
| 3271 | struct device_attribute *attr, | 3271 | struct device_attribute *attr, |
| 3272 | const char *buf, size_t count) | 3272 | const char *buf, size_t count) |
| 3273 | { | 3273 | { |
| 3274 | struct Scsi_Host *shost = class_to_shost(dev); | 3274 | struct Scsi_Host *shost = class_to_shost(dev); |
| @@ -3315,7 +3315,7 @@ static ssize_t ipr_store_diagnostics(struct device *dev, | |||
| 3315 | return -EACCES; | 3315 | return -EACCES; |
| 3316 | 3316 | ||
| 3317 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); | 3317 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); |
| 3318 | while(ioa_cfg->in_reset_reload) { | 3318 | while (ioa_cfg->in_reset_reload) { |
| 3319 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); | 3319 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); |
| 3320 | wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); | 3320 | wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); |
| 3321 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); | 3321 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); |
| @@ -3682,7 +3682,7 @@ static int ipr_update_ioa_ucode(struct ipr_ioa_cfg *ioa_cfg, | |||
| 3682 | unsigned long lock_flags; | 3682 | unsigned long lock_flags; |
| 3683 | 3683 | ||
| 3684 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); | 3684 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); |
| 3685 | while(ioa_cfg->in_reset_reload) { | 3685 | while (ioa_cfg->in_reset_reload) { |
| 3686 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); | 3686 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); |
| 3687 | wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); | 3687 | wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); |
| 3688 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); | 3688 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); |
| @@ -3746,7 +3746,7 @@ static ssize_t ipr_store_update_fw(struct device *dev, | |||
| 3746 | len = snprintf(fname, 99, "%s", buf); | 3746 | len = snprintf(fname, 99, "%s", buf); |
| 3747 | fname[len-1] = '\0'; | 3747 | fname[len-1] = '\0'; |
| 3748 | 3748 | ||
| 3749 | if(request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) { | 3749 | if (request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) { |
| 3750 | dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname); | 3750 | dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname); |
| 3751 | return -EIO; | 3751 | return -EIO; |
| 3752 | } | 3752 | } |
| @@ -4612,7 +4612,7 @@ static int ipr_slave_alloc(struct scsi_device *sdev) | |||
| 4612 | * Return value: | 4612 | * Return value: |
| 4613 | * SUCCESS / FAILED | 4613 | * SUCCESS / FAILED |
| 4614 | **/ | 4614 | **/ |
| 4615 | static int __ipr_eh_host_reset(struct scsi_cmnd * scsi_cmd) | 4615 | static int __ipr_eh_host_reset(struct scsi_cmnd *scsi_cmd) |
| 4616 | { | 4616 | { |
| 4617 | struct ipr_ioa_cfg *ioa_cfg; | 4617 | struct ipr_ioa_cfg *ioa_cfg; |
| 4618 | int rc; | 4618 | int rc; |
| @@ -4634,7 +4634,7 @@ static int __ipr_eh_host_reset(struct scsi_cmnd * scsi_cmd) | |||
| 4634 | return rc; | 4634 | return rc; |
| 4635 | } | 4635 | } |
| 4636 | 4636 | ||
| 4637 | static int ipr_eh_host_reset(struct scsi_cmnd * cmd) | 4637 | static int ipr_eh_host_reset(struct scsi_cmnd *cmd) |
| 4638 | { | 4638 | { |
| 4639 | int rc; | 4639 | int rc; |
| 4640 | 4640 | ||
| @@ -4701,7 +4701,7 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg, | |||
| 4701 | } | 4701 | } |
| 4702 | 4702 | ||
| 4703 | LEAVE; | 4703 | LEAVE; |
| 4704 | return (IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0); | 4704 | return IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0; |
| 4705 | } | 4705 | } |
| 4706 | 4706 | ||
| 4707 | /** | 4707 | /** |
| @@ -4725,7 +4725,7 @@ static int ipr_sata_reset(struct ata_link *link, unsigned int *classes, | |||
| 4725 | 4725 | ||
| 4726 | ENTER; | 4726 | ENTER; |
| 4727 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); | 4727 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); |
| 4728 | while(ioa_cfg->in_reset_reload) { | 4728 | while (ioa_cfg->in_reset_reload) { |
| 4729 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); | 4729 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); |
| 4730 | wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); | 4730 | wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); |
| 4731 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); | 4731 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); |
| @@ -4753,7 +4753,7 @@ static int ipr_sata_reset(struct ata_link *link, unsigned int *classes, | |||
| 4753 | * Return value: | 4753 | * Return value: |
| 4754 | * SUCCESS / FAILED | 4754 | * SUCCESS / FAILED |
| 4755 | **/ | 4755 | **/ |
| 4756 | static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) | 4756 | static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd) |
| 4757 | { | 4757 | { |
| 4758 | struct ipr_cmnd *ipr_cmd; | 4758 | struct ipr_cmnd *ipr_cmd; |
| 4759 | struct ipr_ioa_cfg *ioa_cfg; | 4759 | struct ipr_ioa_cfg *ioa_cfg; |
| @@ -4811,10 +4811,10 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) | |||
| 4811 | res->resetting_device = 0; | 4811 | res->resetting_device = 0; |
| 4812 | 4812 | ||
| 4813 | LEAVE; | 4813 | LEAVE; |
| 4814 | return (rc ? FAILED : SUCCESS); | 4814 | return rc ? FAILED : SUCCESS; |
| 4815 | } | 4815 | } |
| 4816 | 4816 | ||
| 4817 | static int ipr_eh_dev_reset(struct scsi_cmnd * cmd) | 4817 | static int ipr_eh_dev_reset(struct scsi_cmnd *cmd) |
| 4818 | { | 4818 | { |
| 4819 | int rc; | 4819 | int rc; |
| 4820 | 4820 | ||
| @@ -4910,7 +4910,7 @@ static void ipr_abort_timeout(struct ipr_cmnd *ipr_cmd) | |||
| 4910 | * Return value: | 4910 | * Return value: |
| 4911 | * SUCCESS / FAILED | 4911 | * SUCCESS / FAILED |
| 4912 | **/ | 4912 | **/ |
| 4913 | static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) | 4913 | static int ipr_cancel_op(struct scsi_cmnd *scsi_cmd) |
| 4914 | { | 4914 | { |
| 4915 | struct ipr_cmnd *ipr_cmd; | 4915 | struct ipr_cmnd *ipr_cmd; |
| 4916 | struct ipr_ioa_cfg *ioa_cfg; | 4916 | struct ipr_ioa_cfg *ioa_cfg; |
| @@ -4979,7 +4979,7 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) | |||
| 4979 | res->needs_sync_complete = 1; | 4979 | res->needs_sync_complete = 1; |
| 4980 | 4980 | ||
| 4981 | LEAVE; | 4981 | LEAVE; |
| 4982 | return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS); | 4982 | return IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS; |
| 4983 | } | 4983 | } |
| 4984 | 4984 | ||
| 4985 | /** | 4985 | /** |
| @@ -4989,7 +4989,7 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) | |||
| 4989 | * Return value: | 4989 | * Return value: |
| 4990 | * SUCCESS / FAILED | 4990 | * SUCCESS / FAILED |
| 4991 | **/ | 4991 | **/ |
| 4992 | static int ipr_eh_abort(struct scsi_cmnd * scsi_cmd) | 4992 | static int ipr_eh_abort(struct scsi_cmnd *scsi_cmd) |
| 4993 | { | 4993 | { |
| 4994 | unsigned long flags; | 4994 | unsigned long flags; |
| 4995 | int rc; | 4995 | int rc; |
| @@ -5907,7 +5907,7 @@ static int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) | |||
| 5907 | * Return value: | 5907 | * Return value: |
| 5908 | * pointer to buffer with description string | 5908 | * pointer to buffer with description string |
| 5909 | **/ | 5909 | **/ |
| 5910 | static const char * ipr_ioa_info(struct Scsi_Host *host) | 5910 | static const char *ipr_ioa_info(struct Scsi_Host *host) |
| 5911 | { | 5911 | { |
| 5912 | static char buffer[512]; | 5912 | static char buffer[512]; |
| 5913 | struct ipr_ioa_cfg *ioa_cfg; | 5913 | struct ipr_ioa_cfg *ioa_cfg; |
| @@ -5965,7 +5965,7 @@ static void ipr_ata_phy_reset(struct ata_port *ap) | |||
| 5965 | 5965 | ||
| 5966 | ENTER; | 5966 | ENTER; |
| 5967 | spin_lock_irqsave(ioa_cfg->host->host_lock, flags); | 5967 | spin_lock_irqsave(ioa_cfg->host->host_lock, flags); |
| 5968 | while(ioa_cfg->in_reset_reload) { | 5968 | while (ioa_cfg->in_reset_reload) { |
| 5969 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); | 5969 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); |
| 5970 | wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); | 5970 | wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); |
| 5971 | spin_lock_irqsave(ioa_cfg->host->host_lock, flags); | 5971 | spin_lock_irqsave(ioa_cfg->host->host_lock, flags); |
| @@ -6005,7 +6005,7 @@ static void ipr_ata_post_internal(struct ata_queued_cmd *qc) | |||
| 6005 | unsigned long flags; | 6005 | unsigned long flags; |
| 6006 | 6006 | ||
| 6007 | spin_lock_irqsave(ioa_cfg->host->host_lock, flags); | 6007 | spin_lock_irqsave(ioa_cfg->host->host_lock, flags); |
| 6008 | while(ioa_cfg->in_reset_reload) { | 6008 | while (ioa_cfg->in_reset_reload) { |
| 6009 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); | 6009 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); |
| 6010 | wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); | 6010 | wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); |
| 6011 | spin_lock_irqsave(ioa_cfg->host->host_lock, flags); | 6011 | spin_lock_irqsave(ioa_cfg->host->host_lock, flags); |
| @@ -6330,7 +6330,7 @@ static int ipr_invalid_adapter(struct ipr_ioa_cfg *ioa_cfg) | |||
| 6330 | int i; | 6330 | int i; |
| 6331 | 6331 | ||
| 6332 | if ((ioa_cfg->type == 0x5702) && (ioa_cfg->pdev->revision < 4)) { | 6332 | if ((ioa_cfg->type == 0x5702) && (ioa_cfg->pdev->revision < 4)) { |
| 6333 | for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++){ | 6333 | for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++) { |
| 6334 | if (__is_processor(ipr_blocked_processors[i])) | 6334 | if (__is_processor(ipr_blocked_processors[i])) |
| 6335 | return 1; | 6335 | return 1; |
| 6336 | } | 6336 | } |
| @@ -6608,7 +6608,7 @@ static void ipr_scsi_bus_speed_limit(struct ipr_ioa_cfg *ioa_cfg) | |||
| 6608 | * none | 6608 | * none |
| 6609 | **/ | 6609 | **/ |
| 6610 | static void ipr_modify_ioafp_mode_page_28(struct ipr_ioa_cfg *ioa_cfg, | 6610 | static void ipr_modify_ioafp_mode_page_28(struct ipr_ioa_cfg *ioa_cfg, |
| 6611 | struct ipr_mode_pages *mode_pages) | 6611 | struct ipr_mode_pages *mode_pages) |
| 6612 | { | 6612 | { |
| 6613 | int i, entry_length; | 6613 | int i, entry_length; |
| 6614 | struct ipr_dev_bus_entry *bus; | 6614 | struct ipr_dev_bus_entry *bus; |
| @@ -8022,7 +8022,7 @@ static void ipr_reset_ioa_job(struct ipr_cmnd *ipr_cmd) | |||
| 8022 | ipr_reinit_ipr_cmnd(ipr_cmd); | 8022 | ipr_reinit_ipr_cmnd(ipr_cmd); |
| 8023 | ipr_cmd->job_step_failed = ipr_reset_cmd_failed; | 8023 | ipr_cmd->job_step_failed = ipr_reset_cmd_failed; |
| 8024 | rc = ipr_cmd->job_step(ipr_cmd); | 8024 | rc = ipr_cmd->job_step(ipr_cmd); |
| 8025 | } while(rc == IPR_RC_JOB_CONTINUE); | 8025 | } while (rc == IPR_RC_JOB_CONTINUE); |
| 8026 | } | 8026 | } |
| 8027 | 8027 | ||
| 8028 | /** | 8028 | /** |
| @@ -8283,7 +8283,7 @@ static void ipr_free_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) | |||
| 8283 | } | 8283 | } |
| 8284 | 8284 | ||
| 8285 | if (ioa_cfg->ipr_cmd_pool) | 8285 | if (ioa_cfg->ipr_cmd_pool) |
| 8286 | pci_pool_destroy (ioa_cfg->ipr_cmd_pool); | 8286 | pci_pool_destroy(ioa_cfg->ipr_cmd_pool); |
| 8287 | 8287 | ||
| 8288 | kfree(ioa_cfg->ipr_cmnd_list); | 8288 | kfree(ioa_cfg->ipr_cmnd_list); |
| 8289 | kfree(ioa_cfg->ipr_cmnd_list_dma); | 8289 | kfree(ioa_cfg->ipr_cmnd_list_dma); |
| @@ -8363,8 +8363,8 @@ static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) | |||
| 8363 | dma_addr_t dma_addr; | 8363 | dma_addr_t dma_addr; |
| 8364 | int i; | 8364 | int i; |
| 8365 | 8365 | ||
| 8366 | ioa_cfg->ipr_cmd_pool = pci_pool_create (IPR_NAME, ioa_cfg->pdev, | 8366 | ioa_cfg->ipr_cmd_pool = pci_pool_create(IPR_NAME, ioa_cfg->pdev, |
| 8367 | sizeof(struct ipr_cmnd), 512, 0); | 8367 | sizeof(struct ipr_cmnd), 512, 0); |
| 8368 | 8368 | ||
| 8369 | if (!ioa_cfg->ipr_cmd_pool) | 8369 | if (!ioa_cfg->ipr_cmd_pool) |
| 8370 | return -ENOMEM; | 8370 | return -ENOMEM; |
| @@ -8378,7 +8378,7 @@ static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) | |||
| 8378 | } | 8378 | } |
| 8379 | 8379 | ||
| 8380 | for (i = 0; i < IPR_NUM_CMD_BLKS; i++) { | 8380 | for (i = 0; i < IPR_NUM_CMD_BLKS; i++) { |
| 8381 | ipr_cmd = pci_pool_alloc (ioa_cfg->ipr_cmd_pool, GFP_KERNEL, &dma_addr); | 8381 | ipr_cmd = pci_pool_alloc(ioa_cfg->ipr_cmd_pool, GFP_KERNEL, &dma_addr); |
| 8382 | 8382 | ||
| 8383 | if (!ipr_cmd) { | 8383 | if (!ipr_cmd) { |
| 8384 | ipr_free_cmd_blks(ioa_cfg); | 8384 | ipr_free_cmd_blks(ioa_cfg); |
| @@ -8964,7 +8964,7 @@ static void ipr_scan_vsets(struct ipr_ioa_cfg *ioa_cfg) | |||
| 8964 | int target, lun; | 8964 | int target, lun; |
| 8965 | 8965 | ||
| 8966 | for (target = 0; target < IPR_MAX_NUM_TARGETS_PER_BUS; target++) | 8966 | for (target = 0; target < IPR_MAX_NUM_TARGETS_PER_BUS; target++) |
| 8967 | for (lun = 0; lun < IPR_MAX_NUM_VSET_LUNS_PER_TARGET; lun++ ) | 8967 | for (lun = 0; lun < IPR_MAX_NUM_VSET_LUNS_PER_TARGET; lun++) |
| 8968 | scsi_add_device(ioa_cfg->host, IPR_VSET_BUS, target, lun); | 8968 | scsi_add_device(ioa_cfg->host, IPR_VSET_BUS, target, lun); |
| 8969 | } | 8969 | } |
| 8970 | 8970 | ||
| @@ -9010,7 +9010,7 @@ static void __ipr_remove(struct pci_dev *pdev) | |||
| 9010 | ENTER; | 9010 | ENTER; |
| 9011 | 9011 | ||
| 9012 | spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); | 9012 | spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); |
| 9013 | while(ioa_cfg->in_reset_reload) { | 9013 | while (ioa_cfg->in_reset_reload) { |
| 9014 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); | 9014 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); |
| 9015 | wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); | 9015 | wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); |
| 9016 | spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); | 9016 | spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); |
| @@ -9139,7 +9139,7 @@ static void ipr_shutdown(struct pci_dev *pdev) | |||
| 9139 | unsigned long lock_flags = 0; | 9139 | unsigned long lock_flags = 0; |
| 9140 | 9140 | ||
| 9141 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); | 9141 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); |
| 9142 | while(ioa_cfg->in_reset_reload) { | 9142 | while (ioa_cfg->in_reset_reload) { |
| 9143 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); | 9143 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); |
| 9144 | wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); | 9144 | wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); |
| 9145 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); | 9145 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); |
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 45385f531649..b334fdc1726a 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c | |||
| @@ -492,7 +492,7 @@ static void sci_controller_process_completions(struct isci_host *ihost) | |||
| 492 | u32 event_cycle; | 492 | u32 event_cycle; |
| 493 | 493 | ||
| 494 | dev_dbg(&ihost->pdev->dev, | 494 | dev_dbg(&ihost->pdev->dev, |
| 495 | "%s: completion queue begining get:0x%08x\n", | 495 | "%s: completion queue beginning get:0x%08x\n", |
| 496 | __func__, | 496 | __func__, |
| 497 | ihost->completion_queue_get); | 497 | ihost->completion_queue_get); |
| 498 | 498 | ||
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 92c1d86d1fc6..9be45a2b2232 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c | |||
| @@ -222,7 +222,7 @@ static struct sas_domain_function_template isci_transport_ops = { | |||
| 222 | * @isci_host: This parameter specifies the lldd specific wrapper for the | 222 | * @isci_host: This parameter specifies the lldd specific wrapper for the |
| 223 | * libsas sas_ha struct. | 223 | * libsas sas_ha struct. |
| 224 | * | 224 | * |
| 225 | * This method returns an error code indicating sucess or failure. The user | 225 | * This method returns an error code indicating success or failure. The user |
| 226 | * should check for possible memory allocation error return otherwise, a zero | 226 | * should check for possible memory allocation error return otherwise, a zero |
| 227 | * indicates success. | 227 | * indicates success. |
| 228 | */ | 228 | */ |
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c index 2fb85bf75449..13098b09a824 100644 --- a/drivers/scsi/isci/port.c +++ b/drivers/scsi/isci/port.c | |||
| @@ -212,7 +212,7 @@ static void isci_port_link_up(struct isci_host *isci_host, | |||
| 212 | memcpy(iphy->sas_phy.attached_sas_addr, | 212 | memcpy(iphy->sas_phy.attached_sas_addr, |
| 213 | iphy->frame_rcvd.iaf.sas_addr, SAS_ADDR_SIZE); | 213 | iphy->frame_rcvd.iaf.sas_addr, SAS_ADDR_SIZE); |
| 214 | } else { | 214 | } else { |
| 215 | dev_err(&isci_host->pdev->dev, "%s: unkown target\n", __func__); | 215 | dev_err(&isci_host->pdev->dev, "%s: unknown target\n", __func__); |
| 216 | success = false; | 216 | success = false; |
| 217 | } | 217 | } |
| 218 | 218 | ||
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 7a0431c73493..c1bafc3f3fb1 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c | |||
| @@ -2240,7 +2240,7 @@ static enum sci_status atapi_data_tc_completion_handler(struct isci_request *ire | |||
| 2240 | status = ireq->sci_status; | 2240 | status = ireq->sci_status; |
| 2241 | sci_change_state(&idev->sm, SCI_STP_DEV_ATAPI_ERROR); | 2241 | sci_change_state(&idev->sm, SCI_STP_DEV_ATAPI_ERROR); |
| 2242 | } else { | 2242 | } else { |
| 2243 | /* If receiving any non-sucess TC status, no UF | 2243 | /* If receiving any non-success TC status, no UF |
| 2244 | * received yet, then an UF for the status fis | 2244 | * received yet, then an UF for the status fis |
| 2245 | * is coming after (XXX: suspect this is | 2245 | * is coming after (XXX: suspect this is |
| 2246 | * actually a protocol error or a bug like the | 2246 | * actually a protocol error or a bug like the |
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 6bc74eb012c9..b6f19a1db780 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c | |||
| @@ -532,7 +532,7 @@ int isci_task_abort_task(struct sas_task *task) | |||
| 532 | /* The request has already completed and there | 532 | /* The request has already completed and there |
| 533 | * is nothing to do here other than to set the task | 533 | * is nothing to do here other than to set the task |
| 534 | * done bit, and indicate that the task abort function | 534 | * done bit, and indicate that the task abort function |
| 535 | * was sucessful. | 535 | * was successful. |
| 536 | */ | 536 | */ |
| 537 | spin_lock_irqsave(&task->task_state_lock, flags); | 537 | spin_lock_irqsave(&task->task_state_lock, flags); |
| 538 | task->task_state_flags |= SAS_TASK_STATE_DONE; | 538 | task->task_state_flags |= SAS_TASK_STATE_DONE; |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index a979e2765cf6..628a703abddb 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
| @@ -6607,7 +6607,7 @@ out_error: | |||
| 6607 | * we just use some constant number as place holder. | 6607 | * we just use some constant number as place holder. |
| 6608 | * | 6608 | * |
| 6609 | * Return codes | 6609 | * Return codes |
| 6610 | * 0 - sucessful | 6610 | * 0 - successful |
| 6611 | * -ENOMEM - No availble memory | 6611 | * -ENOMEM - No availble memory |
| 6612 | * -EIO - The mailbox failed to complete successfully. | 6612 | * -EIO - The mailbox failed to complete successfully. |
| 6613 | **/ | 6613 | **/ |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 9cbd20b1328b..0e7e144507b2 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
| @@ -4739,7 +4739,7 @@ lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, | |||
| 4739 | * is attached to. | 4739 | * is attached to. |
| 4740 | * | 4740 | * |
| 4741 | * Return codes | 4741 | * Return codes |
| 4742 | * 0 - sucessful | 4742 | * 0 - successful |
| 4743 | * otherwise - failed to retrieve physical port name | 4743 | * otherwise - failed to retrieve physical port name |
| 4744 | **/ | 4744 | **/ |
| 4745 | static int | 4745 | static int |
| @@ -15209,7 +15209,7 @@ lpfc_check_next_fcf_pri_level(struct lpfc_hba *phba) | |||
| 15209 | /* | 15209 | /* |
| 15210 | * if next_fcf_pri was not set above and the list is not empty then | 15210 | * if next_fcf_pri was not set above and the list is not empty then |
| 15211 | * we have failed flogis on all of them. So reset flogi failed | 15211 | * we have failed flogis on all of them. So reset flogi failed |
| 15212 | * and start at the begining. | 15212 | * and start at the beginning. |
| 15213 | */ | 15213 | */ |
| 15214 | if (!next_fcf_pri && !list_empty(&phba->fcf.fcf_pri_list)) { | 15214 | if (!next_fcf_pri && !list_empty(&phba->fcf.fcf_pri_list)) { |
| 15215 | list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) { | 15215 | list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) { |
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 97825f116954..76ad72d32c3f 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c | |||
| @@ -305,12 +305,11 @@ mega_query_adapter(adapter_t *adapter) | |||
| 305 | 305 | ||
| 306 | adapter->host->sg_tablesize = adapter->sglen; | 306 | adapter->host->sg_tablesize = adapter->sglen; |
| 307 | 307 | ||
| 308 | |||
| 309 | /* use HP firmware and bios version encoding | 308 | /* use HP firmware and bios version encoding |
| 310 | Note: fw_version[0|1] and bios_version[0|1] were originally shifted | 309 | Note: fw_version[0|1] and bios_version[0|1] were originally shifted |
| 311 | right 8 bits making them zero. This 0 value was hardcoded to fix | 310 | right 8 bits making them zero. This 0 value was hardcoded to fix |
| 312 | sparse warnings. */ | 311 | sparse warnings. */ |
| 313 | if (adapter->product_info.subsysvid == HP_SUBSYS_VID) { | 312 | if (adapter->product_info.subsysvid == PCI_VENDOR_ID_HP) { |
| 314 | sprintf (adapter->fw_version, "%c%d%d.%d%d", | 313 | sprintf (adapter->fw_version, "%c%d%d.%d%d", |
| 315 | adapter->product_info.fw_version[2], | 314 | adapter->product_info.fw_version[2], |
| 316 | 0, | 315 | 0, |
| @@ -4716,7 +4715,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 4716 | * support, since this firmware cannot handle 64 bit | 4715 | * support, since this firmware cannot handle 64 bit |
| 4717 | * addressing | 4716 | * addressing |
| 4718 | */ | 4717 | */ |
| 4719 | if ((subsysvid == HP_SUBSYS_VID) && | 4718 | if ((subsysvid == PCI_VENDOR_ID_HP) && |
| 4720 | ((subsysid == 0x60E7) || (subsysid == 0x60E8))) { | 4719 | ((subsysid == 0x60E7) || (subsysid == 0x60E8))) { |
| 4721 | /* | 4720 | /* |
| 4722 | * which firmware | 4721 | * which firmware |
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index 9a7897f8ca43..4fb2adf6b80d 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h | |||
| @@ -45,45 +45,10 @@ | |||
| 45 | 45 | ||
| 46 | #define MAX_DEV_TYPE 32 | 46 | #define MAX_DEV_TYPE 32 |
| 47 | 47 | ||
| 48 | #ifndef PCI_VENDOR_ID_LSI_LOGIC | ||
| 49 | #define PCI_VENDOR_ID_LSI_LOGIC 0x1000 | ||
| 50 | #endif | ||
| 51 | |||
| 52 | #ifndef PCI_VENDOR_ID_AMI | ||
| 53 | #define PCI_VENDOR_ID_AMI 0x101E | ||
| 54 | #endif | ||
| 55 | |||
| 56 | #ifndef PCI_VENDOR_ID_DELL | ||
| 57 | #define PCI_VENDOR_ID_DELL 0x1028 | ||
| 58 | #endif | ||
| 59 | |||
| 60 | #ifndef PCI_VENDOR_ID_INTEL | ||
| 61 | #define PCI_VENDOR_ID_INTEL 0x8086 | ||
| 62 | #endif | ||
| 63 | |||
| 64 | #ifndef PCI_DEVICE_ID_AMI_MEGARAID | ||
| 65 | #define PCI_DEVICE_ID_AMI_MEGARAID 0x9010 | ||
| 66 | #endif | ||
| 67 | |||
| 68 | #ifndef PCI_DEVICE_ID_AMI_MEGARAID2 | ||
| 69 | #define PCI_DEVICE_ID_AMI_MEGARAID2 0x9060 | ||
| 70 | #endif | ||
| 71 | |||
| 72 | #ifndef PCI_DEVICE_ID_AMI_MEGARAID3 | ||
| 73 | #define PCI_DEVICE_ID_AMI_MEGARAID3 0x1960 | ||
| 74 | #endif | ||
| 75 | |||
| 76 | #define PCI_DEVICE_ID_DISCOVERY 0x000E | 48 | #define PCI_DEVICE_ID_DISCOVERY 0x000E |
| 77 | #define PCI_DEVICE_ID_PERC4_DI 0x000F | 49 | #define PCI_DEVICE_ID_PERC4_DI 0x000F |
| 78 | #define PCI_DEVICE_ID_PERC4_QC_VERDE 0x0407 | 50 | #define PCI_DEVICE_ID_PERC4_QC_VERDE 0x0407 |
| 79 | 51 | ||
| 80 | /* Sub-System Vendor IDs */ | ||
| 81 | #define AMI_SUBSYS_VID 0x101E | ||
| 82 | #define DELL_SUBSYS_VID 0x1028 | ||
| 83 | #define HP_SUBSYS_VID 0x103C | ||
| 84 | #define LSI_SUBSYS_VID 0x1000 | ||
| 85 | #define INTEL_SUBSYS_VID 0x8086 | ||
| 86 | |||
| 87 | #define HBA_SIGNATURE 0x3344 | 52 | #define HBA_SIGNATURE 0x3344 |
| 88 | #define HBA_SIGNATURE_471 0xCCCC | 53 | #define HBA_SIGNATURE_471 0xCCCC |
| 89 | #define HBA_SIGNATURE_64BIT 0x0299 | 54 | #define HBA_SIGNATURE_64BIT 0x0299 |
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index dc27598785e5..ed38454228c6 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c | |||
| @@ -4066,7 +4066,6 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 4066 | spin_lock_init(&instance->cmd_pool_lock); | 4066 | spin_lock_init(&instance->cmd_pool_lock); |
| 4067 | spin_lock_init(&instance->hba_lock); | 4067 | spin_lock_init(&instance->hba_lock); |
| 4068 | spin_lock_init(&instance->completion_lock); | 4068 | spin_lock_init(&instance->completion_lock); |
| 4069 | spin_lock_init(&poll_aen_lock); | ||
| 4070 | 4069 | ||
| 4071 | mutex_init(&instance->aen_mutex); | 4070 | mutex_init(&instance->aen_mutex); |
| 4072 | mutex_init(&instance->reset_mutex); | 4071 | mutex_init(&instance->reset_mutex); |
| @@ -5392,6 +5391,8 @@ static int __init megasas_init(void) | |||
| 5392 | printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION, | 5391 | printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION, |
| 5393 | MEGASAS_EXT_VERSION); | 5392 | MEGASAS_EXT_VERSION); |
| 5394 | 5393 | ||
| 5394 | spin_lock_init(&poll_aen_lock); | ||
| 5395 | |||
| 5395 | support_poll_for_event = 2; | 5396 | support_poll_for_event = 2; |
| 5396 | support_device_change = 1; | 5397 | support_device_change = 1; |
| 5397 | 5398 | ||
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 9d46fcbe7755..9d5a56c4b332 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c | |||
| @@ -1209,6 +1209,13 @@ _base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc) | |||
| 1209 | u16 message_control; | 1209 | u16 message_control; |
| 1210 | 1210 | ||
| 1211 | 1211 | ||
| 1212 | /* Check whether controller SAS2008 B0 controller, | ||
| 1213 | if it is SAS2008 B0 controller use IO-APIC instead of MSIX */ | ||
| 1214 | if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 && | ||
| 1215 | ioc->pdev->revision == 0x01) { | ||
| 1216 | return -EINVAL; | ||
| 1217 | } | ||
| 1218 | |||
| 1212 | base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); | 1219 | base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); |
| 1213 | if (!base) { | 1220 | if (!base) { |
| 1214 | dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not " | 1221 | dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not " |
| @@ -2424,10 +2431,13 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
| 2424 | } | 2431 | } |
| 2425 | 2432 | ||
| 2426 | /* command line tunables for max controller queue depth */ | 2433 | /* command line tunables for max controller queue depth */ |
| 2427 | if (max_queue_depth != -1) | 2434 | if (max_queue_depth != -1 && max_queue_depth != 0) { |
| 2428 | max_request_credit = (max_queue_depth < facts->RequestCredit) | 2435 | max_request_credit = min_t(u16, max_queue_depth + |
| 2429 | ? max_queue_depth : facts->RequestCredit; | 2436 | ioc->hi_priority_depth + ioc->internal_depth, |
| 2430 | else | 2437 | facts->RequestCredit); |
| 2438 | if (max_request_credit > MAX_HBA_QUEUE_DEPTH) | ||
| 2439 | max_request_credit = MAX_HBA_QUEUE_DEPTH; | ||
| 2440 | } else | ||
| 2431 | max_request_credit = min_t(u16, facts->RequestCredit, | 2441 | max_request_credit = min_t(u16, facts->RequestCredit, |
| 2432 | MAX_HBA_QUEUE_DEPTH); | 2442 | MAX_HBA_QUEUE_DEPTH); |
| 2433 | 2443 | ||
| @@ -2502,7 +2512,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
| 2502 | /* set the scsi host can_queue depth | 2512 | /* set the scsi host can_queue depth |
| 2503 | * with some internal commands that could be outstanding | 2513 | * with some internal commands that could be outstanding |
| 2504 | */ | 2514 | */ |
| 2505 | ioc->shost->can_queue = ioc->scsiio_depth - (2); | 2515 | ioc->shost->can_queue = ioc->scsiio_depth; |
| 2506 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host: " | 2516 | dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host: " |
| 2507 | "can_queue depth (%d)\n", ioc->name, ioc->shost->can_queue)); | 2517 | "can_queue depth (%d)\n", ioc->name, ioc->shost->can_queue)); |
| 2508 | 2518 | ||
diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index 88cf1db21a79..783edc7c6b98 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c | |||
| @@ -122,7 +122,7 @@ static struct mvumi_res *mvumi_alloc_mem_resource(struct mvumi_hba *mhba, | |||
| 122 | 122 | ||
| 123 | if (!res) { | 123 | if (!res) { |
| 124 | dev_err(&mhba->pdev->dev, | 124 | dev_err(&mhba->pdev->dev, |
| 125 | "Failed to allocate memory for resouce manager.\n"); | 125 | "Failed to allocate memory for resource manager.\n"); |
| 126 | return NULL; | 126 | return NULL; |
| 127 | } | 127 | } |
| 128 | 128 | ||
| @@ -1007,13 +1007,13 @@ static int mvumi_handshake(struct mvumi_hba *mhba) | |||
| 1007 | tmp |= INT_MAP_COMAOUT | INT_MAP_COMAERR; | 1007 | tmp |= INT_MAP_COMAOUT | INT_MAP_COMAERR; |
| 1008 | iowrite32(tmp, regs + CPU_ENPOINTA_MASK_REG); | 1008 | iowrite32(tmp, regs + CPU_ENPOINTA_MASK_REG); |
| 1009 | iowrite32(mhba->list_num_io, mhba->ib_shadow); | 1009 | iowrite32(mhba->list_num_io, mhba->ib_shadow); |
| 1010 | /* Set InBound List Avaliable count shadow */ | 1010 | /* Set InBound List Available count shadow */ |
| 1011 | iowrite32(lower_32_bits(mhba->ib_shadow_phys), | 1011 | iowrite32(lower_32_bits(mhba->ib_shadow_phys), |
| 1012 | regs + CLA_INB_AVAL_COUNT_BASEL); | 1012 | regs + CLA_INB_AVAL_COUNT_BASEL); |
| 1013 | iowrite32(upper_32_bits(mhba->ib_shadow_phys), | 1013 | iowrite32(upper_32_bits(mhba->ib_shadow_phys), |
| 1014 | regs + CLA_INB_AVAL_COUNT_BASEH); | 1014 | regs + CLA_INB_AVAL_COUNT_BASEH); |
| 1015 | 1015 | ||
| 1016 | /* Set OutBound List Avaliable count shadow */ | 1016 | /* Set OutBound List Available count shadow */ |
| 1017 | iowrite32((mhba->list_num_io-1) | CL_POINTER_TOGGLE, | 1017 | iowrite32((mhba->list_num_io-1) | CL_POINTER_TOGGLE, |
| 1018 | mhba->ob_shadow); | 1018 | mhba->ob_shadow); |
| 1019 | iowrite32(lower_32_bits(mhba->ob_shadow_phys), regs + 0x5B0); | 1019 | iowrite32(lower_32_bits(mhba->ob_shadow_phys), regs + 0x5B0); |
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index c75ca26298d6..79243b76d17e 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
| @@ -803,7 +803,7 @@ static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, | |||
| 803 | iscsi_stats_dma); | 803 | iscsi_stats_dma); |
| 804 | if (ret != QLA_SUCCESS) { | 804 | if (ret != QLA_SUCCESS) { |
| 805 | ql4_printk(KERN_ERR, ha, | 805 | ql4_printk(KERN_ERR, ha, |
| 806 | "Unable to retreive iscsi stats\n"); | 806 | "Unable to retrieve iscsi stats\n"); |
| 807 | goto free_stats; | 807 | goto free_stats; |
| 808 | } | 808 | } |
| 809 | 809 | ||
| @@ -4338,7 +4338,7 @@ static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha, | |||
| 4338 | return QLA_ERROR; | 4338 | return QLA_ERROR; |
| 4339 | 4339 | ||
| 4340 | /* For multi sessions, driver generates the ISID, so do not compare | 4340 | /* For multi sessions, driver generates the ISID, so do not compare |
| 4341 | * ISID in reset path since it would be a comparision between the | 4341 | * ISID in reset path since it would be a comparison between the |
| 4342 | * driver generated ISID and firmware generated ISID. This could | 4342 | * driver generated ISID and firmware generated ISID. This could |
| 4343 | * lead to adding duplicated DDBs in the list as driver generated | 4343 | * lead to adding duplicated DDBs in the list as driver generated |
| 4344 | * ISID would not match firmware generated ISID. | 4344 | * ISID would not match firmware generated ISID. |
| @@ -5326,7 +5326,7 @@ static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha) | |||
| 5326 | } | 5326 | } |
| 5327 | } | 5327 | } |
| 5328 | /** | 5328 | /** |
| 5329 | * qla4xxx_remove_adapter - calback function to remove adapter. | 5329 | * qla4xxx_remove_adapter - callback function to remove adapter. |
| 5330 | * @pci_dev: PCI device pointer | 5330 | * @pci_dev: PCI device pointer |
| 5331 | **/ | 5331 | **/ |
| 5332 | static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) | 5332 | static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) |
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 4a6381c87253..de2337f255a7 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c | |||
| @@ -42,6 +42,8 @@ | |||
| 42 | 42 | ||
| 43 | #include <trace/events/scsi.h> | 43 | #include <trace/events/scsi.h> |
| 44 | 44 | ||
| 45 | static void scsi_eh_done(struct scsi_cmnd *scmd); | ||
| 46 | |||
| 45 | #define SENSE_TIMEOUT (10*HZ) | 47 | #define SENSE_TIMEOUT (10*HZ) |
| 46 | 48 | ||
| 47 | /* | 49 | /* |
| @@ -241,6 +243,14 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) | |||
| 241 | if (! scsi_command_normalize_sense(scmd, &sshdr)) | 243 | if (! scsi_command_normalize_sense(scmd, &sshdr)) |
| 242 | return FAILED; /* no valid sense data */ | 244 | return FAILED; /* no valid sense data */ |
| 243 | 245 | ||
| 246 | if (scmd->cmnd[0] == TEST_UNIT_READY && scmd->scsi_done != scsi_eh_done) | ||
| 247 | /* | ||
| 248 | * nasty: for mid-layer issued TURs, we need to return the | ||
| 249 | * actual sense data without any recovery attempt. For eh | ||
| 250 | * issued ones, we need to try to recover and interpret | ||
| 251 | */ | ||
| 252 | return SUCCESS; | ||
| 253 | |||
| 244 | if (scsi_sense_is_deferred(&sshdr)) | 254 | if (scsi_sense_is_deferred(&sshdr)) |
| 245 | return NEEDS_RETRY; | 255 | return NEEDS_RETRY; |
| 246 | 256 | ||
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ffd77739ae3e..faa790fba134 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
| @@ -776,7 +776,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) | |||
| 776 | } | 776 | } |
| 777 | 777 | ||
| 778 | if (req->cmd_type == REQ_TYPE_BLOCK_PC) { /* SG_IO ioctl from block level */ | 778 | if (req->cmd_type == REQ_TYPE_BLOCK_PC) { /* SG_IO ioctl from block level */ |
| 779 | req->errors = result; | ||
| 780 | if (result) { | 779 | if (result) { |
| 781 | if (sense_valid && req->sense) { | 780 | if (sense_valid && req->sense) { |
| 782 | /* | 781 | /* |
| @@ -792,6 +791,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) | |||
| 792 | if (!sense_deferred) | 791 | if (!sense_deferred) |
| 793 | error = __scsi_error_from_host_byte(cmd, result); | 792 | error = __scsi_error_from_host_byte(cmd, result); |
| 794 | } | 793 | } |
| 794 | /* | ||
| 795 | * __scsi_error_from_host_byte may have reset the host_byte | ||
| 796 | */ | ||
| 797 | req->errors = cmd->result; | ||
| 795 | 798 | ||
| 796 | req->resid_len = scsi_get_resid(cmd); | 799 | req->resid_len = scsi_get_resid(cmd); |
| 797 | 800 | ||
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 56a93794c470..d947ffc20ceb 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
| @@ -764,6 +764,16 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, | |||
| 764 | sdev->model = (char *) (sdev->inquiry + 16); | 764 | sdev->model = (char *) (sdev->inquiry + 16); |
| 765 | sdev->rev = (char *) (sdev->inquiry + 32); | 765 | sdev->rev = (char *) (sdev->inquiry + 32); |
| 766 | 766 | ||
| 767 | if (strncmp(sdev->vendor, "ATA ", 8) == 0) { | ||
| 768 | /* | ||
| 769 | * sata emulation layer device. This is a hack to work around | ||
| 770 | * the SATL power management specifications which state that | ||
| 771 | * when the SATL detects the device has gone into standby | ||
| 772 | * mode, it shall respond with NOT READY. | ||
| 773 | */ | ||
| 774 | sdev->allow_restart = 1; | ||
| 775 | } | ||
| 776 | |||
| 767 | if (*bflags & BLIST_ISROM) { | 777 | if (*bflags & BLIST_ISROM) { |
| 768 | sdev->type = TYPE_ROM; | 778 | sdev->type = TYPE_ROM; |
| 769 | sdev->removable = 1; | 779 | sdev->removable = 1; |
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index c7030fbee79c..3e79a2f00042 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c | |||
| @@ -331,7 +331,7 @@ static void virtscsi_map_sgl(struct scatterlist *sg, unsigned int *p_idx, | |||
| 331 | int i; | 331 | int i; |
| 332 | 332 | ||
| 333 | for_each_sg(table->sgl, sg_elem, table->nents, i) | 333 | for_each_sg(table->sgl, sg_elem, table->nents, i) |
| 334 | sg_set_buf(&sg[idx++], sg_virt(sg_elem), sg_elem->length); | 334 | sg[idx++] = *sg_elem; |
| 335 | 335 | ||
| 336 | *p_idx = idx; | 336 | *p_idx = idx; |
| 337 | } | 337 | } |
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index 4411d4224401..20b3a483c2cc 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c | |||
| @@ -295,7 +295,7 @@ static void ll_adapter_reset(const struct pvscsi_adapter *adapter) | |||
| 295 | 295 | ||
| 296 | static void ll_bus_reset(const struct pvscsi_adapter *adapter) | 296 | static void ll_bus_reset(const struct pvscsi_adapter *adapter) |
| 297 | { | 297 | { |
| 298 | dev_dbg(pvscsi_dev(adapter), "Reseting bus on %p\n", adapter); | 298 | dev_dbg(pvscsi_dev(adapter), "Resetting bus on %p\n", adapter); |
| 299 | 299 | ||
| 300 | pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_BUS, NULL, 0); | 300 | pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_BUS, NULL, 0); |
| 301 | } | 301 | } |
| @@ -304,7 +304,7 @@ static void ll_device_reset(const struct pvscsi_adapter *adapter, u32 target) | |||
| 304 | { | 304 | { |
| 305 | struct PVSCSICmdDescResetDevice cmd = { 0 }; | 305 | struct PVSCSICmdDescResetDevice cmd = { 0 }; |
| 306 | 306 | ||
| 307 | dev_dbg(pvscsi_dev(adapter), "Reseting device: target=%u\n", target); | 307 | dev_dbg(pvscsi_dev(adapter), "Resetting device: target=%u\n", target); |
| 308 | 308 | ||
| 309 | cmd.target = target; | 309 | cmd.target = target; |
| 310 | 310 | ||
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 32c26d795ed0..8f32a1323a79 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c | |||
| @@ -355,7 +355,7 @@ int __init register_intc_controller(struct intc_desc *desc) | |||
| 355 | if (unlikely(res)) { | 355 | if (unlikely(res)) { |
| 356 | if (res == -EEXIST) { | 356 | if (res == -EEXIST) { |
| 357 | res = irq_domain_associate(d->domain, | 357 | res = irq_domain_associate(d->domain, |
| 358 | irq, irq); | 358 | irq2, irq2); |
| 359 | if (unlikely(res)) { | 359 | if (unlikely(res)) { |
| 360 | pr_err("domain association " | 360 | pr_err("domain association " |
| 361 | "failure\n"); | 361 | "failure\n"); |
diff --git a/drivers/sh/pfc/pinctrl.c b/drivers/sh/pfc/pinctrl.c index 2804eaae804e..0646bf6e7889 100644 --- a/drivers/sh/pfc/pinctrl.c +++ b/drivers/sh/pfc/pinctrl.c | |||
| @@ -208,10 +208,13 @@ static int sh_pfc_gpio_request_enable(struct pinctrl_dev *pctldev, | |||
| 208 | 208 | ||
| 209 | break; | 209 | break; |
| 210 | case PINMUX_TYPE_GPIO: | 210 | case PINMUX_TYPE_GPIO: |
| 211 | case PINMUX_TYPE_INPUT: | ||
| 212 | case PINMUX_TYPE_OUTPUT: | ||
| 211 | break; | 213 | break; |
| 212 | default: | 214 | default: |
| 213 | pr_err("Unsupported mux type (%d), bailing...\n", pinmux_type); | 215 | pr_err("Unsupported mux type (%d), bailing...\n", pinmux_type); |
| 214 | return -ENOTSUPP; | 216 | ret = -ENOTSUPP; |
| 217 | goto err; | ||
| 215 | } | 218 | } |
| 216 | 219 | ||
| 217 | ret = 0; | 220 | ret = 0; |
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c index 5784c8799616..4de66d1cfe51 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c | |||
| @@ -475,7 +475,7 @@ static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw) | |||
| 475 | /* | 475 | /* |
| 476 | * due to an spi error we consider transfer as done, | 476 | * due to an spi error we consider transfer as done, |
| 477 | * so mask all events until before next transfer start | 477 | * so mask all events until before next transfer start |
| 478 | * and stop the possibly running dma immediatelly | 478 | * and stop the possibly running dma immediately |
| 479 | */ | 479 | */ |
| 480 | au1550_spi_mask_ack_all(hw); | 480 | au1550_spi_mask_ack_all(hw); |
| 481 | au1xxx_dbdma_stop(hw->dma_rx_ch); | 481 | au1xxx_dbdma_stop(hw->dma_rx_ch); |
diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c index 1fe51198a622..6555ecd07302 100644 --- a/drivers/spi/spi-bfin-sport.c +++ b/drivers/spi/spi-bfin-sport.c | |||
| @@ -467,7 +467,7 @@ bfin_sport_spi_pump_transfers(unsigned long data) | |||
| 467 | dev_dbg(drv_data->dev, "IO write error!\n"); | 467 | dev_dbg(drv_data->dev, "IO write error!\n"); |
| 468 | drv_data->state = ERROR_STATE; | 468 | drv_data->state = ERROR_STATE; |
| 469 | } else { | 469 | } else { |
| 470 | /* Update total byte transfered */ | 470 | /* Update total byte transferred */ |
| 471 | message->actual_length += transfer->len; | 471 | message->actual_length += transfer->len; |
| 472 | /* Move to next transfer of this msg */ | 472 | /* Move to next transfer of this msg */ |
| 473 | drv_data->state = bfin_sport_spi_next_transfer(drv_data); | 473 | drv_data->state = bfin_sport_spi_next_transfer(drv_data); |
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index 698018fd992b..9d9071b730be 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c | |||
| @@ -129,7 +129,7 @@ static int tiny_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) | |||
| 129 | unsigned int i; | 129 | unsigned int i; |
| 130 | 130 | ||
| 131 | if (hw->irq >= 0) { | 131 | if (hw->irq >= 0) { |
| 132 | /* use intrrupt driven data transfer */ | 132 | /* use interrupt driven data transfer */ |
| 133 | hw->len = t->len; | 133 | hw->len = t->len; |
| 134 | hw->txp = t->tx_buf; | 134 | hw->txp = t->tx_buf; |
| 135 | hw->rxp = t->rx_buf; | 135 | hw->rxp = t->rx_buf; |
diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 75ac9d48ef46..7a85f22b6474 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c | |||
| @@ -101,7 +101,7 @@ struct spi_ppc4xx_regs { | |||
| 101 | u8 dummy; | 101 | u8 dummy; |
| 102 | /* | 102 | /* |
| 103 | * Clock divisor modulus register | 103 | * Clock divisor modulus register |
| 104 | * This uses the follwing formula: | 104 | * This uses the following formula: |
| 105 | * SCPClkOut = OPBCLK/(4(CDM + 1)) | 105 | * SCPClkOut = OPBCLK/(4(CDM + 1)) |
| 106 | * or | 106 | * or |
| 107 | * CDM = (OPBCLK/4*SCPClkOut) - 1 | 107 | * CDM = (OPBCLK/4*SCPClkOut) - 1 |
| @@ -201,7 +201,7 @@ static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t) | |||
| 201 | return -EINVAL; | 201 | return -EINVAL; |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | /* Write new configration */ | 204 | /* Write new configuration */ |
| 205 | out_8(&hw->regs->mode, cs->mode); | 205 | out_8(&hw->regs->mode, cs->mode); |
| 206 | 206 | ||
| 207 | /* Set the clock */ | 207 | /* Set the clock */ |
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index cd56dcf46320..1284c9b74653 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c | |||
| @@ -505,7 +505,7 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) | |||
| 505 | } | 505 | } |
| 506 | 506 | ||
| 507 | if (unlikely(pspi->max_speed_hz == 0)) { | 507 | if (unlikely(pspi->max_speed_hz == 0)) { |
| 508 | dev_err(&pspi->dev, "%s pch_spi_tranfer maxspeed=%d\n", | 508 | dev_err(&pspi->dev, "%s pch_spi_transfer maxspeed=%d\n", |
| 509 | __func__, pspi->max_speed_hz); | 509 | __func__, pspi->max_speed_hz); |
| 510 | retval = -EINVAL; | 510 | retval = -EINVAL; |
| 511 | goto err_out; | 511 | goto err_out; |
diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h index d0cafd637199..f2ffd963f1c3 100644 --- a/drivers/staging/android/android_alarm.h +++ b/drivers/staging/android/android_alarm.h | |||
| @@ -51,10 +51,12 @@ enum android_alarm_return_flags { | |||
| 51 | #define ANDROID_ALARM_WAIT _IO('a', 1) | 51 | #define ANDROID_ALARM_WAIT _IO('a', 1) |
| 52 | 52 | ||
| 53 | #define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size) | 53 | #define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size) |
| 54 | #define ALARM_IOR(c, type, size) _IOR('a', (c) | ((type) << 4), size) | ||
| 55 | |||
| 54 | /* Set alarm */ | 56 | /* Set alarm */ |
| 55 | #define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec) | 57 | #define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec) |
| 56 | #define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec) | 58 | #define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec) |
| 57 | #define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec) | 59 | #define ANDROID_ALARM_GET_TIME(type) ALARM_IOR(4, type, struct timespec) |
| 58 | #define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec) | 60 | #define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec) |
| 59 | #define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0))) | 61 | #define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0))) |
| 60 | #define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4) | 62 | #define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4) |
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c index 6c81e377262c..cc8931fde839 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200.c +++ b/drivers/staging/comedi/drivers/amplc_dio200.c | |||
| @@ -1412,6 +1412,13 @@ static int __devinit dio200_attach_pci(struct comedi_device *dev, | |||
| 1412 | dev_err(dev->class_dev, "BUG! cannot determine board type!\n"); | 1412 | dev_err(dev->class_dev, "BUG! cannot determine board type!\n"); |
| 1413 | return -EINVAL; | 1413 | return -EINVAL; |
| 1414 | } | 1414 | } |
| 1415 | /* | ||
| 1416 | * Need to 'get' the PCI device to match the 'put' in dio200_detach(). | ||
| 1417 | * TODO: Remove the pci_dev_get() and matching pci_dev_put() once | ||
| 1418 | * support for manual attachment of PCI devices via dio200_attach() | ||
| 1419 | * has been removed. | ||
| 1420 | */ | ||
| 1421 | pci_dev_get(pci_dev); | ||
| 1415 | return dio200_pci_common_attach(dev, pci_dev); | 1422 | return dio200_pci_common_attach(dev, pci_dev); |
| 1416 | } | 1423 | } |
| 1417 | 1424 | ||
diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c index aabba9886b7d..f50287903038 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236.c +++ b/drivers/staging/comedi/drivers/amplc_pc236.c | |||
| @@ -565,6 +565,13 @@ static int __devinit pc236_attach_pci(struct comedi_device *dev, | |||
| 565 | dev_err(dev->class_dev, "BUG! cannot determine board type!\n"); | 565 | dev_err(dev->class_dev, "BUG! cannot determine board type!\n"); |
| 566 | return -EINVAL; | 566 | return -EINVAL; |
| 567 | } | 567 | } |
| 568 | /* | ||
| 569 | * Need to 'get' the PCI device to match the 'put' in pc236_detach(). | ||
| 570 | * TODO: Remove the pci_dev_get() and matching pci_dev_put() once | ||
| 571 | * support for manual attachment of PCI devices via pc236_attach() | ||
| 572 | * has been removed. | ||
| 573 | */ | ||
| 574 | pci_dev_get(pci_dev); | ||
| 568 | return pc236_pci_common_attach(dev, pci_dev); | 575 | return pc236_pci_common_attach(dev, pci_dev); |
| 569 | } | 576 | } |
| 570 | 577 | ||
diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c index 40ec1ffebba6..8191c4e28e0a 100644 --- a/drivers/staging/comedi/drivers/amplc_pc263.c +++ b/drivers/staging/comedi/drivers/amplc_pc263.c | |||
| @@ -298,6 +298,13 @@ static int __devinit pc263_attach_pci(struct comedi_device *dev, | |||
| 298 | dev_err(dev->class_dev, "BUG! cannot determine board type!\n"); | 298 | dev_err(dev->class_dev, "BUG! cannot determine board type!\n"); |
| 299 | return -EINVAL; | 299 | return -EINVAL; |
| 300 | } | 300 | } |
| 301 | /* | ||
| 302 | * Need to 'get' the PCI device to match the 'put' in pc263_detach(). | ||
| 303 | * TODO: Remove the pci_dev_get() and matching pci_dev_put() once | ||
| 304 | * support for manual attachment of PCI devices via pc263_attach() | ||
| 305 | * has been removed. | ||
| 306 | */ | ||
| 307 | pci_dev_get(pci_dev); | ||
| 301 | return pc263_pci_common_attach(dev, pci_dev); | 308 | return pc263_pci_common_attach(dev, pci_dev); |
| 302 | } | 309 | } |
| 303 | 310 | ||
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index 4e17f13e57f6..8bf109e7bb05 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c | |||
| @@ -1503,6 +1503,13 @@ pci224_attach_pci(struct comedi_device *dev, struct pci_dev *pci_dev) | |||
| 1503 | DRIVER_NAME ": BUG! cannot determine board type!\n"); | 1503 | DRIVER_NAME ": BUG! cannot determine board type!\n"); |
| 1504 | return -EINVAL; | 1504 | return -EINVAL; |
| 1505 | } | 1505 | } |
| 1506 | /* | ||
| 1507 | * Need to 'get' the PCI device to match the 'put' in pci224_detach(). | ||
| 1508 | * TODO: Remove the pci_dev_get() and matching pci_dev_put() once | ||
| 1509 | * support for manual attachment of PCI devices via pci224_attach() | ||
| 1510 | * has been removed. | ||
| 1511 | */ | ||
| 1512 | pci_dev_get(pci_dev); | ||
| 1506 | return pci224_attach_common(dev, pci_dev, NULL); | 1513 | return pci224_attach_common(dev, pci_dev, NULL); |
| 1507 | } | 1514 | } |
| 1508 | 1515 | ||
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 1b67d0c61fa7..66e74bd12267 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c | |||
| @@ -2925,6 +2925,13 @@ static int __devinit pci230_attach_pci(struct comedi_device *dev, | |||
| 2925 | "amplc_pci230: BUG! cannot determine board type!\n"); | 2925 | "amplc_pci230: BUG! cannot determine board type!\n"); |
| 2926 | return -EINVAL; | 2926 | return -EINVAL; |
| 2927 | } | 2927 | } |
| 2928 | /* | ||
| 2929 | * Need to 'get' the PCI device to match the 'put' in pci230_detach(). | ||
| 2930 | * TODO: Remove the pci_dev_get() and matching pci_dev_put() once | ||
| 2931 | * support for manual attachment of PCI devices via pci230_attach() | ||
| 2932 | * has been removed. | ||
| 2933 | */ | ||
| 2934 | pci_dev_get(pci_dev); | ||
| 2928 | return pci230_attach_common(dev, pci_dev); | 2935 | return pci230_attach_common(dev, pci_dev); |
| 2929 | } | 2936 | } |
| 2930 | 2937 | ||
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index 874e02e47668..67a914a10b55 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c | |||
| @@ -378,7 +378,7 @@ das08jr_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, | |||
| 378 | int chan; | 378 | int chan; |
| 379 | 379 | ||
| 380 | lsb = data[0] & 0xff; | 380 | lsb = data[0] & 0xff; |
| 381 | msb = (data[0] >> 8) & 0xf; | 381 | msb = (data[0] >> 8) & 0xff; |
| 382 | 382 | ||
| 383 | chan = CR_CHAN(insn->chanspec); | 383 | chan = CR_CHAN(insn->chanspec); |
| 384 | 384 | ||
| @@ -623,7 +623,7 @@ static const struct das08_board_struct das08_boards[] = { | |||
| 623 | .ai = das08_ai_rinsn, | 623 | .ai = das08_ai_rinsn, |
| 624 | .ai_nbits = 16, | 624 | .ai_nbits = 16, |
| 625 | .ai_pg = das08_pg_none, | 625 | .ai_pg = das08_pg_none, |
| 626 | .ai_encoding = das08_encode12, | 626 | .ai_encoding = das08_encode16, |
| 627 | .ao = das08jr_ao_winsn, | 627 | .ao = das08jr_ao_winsn, |
| 628 | .ao_nbits = 16, | 628 | .ao_nbits = 16, |
| 629 | .di = das08jr_di_rbits, | 629 | .di = das08jr_di_rbits, |
| @@ -922,6 +922,13 @@ das08_attach_pci(struct comedi_device *dev, struct pci_dev *pdev) | |||
| 922 | dev_err(dev->class_dev, "BUG! cannot determine board type!\n"); | 922 | dev_err(dev->class_dev, "BUG! cannot determine board type!\n"); |
| 923 | return -EINVAL; | 923 | return -EINVAL; |
| 924 | } | 924 | } |
| 925 | /* | ||
| 926 | * Need to 'get' the PCI device to match the 'put' in das08_detach(). | ||
| 927 | * TODO: Remove the pci_dev_get() and matching pci_dev_put() once | ||
| 928 | * support for manual attachment of PCI devices via das08_attach() | ||
| 929 | * has been removed. | ||
| 930 | */ | ||
| 931 | pci_dev_get(pdev); | ||
| 925 | return das08_pci_attach_common(dev, pdev); | 932 | return das08_pci_attach_common(dev, pdev); |
| 926 | } | 933 | } |
| 927 | 934 | ||
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index 18d108fd967a..f3da59063ed2 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c | |||
| @@ -121,8 +121,10 @@ static int lis3l02dq_get_buffer_element(struct iio_dev *indio_dev, | |||
| 121 | if (rx_array == NULL) | 121 | if (rx_array == NULL) |
| 122 | return -ENOMEM; | 122 | return -ENOMEM; |
| 123 | ret = lis3l02dq_read_all(indio_dev, rx_array); | 123 | ret = lis3l02dq_read_all(indio_dev, rx_array); |
| 124 | if (ret < 0) | 124 | if (ret < 0) { |
| 125 | kfree(rx_array); | ||
| 125 | return ret; | 126 | return ret; |
| 127 | } | ||
| 126 | for (i = 0; i < scan_count; i++) | 128 | for (i = 0; i < scan_count; i++) |
| 127 | data[i] = combine_8_to_16(rx_array[i*4+1], | 129 | data[i] = combine_8_to_16(rx_array[i*4+1], |
| 128 | rx_array[i*4+3]); | 130 | rx_array[i*4+3]); |
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c index 095837285f4f..19a064d649e3 100644 --- a/drivers/staging/iio/adc/ad7192.c +++ b/drivers/staging/iio/adc/ad7192.c | |||
| @@ -647,6 +647,8 @@ static ssize_t ad7192_write_frequency(struct device *dev, | |||
| 647 | ret = strict_strtoul(buf, 10, &lval); | 647 | ret = strict_strtoul(buf, 10, &lval); |
| 648 | if (ret) | 648 | if (ret) |
| 649 | return ret; | 649 | return ret; |
| 650 | if (lval == 0) | ||
| 651 | return -EINVAL; | ||
| 650 | 652 | ||
| 651 | mutex_lock(&indio_dev->mlock); | 653 | mutex_lock(&indio_dev->mlock); |
| 652 | if (iio_buffer_enabled(indio_dev)) { | 654 | if (iio_buffer_enabled(indio_dev)) { |
diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c index 93aa431287ac..eb8e9d69efd3 100644 --- a/drivers/staging/iio/gyro/adis16260_core.c +++ b/drivers/staging/iio/gyro/adis16260_core.c | |||
| @@ -195,6 +195,8 @@ static ssize_t adis16260_write_frequency(struct device *dev, | |||
| 195 | ret = strict_strtol(buf, 10, &val); | 195 | ret = strict_strtol(buf, 10, &val); |
| 196 | if (ret) | 196 | if (ret) |
| 197 | return ret; | 197 | return ret; |
| 198 | if (val == 0) | ||
| 199 | return -EINVAL; | ||
| 198 | 200 | ||
| 199 | mutex_lock(&indio_dev->mlock); | 201 | mutex_lock(&indio_dev->mlock); |
| 200 | if (spi_get_device_id(st->us)) { | 202 | if (spi_get_device_id(st->us)) { |
diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index 1f4c17779b5a..a618327e06ed 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c | |||
| @@ -234,6 +234,8 @@ static ssize_t adis16400_write_frequency(struct device *dev, | |||
| 234 | ret = strict_strtol(buf, 10, &val); | 234 | ret = strict_strtol(buf, 10, &val); |
| 235 | if (ret) | 235 | if (ret) |
| 236 | return ret; | 236 | return ret; |
| 237 | if (val == 0) | ||
| 238 | return -EINVAL; | ||
| 237 | 239 | ||
| 238 | mutex_lock(&indio_dev->mlock); | 240 | mutex_lock(&indio_dev->mlock); |
| 239 | 241 | ||
diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c index f04ece7fbc2f..3ccff189f258 100644 --- a/drivers/staging/iio/meter/ade7753.c +++ b/drivers/staging/iio/meter/ade7753.c | |||
| @@ -425,6 +425,8 @@ static ssize_t ade7753_write_frequency(struct device *dev, | |||
| 425 | ret = strict_strtol(buf, 10, &val); | 425 | ret = strict_strtol(buf, 10, &val); |
| 426 | if (ret) | 426 | if (ret) |
| 427 | return ret; | 427 | return ret; |
| 428 | if (val == 0) | ||
| 429 | return -EINVAL; | ||
| 428 | 430 | ||
| 429 | mutex_lock(&indio_dev->mlock); | 431 | mutex_lock(&indio_dev->mlock); |
| 430 | 432 | ||
diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c index 6cee28a5e877..abb1e9c8d094 100644 --- a/drivers/staging/iio/meter/ade7754.c +++ b/drivers/staging/iio/meter/ade7754.c | |||
| @@ -445,6 +445,8 @@ static ssize_t ade7754_write_frequency(struct device *dev, | |||
| 445 | ret = strict_strtol(buf, 10, &val); | 445 | ret = strict_strtol(buf, 10, &val); |
| 446 | if (ret) | 446 | if (ret) |
| 447 | return ret; | 447 | return ret; |
| 448 | if (val == 0) | ||
| 449 | return -EINVAL; | ||
| 448 | 450 | ||
| 449 | mutex_lock(&indio_dev->mlock); | 451 | mutex_lock(&indio_dev->mlock); |
| 450 | 452 | ||
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c index b3f7e0fa9612..eb0a2a98f388 100644 --- a/drivers/staging/iio/meter/ade7759.c +++ b/drivers/staging/iio/meter/ade7759.c | |||
| @@ -385,6 +385,8 @@ static ssize_t ade7759_write_frequency(struct device *dev, | |||
| 385 | ret = strict_strtol(buf, 10, &val); | 385 | ret = strict_strtol(buf, 10, &val); |
| 386 | if (ret) | 386 | if (ret) |
| 387 | return ret; | 387 | return ret; |
| 388 | if (val == 0) | ||
| 389 | return -EINVAL; | ||
| 388 | 390 | ||
| 389 | mutex_lock(&indio_dev->mlock); | 391 | mutex_lock(&indio_dev->mlock); |
| 390 | 392 | ||
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 695ea35f75b0..d0a7e408efe9 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c | |||
| @@ -837,7 +837,7 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev) | |||
| 837 | } | 837 | } |
| 838 | 838 | ||
| 839 | ret = mfd_add_devices(nvec->dev, -1, nvec_devices, | 839 | ret = mfd_add_devices(nvec->dev, -1, nvec_devices, |
| 840 | ARRAY_SIZE(nvec_devices), base, 0); | 840 | ARRAY_SIZE(nvec_devices), base, 0, NULL); |
| 841 | if (ret) | 841 | if (ret) |
| 842 | dev_err(nvec->dev, "error adding subdevices\n"); | 842 | dev_err(nvec->dev, "error adding subdevices\n"); |
| 843 | 843 | ||
diff --git a/drivers/staging/omapdrm/omap_connector.c b/drivers/staging/omapdrm/omap_connector.c index 5e2856c0e0bb..55e9c8655850 100644 --- a/drivers/staging/omapdrm/omap_connector.c +++ b/drivers/staging/omapdrm/omap_connector.c | |||
| @@ -48,13 +48,20 @@ static inline void copy_timings_omap_to_drm(struct drm_display_mode *mode, | |||
| 48 | mode->vsync_end = mode->vsync_start + timings->vsw; | 48 | mode->vsync_end = mode->vsync_start + timings->vsw; |
| 49 | mode->vtotal = mode->vsync_end + timings->vbp; | 49 | mode->vtotal = mode->vsync_end + timings->vbp; |
| 50 | 50 | ||
| 51 | /* note: whether or not it is interlaced, +/- h/vsync, etc, | 51 | mode->flags = 0; |
| 52 | * which should be set in the mode flags, is not exposed in | 52 | |
| 53 | * the omap_video_timings struct.. but hdmi driver tracks | 53 | if (timings->interlace) |
| 54 | * those separately so all we have to have to set the mode | 54 | mode->flags |= DRM_MODE_FLAG_INTERLACE; |
| 55 | * is the way to recover these timings values, and the | 55 | |
| 56 | * omap_dss_driver would do the rest. | 56 | if (timings->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH) |
| 57 | */ | 57 | mode->flags |= DRM_MODE_FLAG_PHSYNC; |
| 58 | else | ||
| 59 | mode->flags |= DRM_MODE_FLAG_NHSYNC; | ||
| 60 | |||
| 61 | if (timings->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH) | ||
| 62 | mode->flags |= DRM_MODE_FLAG_PVSYNC; | ||
| 63 | else | ||
| 64 | mode->flags |= DRM_MODE_FLAG_NVSYNC; | ||
| 58 | } | 65 | } |
| 59 | 66 | ||
| 60 | static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings, | 67 | static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings, |
| @@ -71,6 +78,22 @@ static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings, | |||
| 71 | timings->vfp = mode->vsync_start - mode->vdisplay; | 78 | timings->vfp = mode->vsync_start - mode->vdisplay; |
| 72 | timings->vsw = mode->vsync_end - mode->vsync_start; | 79 | timings->vsw = mode->vsync_end - mode->vsync_start; |
| 73 | timings->vbp = mode->vtotal - mode->vsync_end; | 80 | timings->vbp = mode->vtotal - mode->vsync_end; |
| 81 | |||
| 82 | timings->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); | ||
| 83 | |||
| 84 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
| 85 | timings->hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; | ||
| 86 | else | ||
| 87 | timings->hsync_level = OMAPDSS_SIG_ACTIVE_LOW; | ||
| 88 | |||
| 89 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
| 90 | timings->vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; | ||
| 91 | else | ||
| 92 | timings->vsync_level = OMAPDSS_SIG_ACTIVE_LOW; | ||
| 93 | |||
| 94 | timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | ||
| 95 | timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH; | ||
| 96 | timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; | ||
| 74 | } | 97 | } |
| 75 | 98 | ||
| 76 | static void omap_connector_dpms(struct drm_connector *connector, int mode) | 99 | static void omap_connector_dpms(struct drm_connector *connector, int mode) |
| @@ -187,7 +210,7 @@ static int omap_connector_get_modes(struct drm_connector *connector) | |||
| 187 | } | 210 | } |
| 188 | } else { | 211 | } else { |
| 189 | struct drm_display_mode *mode = drm_mode_create(dev); | 212 | struct drm_display_mode *mode = drm_mode_create(dev); |
| 190 | struct omap_video_timings timings; | 213 | struct omap_video_timings timings = {0}; |
| 191 | 214 | ||
| 192 | dssdrv->get_timings(dssdev, &timings); | 215 | dssdrv->get_timings(dssdev, &timings); |
| 193 | 216 | ||
| @@ -291,7 +314,7 @@ void omap_connector_mode_set(struct drm_connector *connector, | |||
| 291 | struct omap_connector *omap_connector = to_omap_connector(connector); | 314 | struct omap_connector *omap_connector = to_omap_connector(connector); |
| 292 | struct omap_dss_device *dssdev = omap_connector->dssdev; | 315 | struct omap_dss_device *dssdev = omap_connector->dssdev; |
| 293 | struct omap_dss_driver *dssdrv = dssdev->driver; | 316 | struct omap_dss_driver *dssdrv = dssdev->driver; |
| 294 | struct omap_video_timings timings; | 317 | struct omap_video_timings timings = {0}; |
| 295 | 318 | ||
| 296 | copy_timings_drm_to_omap(&timings, mode); | 319 | copy_timings_drm_to_omap(&timings, mode); |
| 297 | 320 | ||
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c index d98321945802..758ce0a8d82e 100644 --- a/drivers/staging/ozwpan/ozcdev.c +++ b/drivers/staging/ozwpan/ozcdev.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <linux/cdev.h> | 8 | #include <linux/cdev.h> |
| 9 | #include <linux/uaccess.h> | 9 | #include <linux/uaccess.h> |
| 10 | #include <linux/netdevice.h> | 10 | #include <linux/netdevice.h> |
| 11 | #include <linux/etherdevice.h> | ||
| 11 | #include <linux/poll.h> | 12 | #include <linux/poll.h> |
| 12 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
| 13 | #include "ozconfig.h" | 14 | #include "ozconfig.h" |
| @@ -213,7 +214,7 @@ static int oz_set_active_pd(u8 *addr) | |||
| 213 | if (old_pd) | 214 | if (old_pd) |
| 214 | oz_pd_put(old_pd); | 215 | oz_pd_put(old_pd); |
| 215 | } else { | 216 | } else { |
| 216 | if (!memcmp(addr, "\0\0\0\0\0\0", sizeof(addr))) { | 217 | if (is_zero_ether_addr(addr)) { |
| 217 | spin_lock_bh(&g_cdev.lock); | 218 | spin_lock_bh(&g_cdev.lock); |
| 218 | pd = g_cdev.active_pd; | 219 | pd = g_cdev.active_pd; |
| 219 | g_cdev.active_pd = 0; | 220 | g_cdev.active_pd = 0; |
diff --git a/drivers/staging/rtl8712/recv_linux.c b/drivers/staging/rtl8712/recv_linux.c index 0e26d5f6cf2d..495ee1205e02 100644 --- a/drivers/staging/rtl8712/recv_linux.c +++ b/drivers/staging/rtl8712/recv_linux.c | |||
| @@ -117,13 +117,8 @@ void r8712_recv_indicatepkt(struct _adapter *padapter, | |||
| 117 | if (skb == NULL) | 117 | if (skb == NULL) |
| 118 | goto _recv_indicatepkt_drop; | 118 | goto _recv_indicatepkt_drop; |
| 119 | skb->data = precv_frame->u.hdr.rx_data; | 119 | skb->data = precv_frame->u.hdr.rx_data; |
| 120 | #ifdef NET_SKBUFF_DATA_USES_OFFSET | ||
| 121 | skb->tail = (sk_buff_data_t)(precv_frame->u.hdr.rx_tail - | ||
| 122 | precv_frame->u.hdr.rx_head); | ||
| 123 | #else | ||
| 124 | skb->tail = (sk_buff_data_t)precv_frame->u.hdr.rx_tail; | ||
| 125 | #endif | ||
| 126 | skb->len = precv_frame->u.hdr.len; | 120 | skb->len = precv_frame->u.hdr.len; |
| 121 | skb_set_tail_pointer(skb, skb->len); | ||
| 127 | if ((pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1)) | 122 | if ((pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1)) |
| 128 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 123 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 129 | else | 124 | else |
diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c index e4bdf2a2b582..3aa895ec6507 100644 --- a/drivers/staging/vt6656/dpc.c +++ b/drivers/staging/vt6656/dpc.c | |||
| @@ -200,7 +200,7 @@ s_vProcessRxMACHeader ( | |||
| 200 | } else if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_RFC1042[0])) { | 200 | } else if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_RFC1042[0])) { |
| 201 | cbHeaderSize += 6; | 201 | cbHeaderSize += 6; |
| 202 | pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize); | 202 | pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize); |
| 203 | if ((*pwType == cpu_to_le16(ETH_P_IPX)) || | 203 | if ((*pwType == cpu_to_be16(ETH_P_IPX)) || |
| 204 | (*pwType == cpu_to_le16(0xF380))) { | 204 | (*pwType == cpu_to_le16(0xF380))) { |
| 205 | cbHeaderSize -= 8; | 205 | cbHeaderSize -= 8; |
| 206 | pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize); | 206 | pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize); |
diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index bb464527fc1b..b6e04e7b629b 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c | |||
| @@ -1699,7 +1699,7 @@ s_bPacketToWirelessUsb( | |||
| 1699 | // 802.1H | 1699 | // 802.1H |
| 1700 | if (ntohs(psEthHeader->wType) > ETH_DATA_LEN) { | 1700 | if (ntohs(psEthHeader->wType) > ETH_DATA_LEN) { |
| 1701 | if (pDevice->dwDiagRefCount == 0) { | 1701 | if (pDevice->dwDiagRefCount == 0) { |
| 1702 | if ((psEthHeader->wType == cpu_to_le16(ETH_P_IPX)) || | 1702 | if ((psEthHeader->wType == cpu_to_be16(ETH_P_IPX)) || |
| 1703 | (psEthHeader->wType == cpu_to_le16(0xF380))) { | 1703 | (psEthHeader->wType == cpu_to_le16(0xF380))) { |
| 1704 | memcpy((PBYTE) (pbyPayloadHead), | 1704 | memcpy((PBYTE) (pbyPayloadHead), |
| 1705 | abySNAP_Bridgetunnel, 6); | 1705 | abySNAP_Bridgetunnel, 6); |
| @@ -2838,10 +2838,10 @@ int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb) | |||
| 2838 | Packet_Type = skb->data[ETH_HLEN+1]; | 2838 | Packet_Type = skb->data[ETH_HLEN+1]; |
| 2839 | Descriptor_type = skb->data[ETH_HLEN+1+1+2]; | 2839 | Descriptor_type = skb->data[ETH_HLEN+1+1+2]; |
| 2840 | Key_info = (skb->data[ETH_HLEN+1+1+2+1] << 8)|(skb->data[ETH_HLEN+1+1+2+2]); | 2840 | Key_info = (skb->data[ETH_HLEN+1+1+2+1] << 8)|(skb->data[ETH_HLEN+1+1+2+2]); |
| 2841 | if (pDevice->sTxEthHeader.wType == cpu_to_le16(ETH_P_PAE)) { | 2841 | if (pDevice->sTxEthHeader.wType == cpu_to_be16(ETH_P_PAE)) { |
| 2842 | /* 802.1x OR eapol-key challenge frame transfer */ | 2842 | /* 802.1x OR eapol-key challenge frame transfer */ |
| 2843 | if (((Protocol_Version == 1) || (Protocol_Version == 2)) && | 2843 | if (((Protocol_Version == 1) || (Protocol_Version == 2)) && |
| 2844 | (Packet_Type == 3)) { | 2844 | (Packet_Type == 3)) { |
| 2845 | bTxeapol_key = TRUE; | 2845 | bTxeapol_key = TRUE; |
| 2846 | if(!(Key_info & BIT3) && //WPA or RSN group-key challenge | 2846 | if(!(Key_info & BIT3) && //WPA or RSN group-key challenge |
| 2847 | (Key_info & BIT8) && (Key_info & BIT9)) { //send 2/2 key | 2847 | (Key_info & BIT8) && (Key_info & BIT9)) { //send 2/2 key |
| @@ -2987,19 +2987,19 @@ int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb) | |||
| 2987 | } | 2987 | } |
| 2988 | } | 2988 | } |
| 2989 | 2989 | ||
| 2990 | if (pDevice->sTxEthHeader.wType == cpu_to_le16(ETH_P_PAE)) { | 2990 | if (pDevice->sTxEthHeader.wType == cpu_to_be16(ETH_P_PAE)) { |
| 2991 | if (pDevice->byBBType != BB_TYPE_11A) { | 2991 | if (pDevice->byBBType != BB_TYPE_11A) { |
| 2992 | pDevice->wCurrentRate = RATE_1M; | 2992 | pDevice->wCurrentRate = RATE_1M; |
| 2993 | pDevice->byACKRate = RATE_1M; | 2993 | pDevice->byACKRate = RATE_1M; |
| 2994 | pDevice->byTopCCKBasicRate = RATE_1M; | 2994 | pDevice->byTopCCKBasicRate = RATE_1M; |
| 2995 | pDevice->byTopOFDMBasicRate = RATE_6M; | 2995 | pDevice->byTopOFDMBasicRate = RATE_6M; |
| 2996 | } else { | 2996 | } else { |
| 2997 | pDevice->wCurrentRate = RATE_6M; | 2997 | pDevice->wCurrentRate = RATE_6M; |
| 2998 | pDevice->byACKRate = RATE_6M; | 2998 | pDevice->byACKRate = RATE_6M; |
| 2999 | pDevice->byTopCCKBasicRate = RATE_1M; | 2999 | pDevice->byTopCCKBasicRate = RATE_1M; |
| 3000 | pDevice->byTopOFDMBasicRate = RATE_6M; | 3000 | pDevice->byTopOFDMBasicRate = RATE_6M; |
| 3001 | } | 3001 | } |
| 3002 | } | 3002 | } |
| 3003 | 3003 | ||
| 3004 | DBG_PRT(MSG_LEVEL_DEBUG, | 3004 | DBG_PRT(MSG_LEVEL_DEBUG, |
| 3005 | KERN_INFO "dma_tx: pDevice->wCurrentRate = %d\n", | 3005 | KERN_INFO "dma_tx: pDevice->wCurrentRate = %d\n", |
| @@ -3015,7 +3015,7 @@ int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb) | |||
| 3015 | 3015 | ||
| 3016 | if (bNeedEncryption == TRUE) { | 3016 | if (bNeedEncryption == TRUE) { |
| 3017 | DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ntohs Pkt Type=%04x\n", ntohs(pDevice->sTxEthHeader.wType)); | 3017 | DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ntohs Pkt Type=%04x\n", ntohs(pDevice->sTxEthHeader.wType)); |
| 3018 | if ((pDevice->sTxEthHeader.wType) == cpu_to_le16(ETH_P_PAE)) { | 3018 | if ((pDevice->sTxEthHeader.wType) == cpu_to_be16(ETH_P_PAE)) { |
| 3019 | bNeedEncryption = FALSE; | 3019 | bNeedEncryption = FALSE; |
| 3020 | DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Pkt Type=%04x\n", (pDevice->sTxEthHeader.wType)); | 3020 | DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Pkt Type=%04x\n", (pDevice->sTxEthHeader.wType)); |
| 3021 | if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pMgmt->eCurrState == WMAC_STATE_ASSOC)) { | 3021 | if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pMgmt->eCurrState == WMAC_STATE_ASSOC)) { |
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index fabff4d650ef..0970127344e6 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c | |||
| @@ -327,9 +327,9 @@ int prism2_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
| 327 | return result; | 327 | return result; |
| 328 | } | 328 | } |
| 329 | 329 | ||
| 330 | int prism2_scan(struct wiphy *wiphy, struct net_device *dev, | 330 | int prism2_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) |
| 331 | struct cfg80211_scan_request *request) | ||
| 332 | { | 331 | { |
| 332 | struct net_device *dev = request->wdev->netdev; | ||
| 333 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); | 333 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
| 334 | wlandevice_t *wlandev = dev->ml_priv; | 334 | wlandevice_t *wlandev = dev->ml_priv; |
| 335 | struct p80211msg_dot11req_scan msg1; | 335 | struct p80211msg_dot11req_scan msg1; |
diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c index c214977b4ab4..52b43b7b83d7 100644 --- a/drivers/staging/zcache/zcache-main.c +++ b/drivers/staging/zcache/zcache-main.c | |||
| @@ -1251,13 +1251,12 @@ static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw, | |||
| 1251 | void *pampd, struct tmem_pool *pool, | 1251 | void *pampd, struct tmem_pool *pool, |
| 1252 | struct tmem_oid *oid, uint32_t index) | 1252 | struct tmem_oid *oid, uint32_t index) |
| 1253 | { | 1253 | { |
| 1254 | int ret = 0; | ||
| 1255 | |||
| 1256 | BUG_ON(!is_ephemeral(pool)); | 1254 | BUG_ON(!is_ephemeral(pool)); |
| 1257 | zbud_decompress((struct page *)(data), pampd); | 1255 | if (zbud_decompress((struct page *)(data), pampd) < 0) |
| 1256 | return -EINVAL; | ||
| 1258 | zbud_free_and_delist((struct zbud_hdr *)pampd); | 1257 | zbud_free_and_delist((struct zbud_hdr *)pampd); |
| 1259 | atomic_dec(&zcache_curr_eph_pampd_count); | 1258 | atomic_dec(&zcache_curr_eph_pampd_count); |
| 1260 | return ret; | 1259 | return 0; |
| 1261 | } | 1260 | } |
| 1262 | 1261 | ||
| 1263 | /* | 1262 | /* |
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 0694d9b1bce6..6aba4395e8d8 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c | |||
| @@ -221,6 +221,7 @@ static int iscsi_login_zero_tsih_s1( | |||
| 221 | { | 221 | { |
| 222 | struct iscsi_session *sess = NULL; | 222 | struct iscsi_session *sess = NULL; |
| 223 | struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf; | 223 | struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf; |
| 224 | int ret; | ||
| 224 | 225 | ||
| 225 | sess = kzalloc(sizeof(struct iscsi_session), GFP_KERNEL); | 226 | sess = kzalloc(sizeof(struct iscsi_session), GFP_KERNEL); |
| 226 | if (!sess) { | 227 | if (!sess) { |
| @@ -257,9 +258,17 @@ static int iscsi_login_zero_tsih_s1( | |||
| 257 | return -ENOMEM; | 258 | return -ENOMEM; |
| 258 | } | 259 | } |
| 259 | spin_lock(&sess_idr_lock); | 260 | spin_lock(&sess_idr_lock); |
| 260 | idr_get_new(&sess_idr, NULL, &sess->session_index); | 261 | ret = idr_get_new(&sess_idr, NULL, &sess->session_index); |
| 261 | spin_unlock(&sess_idr_lock); | 262 | spin_unlock(&sess_idr_lock); |
| 262 | 263 | ||
| 264 | if (ret < 0) { | ||
| 265 | pr_err("idr_get_new() for sess_idr failed\n"); | ||
| 266 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
| 267 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | ||
| 268 | kfree(sess); | ||
| 269 | return -ENOMEM; | ||
| 270 | } | ||
| 271 | |||
| 263 | sess->creation_time = get_jiffies_64(); | 272 | sess->creation_time = get_jiffies_64(); |
| 264 | spin_lock_init(&sess->session_stats_lock); | 273 | spin_lock_init(&sess->session_stats_lock); |
| 265 | /* | 274 | /* |
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index 0c4760fabfc0..240f7aa76ed1 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c | |||
| @@ -662,7 +662,7 @@ int iscsi_extract_key_value(char *textbuf, char **key, char **value) | |||
| 662 | { | 662 | { |
| 663 | *value = strchr(textbuf, '='); | 663 | *value = strchr(textbuf, '='); |
| 664 | if (!*value) { | 664 | if (!*value) { |
| 665 | pr_err("Unable to locate \"=\" seperator for key," | 665 | pr_err("Unable to locate \"=\" separator for key," |
| 666 | " ignoring request.\n"); | 666 | " ignoring request.\n"); |
| 667 | return -1; | 667 | return -1; |
| 668 | } | 668 | } |
| @@ -1269,7 +1269,7 @@ static int iscsi_check_value(struct iscsi_param *param, char *value) | |||
| 1269 | comma_ptr = strchr(value, ','); | 1269 | comma_ptr = strchr(value, ','); |
| 1270 | 1270 | ||
| 1271 | if (comma_ptr && !IS_TYPE_VALUE_LIST(param)) { | 1271 | if (comma_ptr && !IS_TYPE_VALUE_LIST(param)) { |
| 1272 | pr_err("Detected value seperator \",\", but" | 1272 | pr_err("Detected value separator \",\", but" |
| 1273 | " key \"%s\" does not allow a value list," | 1273 | " key \"%s\" does not allow a value list," |
| 1274 | " protocol error.\n", param->name); | 1274 | " protocol error.\n", param->name); |
| 1275 | return -1; | 1275 | return -1; |
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 91799973081a..41641ba54828 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c | |||
| @@ -218,6 +218,13 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd) | |||
| 218 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 218 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
| 219 | return -EINVAL; | 219 | return -EINVAL; |
| 220 | } | 220 | } |
| 221 | if (cmd->data_length < 4) { | ||
| 222 | pr_warn("SET TARGET PORT GROUPS parameter list length %u too" | ||
| 223 | " small\n", cmd->data_length); | ||
| 224 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | ||
| 225 | return -EINVAL; | ||
| 226 | } | ||
| 227 | |||
| 221 | buf = transport_kmap_data_sg(cmd); | 228 | buf = transport_kmap_data_sg(cmd); |
| 222 | 229 | ||
| 223 | /* | 230 | /* |
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index cf2c66f3c116..9fc9a6006ca0 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c | |||
| @@ -669,6 +669,13 @@ int target_report_luns(struct se_cmd *se_cmd) | |||
| 669 | unsigned char *buf; | 669 | unsigned char *buf; |
| 670 | u32 lun_count = 0, offset = 8, i; | 670 | u32 lun_count = 0, offset = 8, i; |
| 671 | 671 | ||
| 672 | if (se_cmd->data_length < 16) { | ||
| 673 | pr_warn("REPORT LUNS allocation length %u too small\n", | ||
| 674 | se_cmd->data_length); | ||
| 675 | se_cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | ||
| 676 | return -EINVAL; | ||
| 677 | } | ||
| 678 | |||
| 672 | buf = transport_kmap_data_sg(se_cmd); | 679 | buf = transport_kmap_data_sg(se_cmd); |
| 673 | if (!buf) | 680 | if (!buf) |
| 674 | return -ENOMEM; | 681 | return -ENOMEM; |
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 76db75e836ed..9ba495477fd2 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c | |||
| @@ -325,17 +325,30 @@ static int iblock_execute_unmap(struct se_cmd *cmd) | |||
| 325 | struct iblock_dev *ibd = dev->dev_ptr; | 325 | struct iblock_dev *ibd = dev->dev_ptr; |
| 326 | unsigned char *buf, *ptr = NULL; | 326 | unsigned char *buf, *ptr = NULL; |
| 327 | sector_t lba; | 327 | sector_t lba; |
| 328 | int size = cmd->data_length; | 328 | int size; |
| 329 | u32 range; | 329 | u32 range; |
| 330 | int ret = 0; | 330 | int ret = 0; |
| 331 | int dl, bd_dl; | 331 | int dl, bd_dl; |
| 332 | 332 | ||
| 333 | if (cmd->data_length < 8) { | ||
| 334 | pr_warn("UNMAP parameter list length %u too small\n", | ||
| 335 | cmd->data_length); | ||
| 336 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | ||
| 337 | return -EINVAL; | ||
| 338 | } | ||
| 339 | |||
| 333 | buf = transport_kmap_data_sg(cmd); | 340 | buf = transport_kmap_data_sg(cmd); |
| 334 | 341 | ||
| 335 | dl = get_unaligned_be16(&buf[0]); | 342 | dl = get_unaligned_be16(&buf[0]); |
| 336 | bd_dl = get_unaligned_be16(&buf[2]); | 343 | bd_dl = get_unaligned_be16(&buf[2]); |
| 337 | 344 | ||
| 338 | size = min(size - 8, bd_dl); | 345 | size = cmd->data_length - 8; |
| 346 | if (bd_dl > size) | ||
| 347 | pr_warn("UNMAP parameter list length %u too small, ignoring bd_dl %u\n", | ||
| 348 | cmd->data_length, bd_dl); | ||
| 349 | else | ||
| 350 | size = bd_dl; | ||
| 351 | |||
| 339 | if (size / 16 > dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { | 352 | if (size / 16 > dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { |
| 340 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 353 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
| 341 | ret = -EINVAL; | 354 | ret = -EINVAL; |
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 1e946502c378..956c84c6b666 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c | |||
| @@ -1540,6 +1540,14 @@ static int core_scsi3_decode_spec_i_port( | |||
| 1540 | tidh_new->dest_local_nexus = 1; | 1540 | tidh_new->dest_local_nexus = 1; |
| 1541 | list_add_tail(&tidh_new->dest_list, &tid_dest_list); | 1541 | list_add_tail(&tidh_new->dest_list, &tid_dest_list); |
| 1542 | 1542 | ||
| 1543 | if (cmd->data_length < 28) { | ||
| 1544 | pr_warn("SPC-PR: Received PR OUT parameter list" | ||
| 1545 | " length too small: %u\n", cmd->data_length); | ||
| 1546 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | ||
| 1547 | ret = -EINVAL; | ||
| 1548 | goto out; | ||
| 1549 | } | ||
| 1550 | |||
| 1543 | buf = transport_kmap_data_sg(cmd); | 1551 | buf = transport_kmap_data_sg(cmd); |
| 1544 | /* | 1552 | /* |
| 1545 | * For a PERSISTENT RESERVE OUT specify initiator ports payload, | 1553 | * For a PERSISTENT RESERVE OUT specify initiator ports payload, |
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 5552fa7426bc..9d7ce3daa262 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c | |||
| @@ -667,7 +667,8 @@ static void pscsi_free_device(void *p) | |||
| 667 | kfree(pdv); | 667 | kfree(pdv); |
| 668 | } | 668 | } |
| 669 | 669 | ||
| 670 | static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg) | 670 | static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg, |
| 671 | unsigned char *sense_buffer) | ||
| 671 | { | 672 | { |
| 672 | struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; | 673 | struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; |
| 673 | struct scsi_device *sd = pdv->pdv_sd; | 674 | struct scsi_device *sd = pdv->pdv_sd; |
| @@ -679,7 +680,7 @@ static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg) | |||
| 679 | * not been allocated because TCM is handling the emulation directly. | 680 | * not been allocated because TCM is handling the emulation directly. |
| 680 | */ | 681 | */ |
| 681 | if (!pt) | 682 | if (!pt) |
| 682 | return 0; | 683 | return; |
| 683 | 684 | ||
| 684 | cdb = &pt->pscsi_cdb[0]; | 685 | cdb = &pt->pscsi_cdb[0]; |
| 685 | result = pt->pscsi_result; | 686 | result = pt->pscsi_result; |
| @@ -687,11 +688,11 @@ static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg) | |||
| 687 | * Hack to make sure that Write-Protect modepage is set if R/O mode is | 688 | * Hack to make sure that Write-Protect modepage is set if R/O mode is |
| 688 | * forced. | 689 | * forced. |
| 689 | */ | 690 | */ |
| 691 | if (!cmd->se_deve || !cmd->data_length) | ||
| 692 | goto after_mode_sense; | ||
| 693 | |||
| 690 | if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) && | 694 | if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) && |
| 691 | (status_byte(result) << 1) == SAM_STAT_GOOD) { | 695 | (status_byte(result) << 1) == SAM_STAT_GOOD) { |
| 692 | if (!cmd->se_deve) | ||
| 693 | goto after_mode_sense; | ||
| 694 | |||
| 695 | if (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) { | 696 | if (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) { |
| 696 | unsigned char *buf = transport_kmap_data_sg(cmd); | 697 | unsigned char *buf = transport_kmap_data_sg(cmd); |
| 697 | 698 | ||
| @@ -708,7 +709,7 @@ static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg) | |||
| 708 | } | 709 | } |
| 709 | after_mode_sense: | 710 | after_mode_sense: |
| 710 | 711 | ||
| 711 | if (sd->type != TYPE_TAPE) | 712 | if (sd->type != TYPE_TAPE || !cmd->data_length) |
| 712 | goto after_mode_select; | 713 | goto after_mode_select; |
| 713 | 714 | ||
| 714 | /* | 715 | /* |
| @@ -750,10 +751,10 @@ after_mode_sense: | |||
| 750 | } | 751 | } |
| 751 | after_mode_select: | 752 | after_mode_select: |
| 752 | 753 | ||
| 753 | if (status_byte(result) & CHECK_CONDITION) | 754 | if (sense_buffer && (status_byte(result) & CHECK_CONDITION)) { |
| 754 | return 1; | 755 | memcpy(sense_buffer, pt->pscsi_sense, TRANSPORT_SENSE_BUFFER); |
| 755 | 756 | cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE; | |
| 756 | return 0; | 757 | } |
| 757 | } | 758 | } |
| 758 | 759 | ||
| 759 | enum { | 760 | enum { |
| @@ -1184,13 +1185,6 @@ fail: | |||
| 1184 | return -ENOMEM; | 1185 | return -ENOMEM; |
| 1185 | } | 1186 | } |
| 1186 | 1187 | ||
| 1187 | static unsigned char *pscsi_get_sense_buffer(struct se_cmd *cmd) | ||
| 1188 | { | ||
| 1189 | struct pscsi_plugin_task *pt = cmd->priv; | ||
| 1190 | |||
| 1191 | return pt->pscsi_sense; | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | /* pscsi_get_device_rev(): | 1188 | /* pscsi_get_device_rev(): |
| 1195 | * | 1189 | * |
| 1196 | * | 1190 | * |
| @@ -1273,7 +1267,6 @@ static struct se_subsystem_api pscsi_template = { | |||
| 1273 | .check_configfs_dev_params = pscsi_check_configfs_dev_params, | 1267 | .check_configfs_dev_params = pscsi_check_configfs_dev_params, |
| 1274 | .set_configfs_dev_params = pscsi_set_configfs_dev_params, | 1268 | .set_configfs_dev_params = pscsi_set_configfs_dev_params, |
| 1275 | .show_configfs_dev_params = pscsi_show_configfs_dev_params, | 1269 | .show_configfs_dev_params = pscsi_show_configfs_dev_params, |
| 1276 | .get_sense_buffer = pscsi_get_sense_buffer, | ||
| 1277 | .get_device_rev = pscsi_get_device_rev, | 1270 | .get_device_rev = pscsi_get_device_rev, |
| 1278 | .get_device_type = pscsi_get_device_type, | 1271 | .get_device_type = pscsi_get_device_type, |
| 1279 | .get_blocks = pscsi_get_blocks, | 1272 | .get_blocks = pscsi_get_blocks, |
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 4c861de538c9..388a922c8f6d 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c | |||
| @@ -877,9 +877,11 @@ static int spc_emulate_modesense(struct se_cmd *cmd) | |||
| 877 | static int spc_emulate_request_sense(struct se_cmd *cmd) | 877 | static int spc_emulate_request_sense(struct se_cmd *cmd) |
| 878 | { | 878 | { |
| 879 | unsigned char *cdb = cmd->t_task_cdb; | 879 | unsigned char *cdb = cmd->t_task_cdb; |
| 880 | unsigned char *buf; | 880 | unsigned char *rbuf; |
| 881 | u8 ua_asc = 0, ua_ascq = 0; | 881 | u8 ua_asc = 0, ua_ascq = 0; |
| 882 | int err = 0; | 882 | unsigned char buf[SE_SENSE_BUF]; |
| 883 | |||
| 884 | memset(buf, 0, SE_SENSE_BUF); | ||
| 883 | 885 | ||
| 884 | if (cdb[1] & 0x01) { | 886 | if (cdb[1] & 0x01) { |
| 885 | pr_err("REQUEST_SENSE description emulation not" | 887 | pr_err("REQUEST_SENSE description emulation not" |
| @@ -888,20 +890,21 @@ static int spc_emulate_request_sense(struct se_cmd *cmd) | |||
| 888 | return -ENOSYS; | 890 | return -ENOSYS; |
| 889 | } | 891 | } |
| 890 | 892 | ||
| 891 | buf = transport_kmap_data_sg(cmd); | 893 | rbuf = transport_kmap_data_sg(cmd); |
| 892 | 894 | if (cmd->scsi_sense_reason != 0) { | |
| 893 | if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) { | 895 | /* |
| 896 | * Out of memory. We will fail with CHECK CONDITION, so | ||
| 897 | * we must not clear the unit attention condition. | ||
| 898 | */ | ||
| 899 | target_complete_cmd(cmd, CHECK_CONDITION); | ||
| 900 | return 0; | ||
| 901 | } else if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) { | ||
| 894 | /* | 902 | /* |
| 895 | * CURRENT ERROR, UNIT ATTENTION | 903 | * CURRENT ERROR, UNIT ATTENTION |
| 896 | */ | 904 | */ |
| 897 | buf[0] = 0x70; | 905 | buf[0] = 0x70; |
| 898 | buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; | 906 | buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; |
| 899 | 907 | ||
| 900 | if (cmd->data_length < 18) { | ||
| 901 | buf[7] = 0x00; | ||
| 902 | err = -EINVAL; | ||
| 903 | goto end; | ||
| 904 | } | ||
| 905 | /* | 908 | /* |
| 906 | * The Additional Sense Code (ASC) from the UNIT ATTENTION | 909 | * The Additional Sense Code (ASC) from the UNIT ATTENTION |
| 907 | */ | 910 | */ |
| @@ -915,11 +918,6 @@ static int spc_emulate_request_sense(struct se_cmd *cmd) | |||
| 915 | buf[0] = 0x70; | 918 | buf[0] = 0x70; |
| 916 | buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE; | 919 | buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE; |
| 917 | 920 | ||
| 918 | if (cmd->data_length < 18) { | ||
| 919 | buf[7] = 0x00; | ||
| 920 | err = -EINVAL; | ||
| 921 | goto end; | ||
| 922 | } | ||
| 923 | /* | 921 | /* |
| 924 | * NO ADDITIONAL SENSE INFORMATION | 922 | * NO ADDITIONAL SENSE INFORMATION |
| 925 | */ | 923 | */ |
| @@ -927,8 +925,11 @@ static int spc_emulate_request_sense(struct se_cmd *cmd) | |||
| 927 | buf[7] = 0x0A; | 925 | buf[7] = 0x0A; |
| 928 | } | 926 | } |
| 929 | 927 | ||
| 930 | end: | 928 | if (rbuf) { |
| 931 | transport_kunmap_data_sg(cmd); | 929 | memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); |
| 930 | transport_kunmap_data_sg(cmd); | ||
| 931 | } | ||
| 932 | |||
| 932 | target_complete_cmd(cmd, GOOD); | 933 | target_complete_cmd(cmd, GOOD); |
| 933 | return 0; | 934 | return 0; |
| 934 | } | 935 | } |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 4de3186dc44e..269f54488397 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
| @@ -567,6 +567,34 @@ static void target_complete_failure_work(struct work_struct *work) | |||
| 567 | transport_generic_request_failure(cmd); | 567 | transport_generic_request_failure(cmd); |
| 568 | } | 568 | } |
| 569 | 569 | ||
| 570 | /* | ||
| 571 | * Used when asking transport to copy Sense Data from the underlying | ||
| 572 | * Linux/SCSI struct scsi_cmnd | ||
| 573 | */ | ||
| 574 | static unsigned char *transport_get_sense_buffer(struct se_cmd *cmd) | ||
| 575 | { | ||
| 576 | unsigned char *buffer = cmd->sense_buffer; | ||
| 577 | struct se_device *dev = cmd->se_dev; | ||
| 578 | u32 offset = 0; | ||
| 579 | |||
| 580 | WARN_ON(!cmd->se_lun); | ||
| 581 | |||
| 582 | if (!dev) | ||
| 583 | return NULL; | ||
| 584 | |||
| 585 | if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) | ||
| 586 | return NULL; | ||
| 587 | |||
| 588 | offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER); | ||
| 589 | |||
| 590 | /* Automatically padded */ | ||
| 591 | cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset; | ||
| 592 | |||
| 593 | pr_debug("HBA_[%u]_PLUG[%s]: Requesting sense for SAM STATUS: 0x%02x\n", | ||
| 594 | dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status); | ||
| 595 | return &buffer[offset]; | ||
| 596 | } | ||
| 597 | |||
| 570 | void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) | 598 | void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) |
| 571 | { | 599 | { |
| 572 | struct se_device *dev = cmd->se_dev; | 600 | struct se_device *dev = cmd->se_dev; |
| @@ -580,11 +608,11 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) | |||
| 580 | cmd->transport_state &= ~CMD_T_BUSY; | 608 | cmd->transport_state &= ~CMD_T_BUSY; |
| 581 | 609 | ||
| 582 | if (dev && dev->transport->transport_complete) { | 610 | if (dev && dev->transport->transport_complete) { |
| 583 | if (dev->transport->transport_complete(cmd, | 611 | dev->transport->transport_complete(cmd, |
| 584 | cmd->t_data_sg) != 0) { | 612 | cmd->t_data_sg, |
| 585 | cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE; | 613 | transport_get_sense_buffer(cmd)); |
| 614 | if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) | ||
| 586 | success = 1; | 615 | success = 1; |
| 587 | } | ||
| 588 | } | 616 | } |
| 589 | 617 | ||
| 590 | /* | 618 | /* |
| @@ -1181,15 +1209,20 @@ int target_cmd_size_check(struct se_cmd *cmd, unsigned int size) | |||
| 1181 | /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */ | 1209 | /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */ |
| 1182 | goto out_invalid_cdb_field; | 1210 | goto out_invalid_cdb_field; |
| 1183 | } | 1211 | } |
| 1184 | 1212 | /* | |
| 1213 | * For the overflow case keep the existing fabric provided | ||
| 1214 | * ->data_length. Otherwise for the underflow case, reset | ||
| 1215 | * ->data_length to the smaller SCSI expected data transfer | ||
| 1216 | * length. | ||
| 1217 | */ | ||
| 1185 | if (size > cmd->data_length) { | 1218 | if (size > cmd->data_length) { |
| 1186 | cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; | 1219 | cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; |
| 1187 | cmd->residual_count = (size - cmd->data_length); | 1220 | cmd->residual_count = (size - cmd->data_length); |
| 1188 | } else { | 1221 | } else { |
| 1189 | cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; | 1222 | cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; |
| 1190 | cmd->residual_count = (cmd->data_length - size); | 1223 | cmd->residual_count = (cmd->data_length - size); |
| 1224 | cmd->data_length = size; | ||
| 1191 | } | 1225 | } |
| 1192 | cmd->data_length = size; | ||
| 1193 | } | 1226 | } |
| 1194 | 1227 | ||
| 1195 | return 0; | 1228 | return 0; |
| @@ -1816,61 +1849,6 @@ execute: | |||
| 1816 | EXPORT_SYMBOL(target_execute_cmd); | 1849 | EXPORT_SYMBOL(target_execute_cmd); |
| 1817 | 1850 | ||
| 1818 | /* | 1851 | /* |
| 1819 | * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd | ||
| 1820 | */ | ||
| 1821 | static int transport_get_sense_data(struct se_cmd *cmd) | ||
| 1822 | { | ||
| 1823 | unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL; | ||
| 1824 | struct se_device *dev = cmd->se_dev; | ||
| 1825 | unsigned long flags; | ||
| 1826 | u32 offset = 0; | ||
| 1827 | |||
| 1828 | WARN_ON(!cmd->se_lun); | ||
| 1829 | |||
| 1830 | if (!dev) | ||
| 1831 | return 0; | ||
| 1832 | |||
| 1833 | spin_lock_irqsave(&cmd->t_state_lock, flags); | ||
| 1834 | if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) { | ||
| 1835 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
| 1836 | return 0; | ||
| 1837 | } | ||
| 1838 | |||
| 1839 | if (!(cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE)) | ||
| 1840 | goto out; | ||
| 1841 | |||
| 1842 | if (!dev->transport->get_sense_buffer) { | ||
| 1843 | pr_err("dev->transport->get_sense_buffer is NULL\n"); | ||
| 1844 | goto out; | ||
| 1845 | } | ||
| 1846 | |||
| 1847 | sense_buffer = dev->transport->get_sense_buffer(cmd); | ||
| 1848 | if (!sense_buffer) { | ||
| 1849 | pr_err("ITT 0x%08x cmd %p: Unable to locate" | ||
| 1850 | " sense buffer for task with sense\n", | ||
| 1851 | cmd->se_tfo->get_task_tag(cmd), cmd); | ||
| 1852 | goto out; | ||
| 1853 | } | ||
| 1854 | |||
| 1855 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
| 1856 | |||
| 1857 | offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER); | ||
| 1858 | |||
| 1859 | memcpy(&buffer[offset], sense_buffer, TRANSPORT_SENSE_BUFFER); | ||
| 1860 | |||
| 1861 | /* Automatically padded */ | ||
| 1862 | cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset; | ||
| 1863 | |||
| 1864 | pr_debug("HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x and sense\n", | ||
| 1865 | dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status); | ||
| 1866 | return 0; | ||
| 1867 | |||
| 1868 | out: | ||
| 1869 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
| 1870 | return -1; | ||
| 1871 | } | ||
| 1872 | |||
| 1873 | /* | ||
| 1874 | * Process all commands up to the last received ORDERED task attribute which | 1852 | * Process all commands up to the last received ORDERED task attribute which |
| 1875 | * requires another blocking boundary | 1853 | * requires another blocking boundary |
| 1876 | */ | 1854 | */ |
| @@ -1985,7 +1963,7 @@ static void transport_handle_queue_full( | |||
| 1985 | static void target_complete_ok_work(struct work_struct *work) | 1963 | static void target_complete_ok_work(struct work_struct *work) |
| 1986 | { | 1964 | { |
| 1987 | struct se_cmd *cmd = container_of(work, struct se_cmd, work); | 1965 | struct se_cmd *cmd = container_of(work, struct se_cmd, work); |
| 1988 | int reason = 0, ret; | 1966 | int ret; |
| 1989 | 1967 | ||
| 1990 | /* | 1968 | /* |
| 1991 | * Check if we need to move delayed/dormant tasks from cmds on the | 1969 | * Check if we need to move delayed/dormant tasks from cmds on the |
| @@ -2002,23 +1980,19 @@ static void target_complete_ok_work(struct work_struct *work) | |||
| 2002 | schedule_work(&cmd->se_dev->qf_work_queue); | 1980 | schedule_work(&cmd->se_dev->qf_work_queue); |
| 2003 | 1981 | ||
| 2004 | /* | 1982 | /* |
| 2005 | * Check if we need to retrieve a sense buffer from | 1983 | * Check if we need to send a sense buffer from |
| 2006 | * the struct se_cmd in question. | 1984 | * the struct se_cmd in question. |
| 2007 | */ | 1985 | */ |
| 2008 | if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) { | 1986 | if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) { |
| 2009 | if (transport_get_sense_data(cmd) < 0) | 1987 | WARN_ON(!cmd->scsi_status); |
| 2010 | reason = TCM_NON_EXISTENT_LUN; | 1988 | ret = transport_send_check_condition_and_sense( |
| 2011 | 1989 | cmd, 0, 1); | |
| 2012 | if (cmd->scsi_status) { | 1990 | if (ret == -EAGAIN || ret == -ENOMEM) |
| 2013 | ret = transport_send_check_condition_and_sense( | 1991 | goto queue_full; |
| 2014 | cmd, reason, 1); | ||
| 2015 | if (ret == -EAGAIN || ret == -ENOMEM) | ||
| 2016 | goto queue_full; | ||
| 2017 | 1992 | ||
| 2018 | transport_lun_remove_cmd(cmd); | 1993 | transport_lun_remove_cmd(cmd); |
| 2019 | transport_cmd_check_stop_to_fabric(cmd); | 1994 | transport_cmd_check_stop_to_fabric(cmd); |
| 2020 | return; | 1995 | return; |
| 2021 | } | ||
| 2022 | } | 1996 | } |
| 2023 | /* | 1997 | /* |
| 2024 | * Check for a callback, used by amongst other things | 1998 | * Check for a callback, used by amongst other things |
| @@ -2216,7 +2190,6 @@ void *transport_kmap_data_sg(struct se_cmd *cmd) | |||
| 2216 | struct page **pages; | 2190 | struct page **pages; |
| 2217 | int i; | 2191 | int i; |
| 2218 | 2192 | ||
| 2219 | BUG_ON(!sg); | ||
| 2220 | /* | 2193 | /* |
| 2221 | * We need to take into account a possible offset here for fabrics like | 2194 | * We need to take into account a possible offset here for fabrics like |
| 2222 | * tcm_loop who may be using a contig buffer from the SCSI midlayer for | 2195 | * tcm_loop who may be using a contig buffer from the SCSI midlayer for |
| @@ -2224,13 +2197,17 @@ void *transport_kmap_data_sg(struct se_cmd *cmd) | |||
| 2224 | */ | 2197 | */ |
| 2225 | if (!cmd->t_data_nents) | 2198 | if (!cmd->t_data_nents) |
| 2226 | return NULL; | 2199 | return NULL; |
| 2227 | else if (cmd->t_data_nents == 1) | 2200 | |
| 2201 | BUG_ON(!sg); | ||
| 2202 | if (cmd->t_data_nents == 1) | ||
| 2228 | return kmap(sg_page(sg)) + sg->offset; | 2203 | return kmap(sg_page(sg)) + sg->offset; |
| 2229 | 2204 | ||
| 2230 | /* >1 page. use vmap */ | 2205 | /* >1 page. use vmap */ |
| 2231 | pages = kmalloc(sizeof(*pages) * cmd->t_data_nents, GFP_KERNEL); | 2206 | pages = kmalloc(sizeof(*pages) * cmd->t_data_nents, GFP_KERNEL); |
| 2232 | if (!pages) | 2207 | if (!pages) { |
| 2208 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
| 2233 | return NULL; | 2209 | return NULL; |
| 2210 | } | ||
| 2234 | 2211 | ||
| 2235 | /* convert sg[] to pages[] */ | 2212 | /* convert sg[] to pages[] */ |
| 2236 | for_each_sg(cmd->t_data_sg, sg, cmd->t_data_nents, i) { | 2213 | for_each_sg(cmd->t_data_sg, sg, cmd->t_data_nents, i) { |
| @@ -2239,8 +2216,10 @@ void *transport_kmap_data_sg(struct se_cmd *cmd) | |||
| 2239 | 2216 | ||
| 2240 | cmd->t_data_vmap = vmap(pages, cmd->t_data_nents, VM_MAP, PAGE_KERNEL); | 2217 | cmd->t_data_vmap = vmap(pages, cmd->t_data_nents, VM_MAP, PAGE_KERNEL); |
| 2241 | kfree(pages); | 2218 | kfree(pages); |
| 2242 | if (!cmd->t_data_vmap) | 2219 | if (!cmd->t_data_vmap) { |
| 2220 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
| 2243 | return NULL; | 2221 | return NULL; |
| 2222 | } | ||
| 2244 | 2223 | ||
| 2245 | return cmd->t_data_vmap + cmd->t_data_sg[0].offset; | 2224 | return cmd->t_data_vmap + cmd->t_data_sg[0].offset; |
| 2246 | } | 2225 | } |
| @@ -2326,19 +2305,14 @@ int transport_generic_new_cmd(struct se_cmd *cmd) | |||
| 2326 | * into the fabric for data transfers, go ahead and complete it right | 2305 | * into the fabric for data transfers, go ahead and complete it right |
| 2327 | * away. | 2306 | * away. |
| 2328 | */ | 2307 | */ |
| 2329 | if (!cmd->data_length) { | 2308 | if (!cmd->data_length && |
| 2309 | cmd->t_task_cdb[0] != REQUEST_SENSE && | ||
| 2310 | cmd->se_dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) { | ||
| 2330 | spin_lock_irq(&cmd->t_state_lock); | 2311 | spin_lock_irq(&cmd->t_state_lock); |
| 2331 | cmd->t_state = TRANSPORT_COMPLETE; | 2312 | cmd->t_state = TRANSPORT_COMPLETE; |
| 2332 | cmd->transport_state |= CMD_T_ACTIVE; | 2313 | cmd->transport_state |= CMD_T_ACTIVE; |
| 2333 | spin_unlock_irq(&cmd->t_state_lock); | 2314 | spin_unlock_irq(&cmd->t_state_lock); |
| 2334 | 2315 | ||
| 2335 | if (cmd->t_task_cdb[0] == REQUEST_SENSE) { | ||
| 2336 | u8 ua_asc = 0, ua_ascq = 0; | ||
| 2337 | |||
| 2338 | core_scsi3_ua_clear_for_request_sense(cmd, | ||
| 2339 | &ua_asc, &ua_ascq); | ||
| 2340 | } | ||
| 2341 | |||
| 2342 | INIT_WORK(&cmd->work, target_complete_ok_work); | 2316 | INIT_WORK(&cmd->work, target_complete_ok_work); |
| 2343 | queue_work(target_completion_wq, &cmd->work); | 2317 | queue_work(target_completion_wq, &cmd->work); |
| 2344 | return 0; | 2318 | return 0; |
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index d5c689d6217e..e309e8b0aaba 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c | |||
| @@ -132,6 +132,7 @@ | |||
| 132 | #define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */ | 132 | #define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */ |
| 133 | #define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ | 133 | #define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ |
| 134 | #define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ | 134 | #define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ |
| 135 | #define UFCR_DCEDTE (1<<6) /* DCE/DTE mode select */ | ||
| 135 | #define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ | 136 | #define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ |
| 136 | #define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) | 137 | #define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) |
| 137 | #define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ | 138 | #define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ |
| @@ -667,22 +668,11 @@ static void imx_break_ctl(struct uart_port *port, int break_state) | |||
| 667 | static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) | 668 | static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) |
| 668 | { | 669 | { |
| 669 | unsigned int val; | 670 | unsigned int val; |
| 670 | unsigned int ufcr_rfdiv; | ||
| 671 | |||
| 672 | /* set receiver / transmitter trigger level. | ||
| 673 | * RFDIV is set such way to satisfy requested uartclk value | ||
| 674 | */ | ||
| 675 | val = TXTL << 10 | RXTL; | ||
| 676 | ufcr_rfdiv = (clk_get_rate(sport->clk_per) + sport->port.uartclk / 2) | ||
| 677 | / sport->port.uartclk; | ||
| 678 | |||
| 679 | if(!ufcr_rfdiv) | ||
| 680 | ufcr_rfdiv = 1; | ||
| 681 | |||
| 682 | val |= UFCR_RFDIV_REG(ufcr_rfdiv); | ||
| 683 | 671 | ||
| 672 | /* set receiver / transmitter trigger level */ | ||
| 673 | val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE); | ||
| 674 | val |= TXTL << UFCR_TXTL_SHF | RXTL; | ||
| 684 | writel(val, sport->port.membase + UFCR); | 675 | writel(val, sport->port.membase + UFCR); |
| 685 | |||
| 686 | return 0; | 676 | return 0; |
| 687 | } | 677 | } |
| 688 | 678 | ||
| @@ -754,6 +744,7 @@ static int imx_startup(struct uart_port *port) | |||
| 754 | } | 744 | } |
| 755 | } | 745 | } |
| 756 | 746 | ||
| 747 | spin_lock_irqsave(&sport->port.lock, flags); | ||
| 757 | /* | 748 | /* |
| 758 | * Finally, clear and enable interrupts | 749 | * Finally, clear and enable interrupts |
| 759 | */ | 750 | */ |
| @@ -807,7 +798,6 @@ static int imx_startup(struct uart_port *port) | |||
| 807 | /* | 798 | /* |
| 808 | * Enable modem status interrupts | 799 | * Enable modem status interrupts |
| 809 | */ | 800 | */ |
| 810 | spin_lock_irqsave(&sport->port.lock,flags); | ||
| 811 | imx_enable_ms(&sport->port); | 801 | imx_enable_ms(&sport->port); |
| 812 | spin_unlock_irqrestore(&sport->port.lock,flags); | 802 | spin_unlock_irqrestore(&sport->port.lock,flags); |
| 813 | 803 | ||
| @@ -837,10 +827,13 @@ static void imx_shutdown(struct uart_port *port) | |||
| 837 | { | 827 | { |
| 838 | struct imx_port *sport = (struct imx_port *)port; | 828 | struct imx_port *sport = (struct imx_port *)port; |
| 839 | unsigned long temp; | 829 | unsigned long temp; |
| 830 | unsigned long flags; | ||
| 840 | 831 | ||
| 832 | spin_lock_irqsave(&sport->port.lock, flags); | ||
| 841 | temp = readl(sport->port.membase + UCR2); | 833 | temp = readl(sport->port.membase + UCR2); |
| 842 | temp &= ~(UCR2_TXEN); | 834 | temp &= ~(UCR2_TXEN); |
| 843 | writel(temp, sport->port.membase + UCR2); | 835 | writel(temp, sport->port.membase + UCR2); |
| 836 | spin_unlock_irqrestore(&sport->port.lock, flags); | ||
| 844 | 837 | ||
| 845 | if (USE_IRDA(sport)) { | 838 | if (USE_IRDA(sport)) { |
| 846 | struct imxuart_platform_data *pdata; | 839 | struct imxuart_platform_data *pdata; |
| @@ -869,12 +862,14 @@ static void imx_shutdown(struct uart_port *port) | |||
| 869 | * Disable all interrupts, port and break condition. | 862 | * Disable all interrupts, port and break condition. |
| 870 | */ | 863 | */ |
| 871 | 864 | ||
| 865 | spin_lock_irqsave(&sport->port.lock, flags); | ||
| 872 | temp = readl(sport->port.membase + UCR1); | 866 | temp = readl(sport->port.membase + UCR1); |
| 873 | temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); | 867 | temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); |
| 874 | if (USE_IRDA(sport)) | 868 | if (USE_IRDA(sport)) |
| 875 | temp &= ~(UCR1_IREN); | 869 | temp &= ~(UCR1_IREN); |
| 876 | 870 | ||
| 877 | writel(temp, sport->port.membase + UCR1); | 871 | writel(temp, sport->port.membase + UCR1); |
| 872 | spin_unlock_irqrestore(&sport->port.lock, flags); | ||
| 878 | } | 873 | } |
| 879 | 874 | ||
| 880 | static void | 875 | static void |
| @@ -1217,6 +1212,9 @@ imx_console_write(struct console *co, const char *s, unsigned int count) | |||
| 1217 | struct imx_port *sport = imx_ports[co->index]; | 1212 | struct imx_port *sport = imx_ports[co->index]; |
| 1218 | struct imx_port_ucrs old_ucr; | 1213 | struct imx_port_ucrs old_ucr; |
| 1219 | unsigned int ucr1; | 1214 | unsigned int ucr1; |
| 1215 | unsigned long flags; | ||
| 1216 | |||
| 1217 | spin_lock_irqsave(&sport->port.lock, flags); | ||
| 1220 | 1218 | ||
| 1221 | /* | 1219 | /* |
| 1222 | * First, save UCR1/2/3 and then disable interrupts | 1220 | * First, save UCR1/2/3 and then disable interrupts |
| @@ -1242,6 +1240,8 @@ imx_console_write(struct console *co, const char *s, unsigned int count) | |||
| 1242 | while (!(readl(sport->port.membase + USR2) & USR2_TXDC)); | 1240 | while (!(readl(sport->port.membase + USR2) & USR2_TXDC)); |
| 1243 | 1241 | ||
| 1244 | imx_port_ucrs_restore(&sport->port, &old_ucr); | 1242 | imx_port_ucrs_restore(&sport->port, &old_ucr); |
| 1243 | |||
| 1244 | spin_unlock_irqrestore(&sport->port.lock, flags); | ||
| 1245 | } | 1245 | } |
| 1246 | 1246 | ||
| 1247 | /* | 1247 | /* |
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index c7a032a4f0c5..d214448b677e 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c | |||
| @@ -78,8 +78,7 @@ static inline int ep_to_bit(struct ci13xxx *ci, int n) | |||
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | /** | 80 | /** |
| 81 | * hw_device_state: enables/disables interrupts & starts/stops device (execute | 81 | * hw_device_state: enables/disables interrupts (execute without interruption) |
| 82 | * without interruption) | ||
| 83 | * @dma: 0 => disable, !0 => enable and set dma engine | 82 | * @dma: 0 => disable, !0 => enable and set dma engine |
| 84 | * | 83 | * |
| 85 | * This function returns an error code | 84 | * This function returns an error code |
| @@ -91,9 +90,7 @@ static int hw_device_state(struct ci13xxx *ci, u32 dma) | |||
| 91 | /* interrupt, error, port change, reset, sleep/suspend */ | 90 | /* interrupt, error, port change, reset, sleep/suspend */ |
| 92 | hw_write(ci, OP_USBINTR, ~0, | 91 | hw_write(ci, OP_USBINTR, ~0, |
| 93 | USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI); | 92 | USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI); |
| 94 | hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS); | ||
| 95 | } else { | 93 | } else { |
| 96 | hw_write(ci, OP_USBCMD, USBCMD_RS, 0); | ||
| 97 | hw_write(ci, OP_USBINTR, ~0, 0); | 94 | hw_write(ci, OP_USBINTR, ~0, 0); |
| 98 | } | 95 | } |
| 99 | return 0; | 96 | return 0; |
| @@ -774,10 +771,7 @@ __acquires(mEp->lock) | |||
| 774 | { | 771 | { |
| 775 | struct ci13xxx_req *mReq, *mReqTemp; | 772 | struct ci13xxx_req *mReq, *mReqTemp; |
| 776 | struct ci13xxx_ep *mEpTemp = mEp; | 773 | struct ci13xxx_ep *mEpTemp = mEp; |
| 777 | int uninitialized_var(retval); | 774 | int retval = 0; |
| 778 | |||
| 779 | if (list_empty(&mEp->qh.queue)) | ||
| 780 | return -EINVAL; | ||
| 781 | 775 | ||
| 782 | list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue, | 776 | list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue, |
| 783 | queue) { | 777 | queue) { |
| @@ -1420,6 +1414,21 @@ static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA) | |||
| 1420 | return -ENOTSUPP; | 1414 | return -ENOTSUPP; |
| 1421 | } | 1415 | } |
| 1422 | 1416 | ||
| 1417 | /* Change Data+ pullup status | ||
| 1418 | * this func is used by usb_gadget_connect/disconnet | ||
| 1419 | */ | ||
| 1420 | static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_on) | ||
| 1421 | { | ||
| 1422 | struct ci13xxx *ci = container_of(_gadget, struct ci13xxx, gadget); | ||
| 1423 | |||
| 1424 | if (is_on) | ||
| 1425 | hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS); | ||
| 1426 | else | ||
| 1427 | hw_write(ci, OP_USBCMD, USBCMD_RS, 0); | ||
| 1428 | |||
| 1429 | return 0; | ||
| 1430 | } | ||
| 1431 | |||
| 1423 | static int ci13xxx_start(struct usb_gadget *gadget, | 1432 | static int ci13xxx_start(struct usb_gadget *gadget, |
| 1424 | struct usb_gadget_driver *driver); | 1433 | struct usb_gadget_driver *driver); |
| 1425 | static int ci13xxx_stop(struct usb_gadget *gadget, | 1434 | static int ci13xxx_stop(struct usb_gadget *gadget, |
| @@ -1432,6 +1441,7 @@ static int ci13xxx_stop(struct usb_gadget *gadget, | |||
| 1432 | static const struct usb_gadget_ops usb_gadget_ops = { | 1441 | static const struct usb_gadget_ops usb_gadget_ops = { |
| 1433 | .vbus_session = ci13xxx_vbus_session, | 1442 | .vbus_session = ci13xxx_vbus_session, |
| 1434 | .wakeup = ci13xxx_wakeup, | 1443 | .wakeup = ci13xxx_wakeup, |
| 1444 | .pullup = ci13xxx_pullup, | ||
| 1435 | .vbus_draw = ci13xxx_vbus_draw, | 1445 | .vbus_draw = ci13xxx_vbus_draw, |
| 1436 | .udc_start = ci13xxx_start, | 1446 | .udc_start = ci13xxx_start, |
| 1437 | .udc_stop = ci13xxx_stop, | 1447 | .udc_stop = ci13xxx_stop, |
| @@ -1455,7 +1465,12 @@ static int init_eps(struct ci13xxx *ci) | |||
| 1455 | 1465 | ||
| 1456 | mEp->ep.name = mEp->name; | 1466 | mEp->ep.name = mEp->name; |
| 1457 | mEp->ep.ops = &usb_ep_ops; | 1467 | mEp->ep.ops = &usb_ep_ops; |
| 1458 | mEp->ep.maxpacket = CTRL_PAYLOAD_MAX; | 1468 | /* |
| 1469 | * for ep0: maxP defined in desc, for other | ||
| 1470 | * eps, maxP is set by epautoconfig() called | ||
| 1471 | * by gadget layer | ||
| 1472 | */ | ||
| 1473 | mEp->ep.maxpacket = (unsigned short)~0; | ||
| 1459 | 1474 | ||
| 1460 | INIT_LIST_HEAD(&mEp->qh.queue); | 1475 | INIT_LIST_HEAD(&mEp->qh.queue); |
| 1461 | mEp->qh.ptr = dma_pool_alloc(ci->qh_pool, GFP_KERNEL, | 1476 | mEp->qh.ptr = dma_pool_alloc(ci->qh_pool, GFP_KERNEL, |
| @@ -1475,6 +1490,7 @@ static int init_eps(struct ci13xxx *ci) | |||
| 1475 | else | 1490 | else |
| 1476 | ci->ep0in = mEp; | 1491 | ci->ep0in = mEp; |
| 1477 | 1492 | ||
| 1493 | mEp->ep.maxpacket = CTRL_PAYLOAD_MAX; | ||
| 1478 | continue; | 1494 | continue; |
| 1479 | } | 1495 | } |
| 1480 | 1496 | ||
| @@ -1484,6 +1500,17 @@ static int init_eps(struct ci13xxx *ci) | |||
| 1484 | return retval; | 1500 | return retval; |
| 1485 | } | 1501 | } |
| 1486 | 1502 | ||
| 1503 | static void destroy_eps(struct ci13xxx *ci) | ||
| 1504 | { | ||
| 1505 | int i; | ||
| 1506 | |||
| 1507 | for (i = 0; i < ci->hw_ep_max; i++) { | ||
| 1508 | struct ci13xxx_ep *mEp = &ci->ci13xxx_ep[i]; | ||
| 1509 | |||
| 1510 | dma_pool_free(ci->qh_pool, mEp->qh.ptr, mEp->qh.dma); | ||
| 1511 | } | ||
| 1512 | } | ||
| 1513 | |||
| 1487 | /** | 1514 | /** |
| 1488 | * ci13xxx_start: register a gadget driver | 1515 | * ci13xxx_start: register a gadget driver |
| 1489 | * @gadget: our gadget | 1516 | * @gadget: our gadget |
| @@ -1691,7 +1718,7 @@ static int udc_start(struct ci13xxx *ci) | |||
| 1691 | if (ci->platdata->flags & CI13XXX_REQUIRE_TRANSCEIVER) { | 1718 | if (ci->platdata->flags & CI13XXX_REQUIRE_TRANSCEIVER) { |
| 1692 | if (ci->transceiver == NULL) { | 1719 | if (ci->transceiver == NULL) { |
| 1693 | retval = -ENODEV; | 1720 | retval = -ENODEV; |
| 1694 | goto free_pools; | 1721 | goto destroy_eps; |
| 1695 | } | 1722 | } |
| 1696 | } | 1723 | } |
| 1697 | 1724 | ||
| @@ -1729,7 +1756,7 @@ static int udc_start(struct ci13xxx *ci) | |||
| 1729 | 1756 | ||
| 1730 | remove_trans: | 1757 | remove_trans: |
| 1731 | if (!IS_ERR_OR_NULL(ci->transceiver)) { | 1758 | if (!IS_ERR_OR_NULL(ci->transceiver)) { |
| 1732 | otg_set_peripheral(ci->transceiver->otg, &ci->gadget); | 1759 | otg_set_peripheral(ci->transceiver->otg, NULL); |
| 1733 | if (ci->global_phy) | 1760 | if (ci->global_phy) |
| 1734 | usb_put_phy(ci->transceiver); | 1761 | usb_put_phy(ci->transceiver); |
| 1735 | } | 1762 | } |
| @@ -1742,6 +1769,8 @@ unreg_device: | |||
| 1742 | put_transceiver: | 1769 | put_transceiver: |
| 1743 | if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy) | 1770 | if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy) |
| 1744 | usb_put_phy(ci->transceiver); | 1771 | usb_put_phy(ci->transceiver); |
| 1772 | destroy_eps: | ||
| 1773 | destroy_eps(ci); | ||
| 1745 | free_pools: | 1774 | free_pools: |
| 1746 | dma_pool_destroy(ci->td_pool); | 1775 | dma_pool_destroy(ci->td_pool); |
| 1747 | free_qh_pool: | 1776 | free_qh_pool: |
| @@ -1756,18 +1785,12 @@ free_qh_pool: | |||
| 1756 | */ | 1785 | */ |
| 1757 | static void udc_stop(struct ci13xxx *ci) | 1786 | static void udc_stop(struct ci13xxx *ci) |
| 1758 | { | 1787 | { |
| 1759 | int i; | ||
| 1760 | |||
| 1761 | if (ci == NULL) | 1788 | if (ci == NULL) |
| 1762 | return; | 1789 | return; |
| 1763 | 1790 | ||
| 1764 | usb_del_gadget_udc(&ci->gadget); | 1791 | usb_del_gadget_udc(&ci->gadget); |
| 1765 | 1792 | ||
| 1766 | for (i = 0; i < ci->hw_ep_max; i++) { | 1793 | destroy_eps(ci); |
| 1767 | struct ci13xxx_ep *mEp = &ci->ci13xxx_ep[i]; | ||
| 1768 | |||
| 1769 | dma_pool_free(ci->qh_pool, mEp->qh.ptr, mEp->qh.dma); | ||
| 1770 | } | ||
| 1771 | 1794 | ||
| 1772 | dma_pool_destroy(ci->td_pool); | 1795 | dma_pool_destroy(ci->td_pool); |
| 1773 | dma_pool_destroy(ci->qh_pool); | 1796 | dma_pool_destroy(ci->qh_pool); |
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 65a55abb791f..5f0cb417b736 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c | |||
| @@ -109,12 +109,14 @@ static struct usb_driver wdm_driver; | |||
| 109 | /* return intfdata if we own the interface, else look up intf in the list */ | 109 | /* return intfdata if we own the interface, else look up intf in the list */ |
| 110 | static struct wdm_device *wdm_find_device(struct usb_interface *intf) | 110 | static struct wdm_device *wdm_find_device(struct usb_interface *intf) |
| 111 | { | 111 | { |
| 112 | struct wdm_device *desc = NULL; | 112 | struct wdm_device *desc; |
| 113 | 113 | ||
| 114 | spin_lock(&wdm_device_list_lock); | 114 | spin_lock(&wdm_device_list_lock); |
| 115 | list_for_each_entry(desc, &wdm_device_list, device_list) | 115 | list_for_each_entry(desc, &wdm_device_list, device_list) |
| 116 | if (desc->intf == intf) | 116 | if (desc->intf == intf) |
| 117 | break; | 117 | goto found; |
| 118 | desc = NULL; | ||
| 119 | found: | ||
| 118 | spin_unlock(&wdm_device_list_lock); | 120 | spin_unlock(&wdm_device_list_lock); |
| 119 | 121 | ||
| 120 | return desc; | 122 | return desc; |
| @@ -122,12 +124,14 @@ static struct wdm_device *wdm_find_device(struct usb_interface *intf) | |||
| 122 | 124 | ||
| 123 | static struct wdm_device *wdm_find_device_by_minor(int minor) | 125 | static struct wdm_device *wdm_find_device_by_minor(int minor) |
| 124 | { | 126 | { |
| 125 | struct wdm_device *desc = NULL; | 127 | struct wdm_device *desc; |
| 126 | 128 | ||
| 127 | spin_lock(&wdm_device_list_lock); | 129 | spin_lock(&wdm_device_list_lock); |
| 128 | list_for_each_entry(desc, &wdm_device_list, device_list) | 130 | list_for_each_entry(desc, &wdm_device_list, device_list) |
| 129 | if (desc->intf->minor == minor) | 131 | if (desc->intf->minor == minor) |
| 130 | break; | 132 | goto found; |
| 133 | desc = NULL; | ||
| 134 | found: | ||
| 131 | spin_unlock(&wdm_device_list_lock); | 135 | spin_unlock(&wdm_device_list_lock); |
| 132 | 136 | ||
| 133 | return desc; | 137 | return desc; |
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index d95696584762..3440812b4a84 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c | |||
| @@ -624,7 +624,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, | |||
| 624 | /* print devices for all busses */ | 624 | /* print devices for all busses */ |
| 625 | list_for_each_entry(bus, &usb_bus_list, bus_list) { | 625 | list_for_each_entry(bus, &usb_bus_list, bus_list) { |
| 626 | /* recurse through all children of the root hub */ | 626 | /* recurse through all children of the root hub */ |
| 627 | if (!bus->root_hub) | 627 | if (!bus_to_hcd(bus)->rh_registered) |
| 628 | continue; | 628 | continue; |
| 629 | usb_lock_device(bus->root_hub); | 629 | usb_lock_device(bus->root_hub); |
| 630 | ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, | 630 | ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, |
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index bc84106ac057..75ba2091f9b4 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
| @@ -1011,10 +1011,7 @@ static int register_root_hub(struct usb_hcd *hcd) | |||
| 1011 | if (retval) { | 1011 | if (retval) { |
| 1012 | dev_err (parent_dev, "can't register root hub for %s, %d\n", | 1012 | dev_err (parent_dev, "can't register root hub for %s, %d\n", |
| 1013 | dev_name(&usb_dev->dev), retval); | 1013 | dev_name(&usb_dev->dev), retval); |
| 1014 | } | 1014 | } else { |
| 1015 | mutex_unlock(&usb_bus_list_lock); | ||
| 1016 | |||
| 1017 | if (retval == 0) { | ||
| 1018 | spin_lock_irq (&hcd_root_hub_lock); | 1015 | spin_lock_irq (&hcd_root_hub_lock); |
| 1019 | hcd->rh_registered = 1; | 1016 | hcd->rh_registered = 1; |
| 1020 | spin_unlock_irq (&hcd_root_hub_lock); | 1017 | spin_unlock_irq (&hcd_root_hub_lock); |
| @@ -1023,6 +1020,7 @@ static int register_root_hub(struct usb_hcd *hcd) | |||
| 1023 | if (HCD_DEAD(hcd)) | 1020 | if (HCD_DEAD(hcd)) |
| 1024 | usb_hc_died (hcd); /* This time clean up */ | 1021 | usb_hc_died (hcd); /* This time clean up */ |
| 1025 | } | 1022 | } |
| 1023 | mutex_unlock(&usb_bus_list_lock); | ||
| 1026 | 1024 | ||
| 1027 | return retval; | 1025 | return retval; |
| 1028 | } | 1026 | } |
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index f15501f4c585..e77a8e8eaa23 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c | |||
| @@ -71,6 +71,10 @@ static const struct usb_device_id usb_quirk_list[] = { | |||
| 71 | { USB_DEVICE(0x04b4, 0x0526), .driver_info = | 71 | { USB_DEVICE(0x04b4, 0x0526), .driver_info = |
| 72 | USB_QUIRK_CONFIG_INTF_STRINGS }, | 72 | USB_QUIRK_CONFIG_INTF_STRINGS }, |
| 73 | 73 | ||
| 74 | /* Microchip Joss Optical infrared touchboard device */ | ||
| 75 | { USB_DEVICE(0x04d8, 0x000c), .driver_info = | ||
| 76 | USB_QUIRK_CONFIG_INTF_STRINGS }, | ||
| 77 | |||
| 74 | /* Samsung Android phone modem - ID conflict with SPH-I500 */ | 78 | /* Samsung Android phone modem - ID conflict with SPH-I500 */ |
| 75 | { USB_DEVICE(0x04e8, 0x6601), .driver_info = | 79 | { USB_DEVICE(0x04e8, 0x6601), .driver_info = |
| 76 | USB_QUIRK_CONFIG_INTF_STRINGS }, | 80 | USB_QUIRK_CONFIG_INTF_STRINGS }, |
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index c34452a7304f..a68ff53124dc 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c | |||
| @@ -436,16 +436,21 @@ static int __devinit dwc3_probe(struct platform_device *pdev) | |||
| 436 | dev_err(dev, "missing IRQ\n"); | 436 | dev_err(dev, "missing IRQ\n"); |
| 437 | return -ENODEV; | 437 | return -ENODEV; |
| 438 | } | 438 | } |
| 439 | dwc->xhci_resources[1] = *res; | 439 | dwc->xhci_resources[1].start = res->start; |
| 440 | dwc->xhci_resources[1].end = res->end; | ||
| 441 | dwc->xhci_resources[1].flags = res->flags; | ||
| 442 | dwc->xhci_resources[1].name = res->name; | ||
| 440 | 443 | ||
| 441 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 444 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 442 | if (!res) { | 445 | if (!res) { |
| 443 | dev_err(dev, "missing memory resource\n"); | 446 | dev_err(dev, "missing memory resource\n"); |
| 444 | return -ENODEV; | 447 | return -ENODEV; |
| 445 | } | 448 | } |
| 446 | dwc->xhci_resources[0] = *res; | 449 | dwc->xhci_resources[0].start = res->start; |
| 447 | dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + | 450 | dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + |
| 448 | DWC3_XHCI_REGS_END; | 451 | DWC3_XHCI_REGS_END; |
| 452 | dwc->xhci_resources[0].flags = res->flags; | ||
| 453 | dwc->xhci_resources[0].name = res->name; | ||
| 449 | 454 | ||
| 450 | /* | 455 | /* |
| 451 | * Request memory region but exclude xHCI regs, | 456 | * Request memory region but exclude xHCI regs, |
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 9b94886b66e5..e4d5ca86b9da 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c | |||
| @@ -720,7 +720,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, | |||
| 720 | transferred = min_t(u32, ur->length, | 720 | transferred = min_t(u32, ur->length, |
| 721 | transfer_size - length); | 721 | transfer_size - length); |
| 722 | memcpy(ur->buf, dwc->ep0_bounce, transferred); | 722 | memcpy(ur->buf, dwc->ep0_bounce, transferred); |
| 723 | dwc->ep0_bounced = false; | ||
| 724 | } else { | 723 | } else { |
| 725 | transferred = ur->length - length; | 724 | transferred = ur->length - length; |
| 726 | } | 725 | } |
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 58fdfad96b4d..c2813c2b005a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c | |||
| @@ -263,8 +263,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, | |||
| 263 | if (req->request.status == -EINPROGRESS) | 263 | if (req->request.status == -EINPROGRESS) |
| 264 | req->request.status = status; | 264 | req->request.status = status; |
| 265 | 265 | ||
| 266 | usb_gadget_unmap_request(&dwc->gadget, &req->request, | 266 | if (dwc->ep0_bounced && dep->number == 0) |
| 267 | req->direction); | 267 | dwc->ep0_bounced = false; |
| 268 | else | ||
| 269 | usb_gadget_unmap_request(&dwc->gadget, &req->request, | ||
| 270 | req->direction); | ||
| 268 | 271 | ||
| 269 | dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n", | 272 | dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n", |
| 270 | req, dep->name, req->request.actual, | 273 | req, dep->name, req->request.actual, |
| @@ -1026,6 +1029,7 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc, | |||
| 1026 | if (list_empty(&dep->request_list)) { | 1029 | if (list_empty(&dep->request_list)) { |
| 1027 | dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n", | 1030 | dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n", |
| 1028 | dep->name); | 1031 | dep->name); |
| 1032 | dep->flags |= DWC3_EP_PENDING_REQUEST; | ||
| 1029 | return; | 1033 | return; |
| 1030 | } | 1034 | } |
| 1031 | 1035 | ||
| @@ -1089,6 +1093,17 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) | |||
| 1089 | if (dep->flags & DWC3_EP_PENDING_REQUEST) { | 1093 | if (dep->flags & DWC3_EP_PENDING_REQUEST) { |
| 1090 | int ret; | 1094 | int ret; |
| 1091 | 1095 | ||
| 1096 | /* | ||
| 1097 | * If xfernotready is already elapsed and it is a case | ||
| 1098 | * of isoc transfer, then issue END TRANSFER, so that | ||
| 1099 | * you can receive xfernotready again and can have | ||
| 1100 | * notion of current microframe. | ||
| 1101 | */ | ||
| 1102 | if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { | ||
| 1103 | dwc3_stop_active_transfer(dwc, dep->number); | ||
| 1104 | return 0; | ||
| 1105 | } | ||
| 1106 | |||
| 1092 | ret = __dwc3_gadget_kick_transfer(dep, 0, true); | 1107 | ret = __dwc3_gadget_kick_transfer(dep, 0, true); |
| 1093 | if (ret && ret != -EBUSY) { | 1108 | if (ret && ret != -EBUSY) { |
| 1094 | struct dwc3 *dwc = dep->dwc; | 1109 | struct dwc3 *dwc = dep->dwc; |
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index c9e66dfb02e6..1e35963bd4ed 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c | |||
| @@ -475,8 +475,7 @@ static int at91_ep_enable(struct usb_ep *_ep, | |||
| 475 | unsigned long flags; | 475 | unsigned long flags; |
| 476 | 476 | ||
| 477 | if (!_ep || !ep | 477 | if (!_ep || !ep |
| 478 | || !desc || ep->ep.desc | 478 | || !desc || _ep->name == ep0name |
| 479 | || _ep->name == ep0name | ||
| 480 | || desc->bDescriptorType != USB_DT_ENDPOINT | 479 | || desc->bDescriptorType != USB_DT_ENDPOINT |
| 481 | || (maxpacket = usb_endpoint_maxp(desc)) == 0 | 480 | || (maxpacket = usb_endpoint_maxp(desc)) == 0 |
| 482 | || maxpacket > ep->maxpacket) { | 481 | || maxpacket > ep->maxpacket) { |
| @@ -530,7 +529,6 @@ ok: | |||
| 530 | tmp |= AT91_UDP_EPEDS; | 529 | tmp |= AT91_UDP_EPEDS; |
| 531 | __raw_writel(tmp, ep->creg); | 530 | __raw_writel(tmp, ep->creg); |
| 532 | 531 | ||
| 533 | ep->ep.desc = desc; | ||
| 534 | ep->ep.maxpacket = maxpacket; | 532 | ep->ep.maxpacket = maxpacket; |
| 535 | 533 | ||
| 536 | /* | 534 | /* |
| @@ -1635,7 +1633,6 @@ static int at91_start(struct usb_gadget *gadget, | |||
| 1635 | udc->driver = driver; | 1633 | udc->driver = driver; |
| 1636 | udc->gadget.dev.driver = &driver->driver; | 1634 | udc->gadget.dev.driver = &driver->driver; |
| 1637 | udc->gadget.dev.of_node = udc->pdev->dev.of_node; | 1635 | udc->gadget.dev.of_node = udc->pdev->dev.of_node; |
| 1638 | dev_set_drvdata(&udc->gadget.dev, &driver->driver); | ||
| 1639 | udc->enabled = 1; | 1636 | udc->enabled = 1; |
| 1640 | udc->selfpowered = 1; | 1637 | udc->selfpowered = 1; |
| 1641 | 1638 | ||
| @@ -1656,7 +1653,6 @@ static int at91_stop(struct usb_gadget *gadget, | |||
| 1656 | spin_unlock_irqrestore(&udc->lock, flags); | 1653 | spin_unlock_irqrestore(&udc->lock, flags); |
| 1657 | 1654 | ||
| 1658 | udc->gadget.dev.driver = NULL; | 1655 | udc->gadget.dev.driver = NULL; |
| 1659 | dev_set_drvdata(&udc->gadget.dev, NULL); | ||
| 1660 | udc->driver = NULL; | 1656 | udc->driver = NULL; |
| 1661 | 1657 | ||
| 1662 | DBG("unbound from %s\n", driver->driver.name); | 1658 | DBG("unbound from %s\n", driver->driver.name); |
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index b799106027ad..afdbb1cbf5d9 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c | |||
| @@ -1916,6 +1916,27 @@ done: | |||
| 1916 | return retval; | 1916 | return retval; |
| 1917 | } | 1917 | } |
| 1918 | 1918 | ||
| 1919 | /* usb 3.0 root hub device descriptor */ | ||
| 1920 | struct { | ||
| 1921 | struct usb_bos_descriptor bos; | ||
| 1922 | struct usb_ss_cap_descriptor ss_cap; | ||
| 1923 | } __packed usb3_bos_desc = { | ||
| 1924 | |||
| 1925 | .bos = { | ||
| 1926 | .bLength = USB_DT_BOS_SIZE, | ||
| 1927 | .bDescriptorType = USB_DT_BOS, | ||
| 1928 | .wTotalLength = cpu_to_le16(sizeof(usb3_bos_desc)), | ||
| 1929 | .bNumDeviceCaps = 1, | ||
| 1930 | }, | ||
| 1931 | .ss_cap = { | ||
| 1932 | .bLength = USB_DT_USB_SS_CAP_SIZE, | ||
| 1933 | .bDescriptorType = USB_DT_DEVICE_CAPABILITY, | ||
| 1934 | .bDevCapabilityType = USB_SS_CAP_TYPE, | ||
| 1935 | .wSpeedSupported = cpu_to_le16(USB_5GBPS_OPERATION), | ||
| 1936 | .bFunctionalitySupport = ilog2(USB_5GBPS_OPERATION), | ||
| 1937 | }, | ||
| 1938 | }; | ||
| 1939 | |||
| 1919 | static inline void | 1940 | static inline void |
| 1920 | ss_hub_descriptor(struct usb_hub_descriptor *desc) | 1941 | ss_hub_descriptor(struct usb_hub_descriptor *desc) |
| 1921 | { | 1942 | { |
| @@ -2006,6 +2027,18 @@ static int dummy_hub_control( | |||
| 2006 | else | 2027 | else |
| 2007 | hub_descriptor((struct usb_hub_descriptor *) buf); | 2028 | hub_descriptor((struct usb_hub_descriptor *) buf); |
| 2008 | break; | 2029 | break; |
| 2030 | |||
| 2031 | case DeviceRequest | USB_REQ_GET_DESCRIPTOR: | ||
| 2032 | if (hcd->speed != HCD_USB3) | ||
| 2033 | goto error; | ||
| 2034 | |||
| 2035 | if ((wValue >> 8) != USB_DT_BOS) | ||
| 2036 | goto error; | ||
| 2037 | |||
| 2038 | memcpy(buf, &usb3_bos_desc, sizeof(usb3_bos_desc)); | ||
| 2039 | retval = sizeof(usb3_bos_desc); | ||
| 2040 | break; | ||
| 2041 | |||
| 2009 | case GetHubStatus: | 2042 | case GetHubStatus: |
| 2010 | *(__le32 *) buf = cpu_to_le32(0); | 2043 | *(__le32 *) buf = cpu_to_le32(0); |
| 2011 | break; | 2044 | break; |
| @@ -2503,10 +2536,8 @@ static int dummy_hcd_probe(struct platform_device *pdev) | |||
| 2503 | hs_hcd->has_tt = 1; | 2536 | hs_hcd->has_tt = 1; |
| 2504 | 2537 | ||
| 2505 | retval = usb_add_hcd(hs_hcd, 0, 0); | 2538 | retval = usb_add_hcd(hs_hcd, 0, 0); |
| 2506 | if (retval != 0) { | 2539 | if (retval) |
| 2507 | usb_put_hcd(hs_hcd); | 2540 | goto put_usb2_hcd; |
| 2508 | return retval; | ||
| 2509 | } | ||
| 2510 | 2541 | ||
| 2511 | if (mod_data.is_super_speed) { | 2542 | if (mod_data.is_super_speed) { |
| 2512 | ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev, | 2543 | ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev, |
| @@ -2525,6 +2556,8 @@ static int dummy_hcd_probe(struct platform_device *pdev) | |||
| 2525 | put_usb3_hcd: | 2556 | put_usb3_hcd: |
| 2526 | usb_put_hcd(ss_hcd); | 2557 | usb_put_hcd(ss_hcd); |
| 2527 | dealloc_usb2_hcd: | 2558 | dealloc_usb2_hcd: |
| 2559 | usb_remove_hcd(hs_hcd); | ||
| 2560 | put_usb2_hcd: | ||
| 2528 | usb_put_hcd(hs_hcd); | 2561 | usb_put_hcd(hs_hcd); |
| 2529 | the_controller.hs_hcd = the_controller.ss_hcd = NULL; | 2562 | the_controller.hs_hcd = the_controller.ss_hcd = NULL; |
| 2530 | return retval; | 2563 | return retval; |
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 8adc79d1b402..829aba75a6df 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c | |||
| @@ -34,11 +34,15 @@ | |||
| 34 | /* Debugging ****************************************************************/ | 34 | /* Debugging ****************************************************************/ |
| 35 | 35 | ||
| 36 | #ifdef VERBOSE_DEBUG | 36 | #ifdef VERBOSE_DEBUG |
| 37 | #ifndef pr_vdebug | ||
| 37 | # define pr_vdebug pr_debug | 38 | # define pr_vdebug pr_debug |
| 39 | #endif /* pr_vdebug */ | ||
| 38 | # define ffs_dump_mem(prefix, ptr, len) \ | 40 | # define ffs_dump_mem(prefix, ptr, len) \ |
| 39 | print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len) | 41 | print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len) |
| 40 | #else | 42 | #else |
| 43 | #ifndef pr_vdebug | ||
| 41 | # define pr_vdebug(...) do { } while (0) | 44 | # define pr_vdebug(...) do { } while (0) |
| 45 | #endif /* pr_vdebug */ | ||
| 42 | # define ffs_dump_mem(prefix, ptr, len) do { } while (0) | 46 | # define ffs_dump_mem(prefix, ptr, len) do { } while (0) |
| 43 | #endif /* VERBOSE_DEBUG */ | 47 | #endif /* VERBOSE_DEBUG */ |
| 44 | 48 | ||
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index b13e0bb5f5b8..0bb617e1dda2 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c | |||
| @@ -3599,6 +3599,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) | |||
| 3599 | 3599 | ||
| 3600 | if (hsotg->num_of_eps == 0) { | 3600 | if (hsotg->num_of_eps == 0) { |
| 3601 | dev_err(dev, "wrong number of EPs (zero)\n"); | 3601 | dev_err(dev, "wrong number of EPs (zero)\n"); |
| 3602 | ret = -EINVAL; | ||
| 3602 | goto err_supplies; | 3603 | goto err_supplies; |
| 3603 | } | 3604 | } |
| 3604 | 3605 | ||
| @@ -3606,6 +3607,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) | |||
| 3606 | GFP_KERNEL); | 3607 | GFP_KERNEL); |
| 3607 | if (!eps) { | 3608 | if (!eps) { |
| 3608 | dev_err(dev, "cannot get memory\n"); | 3609 | dev_err(dev, "cannot get memory\n"); |
| 3610 | ret = -ENOMEM; | ||
| 3609 | goto err_supplies; | 3611 | goto err_supplies; |
| 3610 | } | 3612 | } |
| 3611 | 3613 | ||
| @@ -3622,6 +3624,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) | |||
| 3622 | GFP_KERNEL); | 3624 | GFP_KERNEL); |
| 3623 | if (!hsotg->ctrl_req) { | 3625 | if (!hsotg->ctrl_req) { |
| 3624 | dev_err(dev, "failed to allocate ctrl req\n"); | 3626 | dev_err(dev, "failed to allocate ctrl req\n"); |
| 3627 | ret = -ENOMEM; | ||
| 3625 | goto err_ep_mem; | 3628 | goto err_ep_mem; |
| 3626 | } | 3629 | } |
| 3627 | 3630 | ||
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 5b3f5fffea92..da6d479ff9a6 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c | |||
| @@ -132,11 +132,15 @@ static unsigned n_ports; | |||
| 132 | 132 | ||
| 133 | 133 | ||
| 134 | #ifdef VERBOSE_DEBUG | 134 | #ifdef VERBOSE_DEBUG |
| 135 | #ifndef pr_vdebug | ||
| 135 | #define pr_vdebug(fmt, arg...) \ | 136 | #define pr_vdebug(fmt, arg...) \ |
| 136 | pr_debug(fmt, ##arg) | 137 | pr_debug(fmt, ##arg) |
| 138 | #endif /* pr_vdebug */ | ||
| 137 | #else | 139 | #else |
| 140 | #ifndef pr_vdebig | ||
| 138 | #define pr_vdebug(fmt, arg...) \ | 141 | #define pr_vdebug(fmt, arg...) \ |
| 139 | ({ if (0) pr_debug(fmt, ##arg); }) | 142 | ({ if (0) pr_debug(fmt, ##arg); }) |
| 143 | #endif /* pr_vdebug */ | ||
| 140 | #endif | 144 | #endif |
| 141 | 145 | ||
| 142 | /*-------------------------------------------------------------------------*/ | 146 | /*-------------------------------------------------------------------------*/ |
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 9bc39ca460c8..4b66374bdc8e 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c | |||
| @@ -128,9 +128,17 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
| 128 | else { | 128 | else { |
| 129 | qtd = list_entry (qh->qtd_list.next, | 129 | qtd = list_entry (qh->qtd_list.next, |
| 130 | struct ehci_qtd, qtd_list); | 130 | struct ehci_qtd, qtd_list); |
| 131 | /* first qtd may already be partially processed */ | 131 | /* |
| 132 | if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current) | 132 | * first qtd may already be partially processed. |
| 133 | * If we come here during unlink, the QH overlay region | ||
| 134 | * might have reference to the just unlinked qtd. The | ||
| 135 | * qtd is updated in qh_completions(). Update the QH | ||
| 136 | * overlay here. | ||
| 137 | */ | ||
| 138 | if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current) { | ||
| 139 | qh->hw->hw_qtd_next = qtd->hw_next; | ||
| 133 | qtd = NULL; | 140 | qtd = NULL; |
| 141 | } | ||
| 134 | } | 142 | } |
| 135 | 143 | ||
| 136 | if (qtd) | 144 | if (qtd) |
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index a665b3eaa746..0bf72f943b00 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c | |||
| @@ -467,7 +467,8 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) | |||
| 467 | /* From the GPIO notifying the over-current situation, find | 467 | /* From the GPIO notifying the over-current situation, find |
| 468 | * out the corresponding port */ | 468 | * out the corresponding port */ |
| 469 | at91_for_each_port(port) { | 469 | at91_for_each_port(port) { |
| 470 | if (gpio_to_irq(pdata->overcurrent_pin[port]) == irq) { | 470 | if (gpio_is_valid(pdata->overcurrent_pin[port]) && |
| 471 | gpio_to_irq(pdata->overcurrent_pin[port]) == irq) { | ||
| 471 | gpio = pdata->overcurrent_pin[port]; | 472 | gpio = pdata->overcurrent_pin[port]; |
| 472 | break; | 473 | break; |
| 473 | } | 474 | } |
| @@ -570,6 +571,16 @@ static int __devinit ohci_hcd_at91_drv_probe(struct platform_device *pdev) | |||
| 570 | 571 | ||
| 571 | if (pdata) { | 572 | if (pdata) { |
| 572 | at91_for_each_port(i) { | 573 | at91_for_each_port(i) { |
| 574 | /* | ||
| 575 | * do not configure PIO if not in relation with | ||
| 576 | * real USB port on board | ||
| 577 | */ | ||
| 578 | if (i >= pdata->ports) { | ||
| 579 | pdata->vbus_pin[i] = -EINVAL; | ||
| 580 | pdata->overcurrent_pin[i] = -EINVAL; | ||
| 581 | break; | ||
| 582 | } | ||
| 583 | |||
| 573 | if (!gpio_is_valid(pdata->vbus_pin[i])) | 584 | if (!gpio_is_valid(pdata->vbus_pin[i])) |
| 574 | continue; | 585 | continue; |
| 575 | gpio = pdata->vbus_pin[i]; | 586 | gpio = pdata->vbus_pin[i]; |
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index c5e9e4a76f14..966d1484ee79 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c | |||
| @@ -75,7 +75,9 @@ | |||
| 75 | #define NB_PIF0_PWRDOWN_1 0x01100013 | 75 | #define NB_PIF0_PWRDOWN_1 0x01100013 |
| 76 | 76 | ||
| 77 | #define USB_INTEL_XUSB2PR 0xD0 | 77 | #define USB_INTEL_XUSB2PR 0xD0 |
| 78 | #define USB_INTEL_USB2PRM 0xD4 | ||
| 78 | #define USB_INTEL_USB3_PSSEN 0xD8 | 79 | #define USB_INTEL_USB3_PSSEN 0xD8 |
| 80 | #define USB_INTEL_USB3PRM 0xDC | ||
| 79 | 81 | ||
| 80 | static struct amd_chipset_info { | 82 | static struct amd_chipset_info { |
| 81 | struct pci_dev *nb_dev; | 83 | struct pci_dev *nb_dev; |
| @@ -772,10 +774,18 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) | |||
| 772 | return; | 774 | return; |
| 773 | } | 775 | } |
| 774 | 776 | ||
| 775 | ports_available = 0xffffffff; | 777 | /* Read USB3PRM, the USB 3.0 Port Routing Mask Register |
| 778 | * Indicate the ports that can be changed from OS. | ||
| 779 | */ | ||
| 780 | pci_read_config_dword(xhci_pdev, USB_INTEL_USB3PRM, | ||
| 781 | &ports_available); | ||
| 782 | |||
| 783 | dev_dbg(&xhci_pdev->dev, "Configurable ports to enable SuperSpeed: 0x%x\n", | ||
| 784 | ports_available); | ||
| 785 | |||
| 776 | /* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable | 786 | /* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable |
| 777 | * Register, to turn on SuperSpeed terminations for all | 787 | * Register, to turn on SuperSpeed terminations for the |
| 778 | * available ports. | 788 | * switchable ports. |
| 779 | */ | 789 | */ |
| 780 | pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, | 790 | pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, |
| 781 | cpu_to_le32(ports_available)); | 791 | cpu_to_le32(ports_available)); |
| @@ -785,7 +795,16 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) | |||
| 785 | dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled " | 795 | dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled " |
| 786 | "under xHCI: 0x%x\n", ports_available); | 796 | "under xHCI: 0x%x\n", ports_available); |
| 787 | 797 | ||
| 788 | ports_available = 0xffffffff; | 798 | /* Read XUSB2PRM, xHCI USB 2.0 Port Routing Mask Register |
| 799 | * Indicate the USB 2.0 ports to be controlled by the xHCI host. | ||
| 800 | */ | ||
| 801 | |||
| 802 | pci_read_config_dword(xhci_pdev, USB_INTEL_USB2PRM, | ||
| 803 | &ports_available); | ||
| 804 | |||
| 805 | dev_dbg(&xhci_pdev->dev, "Configurable USB 2.0 ports to hand over to xCHI: 0x%x\n", | ||
| 806 | ports_available); | ||
| 807 | |||
| 789 | /* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to | 808 | /* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to |
| 790 | * switch the USB 2.0 power and data lines over to the xHCI | 809 | * switch the USB 2.0 power and data lines over to the xHCI |
| 791 | * host. | 810 | * host. |
| @@ -822,12 +841,12 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) | |||
| 822 | void __iomem *op_reg_base; | 841 | void __iomem *op_reg_base; |
| 823 | u32 val; | 842 | u32 val; |
| 824 | int timeout; | 843 | int timeout; |
| 844 | int len = pci_resource_len(pdev, 0); | ||
| 825 | 845 | ||
| 826 | if (!mmio_resource_enabled(pdev, 0)) | 846 | if (!mmio_resource_enabled(pdev, 0)) |
| 827 | return; | 847 | return; |
| 828 | 848 | ||
| 829 | base = ioremap_nocache(pci_resource_start(pdev, 0), | 849 | base = ioremap_nocache(pci_resource_start(pdev, 0), len); |
| 830 | pci_resource_len(pdev, 0)); | ||
| 831 | if (base == NULL) | 850 | if (base == NULL) |
| 832 | return; | 851 | return; |
| 833 | 852 | ||
| @@ -837,9 +856,17 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) | |||
| 837 | */ | 856 | */ |
| 838 | ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET); | 857 | ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET); |
| 839 | do { | 858 | do { |
| 859 | if ((ext_cap_offset + sizeof(val)) > len) { | ||
| 860 | /* We're reading garbage from the controller */ | ||
| 861 | dev_warn(&pdev->dev, | ||
| 862 | "xHCI controller failing to respond"); | ||
| 863 | return; | ||
| 864 | } | ||
| 865 | |||
| 840 | if (!ext_cap_offset) | 866 | if (!ext_cap_offset) |
| 841 | /* We've reached the end of the extended capabilities */ | 867 | /* We've reached the end of the extended capabilities */ |
| 842 | goto hc_init; | 868 | goto hc_init; |
| 869 | |||
| 843 | val = readl(base + ext_cap_offset); | 870 | val = readl(base + ext_cap_offset); |
| 844 | if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY) | 871 | if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY) |
| 845 | break; | 872 | break; |
| @@ -870,9 +897,10 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) | |||
| 870 | /* Disable any BIOS SMIs and clear all SMI events*/ | 897 | /* Disable any BIOS SMIs and clear all SMI events*/ |
| 871 | writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); | 898 | writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); |
| 872 | 899 | ||
| 900 | hc_init: | ||
| 873 | if (usb_is_intel_switchable_xhci(pdev)) | 901 | if (usb_is_intel_switchable_xhci(pdev)) |
| 874 | usb_enable_xhci_ports(pdev); | 902 | usb_enable_xhci_ports(pdev); |
| 875 | hc_init: | 903 | |
| 876 | op_reg_base = base + XHCI_HC_LENGTH(readl(base)); | 904 | op_reg_base = base + XHCI_HC_LENGTH(readl(base)); |
| 877 | 905 | ||
| 878 | /* Wait for the host controller to be ready before writing any | 906 | /* Wait for the host controller to be ready before writing any |
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index ef004a5de20f..7f69a39163ce 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h | |||
| @@ -15,6 +15,7 @@ void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); | |||
| 15 | static inline void usb_amd_quirk_pll_disable(void) {} | 15 | static inline void usb_amd_quirk_pll_disable(void) {} |
| 16 | static inline void usb_amd_quirk_pll_enable(void) {} | 16 | static inline void usb_amd_quirk_pll_enable(void) {} |
| 17 | static inline void usb_amd_dev_put(void) {} | 17 | static inline void usb_amd_dev_put(void) {} |
| 18 | static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {} | ||
| 18 | #endif /* CONFIG_PCI */ | 19 | #endif /* CONFIG_PCI */ |
| 19 | 20 | ||
| 20 | #endif /* __LINUX_USB_PCI_QUIRKS_H */ | 21 | #endif /* __LINUX_USB_PCI_QUIRKS_H */ |
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 74bfc868b7ad..d5eb357aa5c4 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
| @@ -493,11 +493,48 @@ static void xhci_hub_report_link_state(u32 *status, u32 status_reg) | |||
| 493 | * when this bit is set. | 493 | * when this bit is set. |
| 494 | */ | 494 | */ |
| 495 | pls |= USB_PORT_STAT_CONNECTION; | 495 | pls |= USB_PORT_STAT_CONNECTION; |
| 496 | } else { | ||
| 497 | /* | ||
| 498 | * If CAS bit isn't set but the Port is already at | ||
| 499 | * Compliance Mode, fake a connection so the USB core | ||
| 500 | * notices the Compliance state and resets the port. | ||
| 501 | * This resolves an issue generated by the SN65LVPE502CP | ||
| 502 | * in which sometimes the port enters compliance mode | ||
| 503 | * caused by a delay on the host-device negotiation. | ||
| 504 | */ | ||
| 505 | if (pls == USB_SS_PORT_LS_COMP_MOD) | ||
| 506 | pls |= USB_PORT_STAT_CONNECTION; | ||
| 496 | } | 507 | } |
| 508 | |||
| 497 | /* update status field */ | 509 | /* update status field */ |
| 498 | *status |= pls; | 510 | *status |= pls; |
| 499 | } | 511 | } |
| 500 | 512 | ||
| 513 | /* | ||
| 514 | * Function for Compliance Mode Quirk. | ||
| 515 | * | ||
| 516 | * This Function verifies if all xhc USB3 ports have entered U0, if so, | ||
| 517 | * the compliance mode timer is deleted. A port won't enter | ||
| 518 | * compliance mode if it has previously entered U0. | ||
| 519 | */ | ||
| 520 | void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex) | ||
| 521 | { | ||
| 522 | u32 all_ports_seen_u0 = ((1 << xhci->num_usb3_ports)-1); | ||
| 523 | bool port_in_u0 = ((status & PORT_PLS_MASK) == XDEV_U0); | ||
| 524 | |||
| 525 | if (!(xhci->quirks & XHCI_COMP_MODE_QUIRK)) | ||
| 526 | return; | ||
| 527 | |||
| 528 | if ((xhci->port_status_u0 != all_ports_seen_u0) && port_in_u0) { | ||
| 529 | xhci->port_status_u0 |= 1 << wIndex; | ||
| 530 | if (xhci->port_status_u0 == all_ports_seen_u0) { | ||
| 531 | del_timer_sync(&xhci->comp_mode_recovery_timer); | ||
| 532 | xhci_dbg(xhci, "All USB3 ports have entered U0 already!\n"); | ||
| 533 | xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted.\n"); | ||
| 534 | } | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 501 | int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | 538 | int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, |
| 502 | u16 wIndex, char *buf, u16 wLength) | 539 | u16 wIndex, char *buf, u16 wLength) |
| 503 | { | 540 | { |
| @@ -651,6 +688,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
| 651 | /* Update Port Link State for super speed ports*/ | 688 | /* Update Port Link State for super speed ports*/ |
| 652 | if (hcd->speed == HCD_USB3) { | 689 | if (hcd->speed == HCD_USB3) { |
| 653 | xhci_hub_report_link_state(&status, temp); | 690 | xhci_hub_report_link_state(&status, temp); |
| 691 | /* | ||
| 692 | * Verify if all USB3 Ports Have entered U0 already. | ||
| 693 | * Delete Compliance Mode Timer if so. | ||
| 694 | */ | ||
| 695 | xhci_del_comp_mod_timer(xhci, temp, wIndex); | ||
| 654 | } | 696 | } |
| 655 | if (bus_state->port_c_suspend & (1 << wIndex)) | 697 | if (bus_state->port_c_suspend & (1 << wIndex)) |
| 656 | status |= 1 << USB_PORT_FEAT_C_SUSPEND; | 698 | status |= 1 << USB_PORT_FEAT_C_SUSPEND; |
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 689bc18b051d..df90fe51b4aa 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c | |||
| @@ -118,7 +118,7 @@ static int xhci_plat_probe(struct platform_device *pdev) | |||
| 118 | goto put_hcd; | 118 | goto put_hcd; |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); | 121 | hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); |
| 122 | if (!hcd->regs) { | 122 | if (!hcd->regs) { |
| 123 | dev_dbg(&pdev->dev, "error mapping memory\n"); | 123 | dev_dbg(&pdev->dev, "error mapping memory\n"); |
| 124 | ret = -EFAULT; | 124 | ret = -EFAULT; |
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index c59d5b5b6c7d..6ece0ed288d4 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
| 27 | #include <linux/moduleparam.h> | 27 | #include <linux/moduleparam.h> |
| 28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
| 29 | #include <linux/dmi.h> | ||
| 29 | 30 | ||
| 30 | #include "xhci.h" | 31 | #include "xhci.h" |
| 31 | 32 | ||
| @@ -398,6 +399,95 @@ static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) | |||
| 398 | 399 | ||
| 399 | #endif | 400 | #endif |
| 400 | 401 | ||
| 402 | static void compliance_mode_recovery(unsigned long arg) | ||
| 403 | { | ||
| 404 | struct xhci_hcd *xhci; | ||
| 405 | struct usb_hcd *hcd; | ||
| 406 | u32 temp; | ||
| 407 | int i; | ||
| 408 | |||
| 409 | xhci = (struct xhci_hcd *)arg; | ||
| 410 | |||
| 411 | for (i = 0; i < xhci->num_usb3_ports; i++) { | ||
| 412 | temp = xhci_readl(xhci, xhci->usb3_ports[i]); | ||
| 413 | if ((temp & PORT_PLS_MASK) == USB_SS_PORT_LS_COMP_MOD) { | ||
| 414 | /* | ||
| 415 | * Compliance Mode Detected. Letting USB Core | ||
| 416 | * handle the Warm Reset | ||
| 417 | */ | ||
| 418 | xhci_dbg(xhci, "Compliance Mode Detected->Port %d!\n", | ||
| 419 | i + 1); | ||
| 420 | xhci_dbg(xhci, "Attempting Recovery routine!\n"); | ||
| 421 | hcd = xhci->shared_hcd; | ||
| 422 | |||
| 423 | if (hcd->state == HC_STATE_SUSPENDED) | ||
| 424 | usb_hcd_resume_root_hub(hcd); | ||
| 425 | |||
| 426 | usb_hcd_poll_rh_status(hcd); | ||
| 427 | } | ||
| 428 | } | ||
| 429 | |||
| 430 | if (xhci->port_status_u0 != ((1 << xhci->num_usb3_ports)-1)) | ||
| 431 | mod_timer(&xhci->comp_mode_recovery_timer, | ||
| 432 | jiffies + msecs_to_jiffies(COMP_MODE_RCVRY_MSECS)); | ||
| 433 | } | ||
| 434 | |||
| 435 | /* | ||
| 436 | * Quirk to work around issue generated by the SN65LVPE502CP USB3.0 re-driver | ||
| 437 | * that causes ports behind that hardware to enter compliance mode sometimes. | ||
| 438 | * The quirk creates a timer that polls every 2 seconds the link state of | ||
| 439 | * each host controller's port and recovers it by issuing a Warm reset | ||
| 440 | * if Compliance mode is detected, otherwise the port will become "dead" (no | ||
| 441 | * device connections or disconnections will be detected anymore). Becasue no | ||
| 442 | * status event is generated when entering compliance mode (per xhci spec), | ||
| 443 | * this quirk is needed on systems that have the failing hardware installed. | ||
| 444 | */ | ||
| 445 | static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci) | ||
| 446 | { | ||
| 447 | xhci->port_status_u0 = 0; | ||
| 448 | init_timer(&xhci->comp_mode_recovery_timer); | ||
| 449 | |||
| 450 | xhci->comp_mode_recovery_timer.data = (unsigned long) xhci; | ||
| 451 | xhci->comp_mode_recovery_timer.function = compliance_mode_recovery; | ||
| 452 | xhci->comp_mode_recovery_timer.expires = jiffies + | ||
| 453 | msecs_to_jiffies(COMP_MODE_RCVRY_MSECS); | ||
| 454 | |||
| 455 | set_timer_slack(&xhci->comp_mode_recovery_timer, | ||
| 456 | msecs_to_jiffies(COMP_MODE_RCVRY_MSECS)); | ||
| 457 | add_timer(&xhci->comp_mode_recovery_timer); | ||
| 458 | xhci_dbg(xhci, "Compliance Mode Recovery Timer Initialized.\n"); | ||
| 459 | } | ||
| 460 | |||
| 461 | /* | ||
| 462 | * This function identifies the systems that have installed the SN65LVPE502CP | ||
| 463 | * USB3.0 re-driver and that need the Compliance Mode Quirk. | ||
| 464 | * Systems: | ||
| 465 | * Vendor: Hewlett-Packard -> System Models: Z420, Z620 and Z820 | ||
| 466 | */ | ||
| 467 | static bool compliance_mode_recovery_timer_quirk_check(void) | ||
| 468 | { | ||
| 469 | const char *dmi_product_name, *dmi_sys_vendor; | ||
| 470 | |||
| 471 | dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME); | ||
| 472 | dmi_sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR); | ||
| 473 | |||
| 474 | if (!(strstr(dmi_sys_vendor, "Hewlett-Packard"))) | ||
| 475 | return false; | ||
| 476 | |||
| 477 | if (strstr(dmi_product_name, "Z420") || | ||
| 478 | strstr(dmi_product_name, "Z620") || | ||
| 479 | strstr(dmi_product_name, "Z820")) | ||
| 480 | return true; | ||
| 481 | |||
| 482 | return false; | ||
| 483 | } | ||
| 484 | |||
| 485 | static int xhci_all_ports_seen_u0(struct xhci_hcd *xhci) | ||
| 486 | { | ||
| 487 | return (xhci->port_status_u0 == ((1 << xhci->num_usb3_ports)-1)); | ||
| 488 | } | ||
| 489 | |||
| 490 | |||
| 401 | /* | 491 | /* |
| 402 | * Initialize memory for HCD and xHC (one-time init). | 492 | * Initialize memory for HCD and xHC (one-time init). |
| 403 | * | 493 | * |
| @@ -421,6 +511,12 @@ int xhci_init(struct usb_hcd *hcd) | |||
| 421 | retval = xhci_mem_init(xhci, GFP_KERNEL); | 511 | retval = xhci_mem_init(xhci, GFP_KERNEL); |
| 422 | xhci_dbg(xhci, "Finished xhci_init\n"); | 512 | xhci_dbg(xhci, "Finished xhci_init\n"); |
| 423 | 513 | ||
| 514 | /* Initializing Compliance Mode Recovery Data If Needed */ | ||
| 515 | if (compliance_mode_recovery_timer_quirk_check()) { | ||
| 516 | xhci->quirks |= XHCI_COMP_MODE_QUIRK; | ||
| 517 | compliance_mode_recovery_timer_init(xhci); | ||
| 518 | } | ||
| 519 | |||
| 424 | return retval; | 520 | return retval; |
| 425 | } | 521 | } |
| 426 | 522 | ||
| @@ -629,6 +725,11 @@ void xhci_stop(struct usb_hcd *hcd) | |||
| 629 | del_timer_sync(&xhci->event_ring_timer); | 725 | del_timer_sync(&xhci->event_ring_timer); |
| 630 | #endif | 726 | #endif |
| 631 | 727 | ||
| 728 | /* Deleting Compliance Mode Recovery Timer */ | ||
| 729 | if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && | ||
| 730 | (!(xhci_all_ports_seen_u0(xhci)))) | ||
| 731 | del_timer_sync(&xhci->comp_mode_recovery_timer); | ||
| 732 | |||
| 632 | if (xhci->quirks & XHCI_AMD_PLL_FIX) | 733 | if (xhci->quirks & XHCI_AMD_PLL_FIX) |
| 633 | usb_amd_dev_put(); | 734 | usb_amd_dev_put(); |
| 634 | 735 | ||
| @@ -659,7 +760,7 @@ void xhci_shutdown(struct usb_hcd *hcd) | |||
| 659 | { | 760 | { |
| 660 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 761 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
| 661 | 762 | ||
| 662 | if (xhci->quirks && XHCI_SPURIOUS_REBOOT) | 763 | if (xhci->quirks & XHCI_SPURIOUS_REBOOT) |
| 663 | usb_disable_xhci_ports(to_pci_dev(hcd->self.controller)); | 764 | usb_disable_xhci_ports(to_pci_dev(hcd->self.controller)); |
| 664 | 765 | ||
| 665 | spin_lock_irq(&xhci->lock); | 766 | spin_lock_irq(&xhci->lock); |
| @@ -806,6 +907,16 @@ int xhci_suspend(struct xhci_hcd *xhci) | |||
| 806 | } | 907 | } |
| 807 | spin_unlock_irq(&xhci->lock); | 908 | spin_unlock_irq(&xhci->lock); |
| 808 | 909 | ||
| 910 | /* | ||
| 911 | * Deleting Compliance Mode Recovery Timer because the xHCI Host | ||
| 912 | * is about to be suspended. | ||
| 913 | */ | ||
| 914 | if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && | ||
| 915 | (!(xhci_all_ports_seen_u0(xhci)))) { | ||
| 916 | del_timer_sync(&xhci->comp_mode_recovery_timer); | ||
| 917 | xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted!\n"); | ||
| 918 | } | ||
| 919 | |||
| 809 | /* step 5: remove core well power */ | 920 | /* step 5: remove core well power */ |
| 810 | /* synchronize irq when using MSI-X */ | 921 | /* synchronize irq when using MSI-X */ |
| 811 | xhci_msix_sync_irqs(xhci); | 922 | xhci_msix_sync_irqs(xhci); |
| @@ -938,6 +1049,16 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) | |||
| 938 | usb_hcd_resume_root_hub(hcd); | 1049 | usb_hcd_resume_root_hub(hcd); |
| 939 | usb_hcd_resume_root_hub(xhci->shared_hcd); | 1050 | usb_hcd_resume_root_hub(xhci->shared_hcd); |
| 940 | } | 1051 | } |
| 1052 | |||
| 1053 | /* | ||
| 1054 | * If system is subject to the Quirk, Compliance Mode Timer needs to | ||
| 1055 | * be re-initialized Always after a system resume. Ports are subject | ||
| 1056 | * to suffer the Compliance Mode issue again. It doesn't matter if | ||
| 1057 | * ports have entered previously to U0 before system's suspension. | ||
| 1058 | */ | ||
| 1059 | if (xhci->quirks & XHCI_COMP_MODE_QUIRK) | ||
| 1060 | compliance_mode_recovery_timer_init(xhci); | ||
| 1061 | |||
| 941 | return retval; | 1062 | return retval; |
| 942 | } | 1063 | } |
| 943 | #endif /* CONFIG_PM */ | 1064 | #endif /* CONFIG_PM */ |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index c713256297ac..1a05908c6673 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
| @@ -1495,6 +1495,7 @@ struct xhci_hcd { | |||
| 1495 | #define XHCI_LPM_SUPPORT (1 << 11) | 1495 | #define XHCI_LPM_SUPPORT (1 << 11) |
| 1496 | #define XHCI_INTEL_HOST (1 << 12) | 1496 | #define XHCI_INTEL_HOST (1 << 12) |
| 1497 | #define XHCI_SPURIOUS_REBOOT (1 << 13) | 1497 | #define XHCI_SPURIOUS_REBOOT (1 << 13) |
| 1498 | #define XHCI_COMP_MODE_QUIRK (1 << 14) | ||
| 1498 | unsigned int num_active_eps; | 1499 | unsigned int num_active_eps; |
| 1499 | unsigned int limit_active_eps; | 1500 | unsigned int limit_active_eps; |
| 1500 | /* There are two roothubs to keep track of bus suspend info for */ | 1501 | /* There are two roothubs to keep track of bus suspend info for */ |
| @@ -1511,6 +1512,11 @@ struct xhci_hcd { | |||
| 1511 | unsigned sw_lpm_support:1; | 1512 | unsigned sw_lpm_support:1; |
| 1512 | /* support xHCI 1.0 spec USB2 hardware LPM */ | 1513 | /* support xHCI 1.0 spec USB2 hardware LPM */ |
| 1513 | unsigned hw_lpm_support:1; | 1514 | unsigned hw_lpm_support:1; |
| 1515 | /* Compliance Mode Recovery Data */ | ||
| 1516 | struct timer_list comp_mode_recovery_timer; | ||
| 1517 | u32 port_status_u0; | ||
| 1518 | /* Compliance Mode Timer Triggered every 2 seconds */ | ||
| 1519 | #define COMP_MODE_RCVRY_MSECS 2000 | ||
| 1514 | }; | 1520 | }; |
| 1515 | 1521 | ||
| 1516 | /* convert between an HCD pointer and the corresponding EHCI_HCD */ | 1522 | /* convert between an HCD pointer and the corresponding EHCI_HCD */ |
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 4bb717d0bd41..1ae378d5fc6f 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c | |||
| @@ -2049,7 +2049,7 @@ static int musb_urb_enqueue( | |||
| 2049 | * we only have work to do in the former case. | 2049 | * we only have work to do in the former case. |
| 2050 | */ | 2050 | */ |
| 2051 | spin_lock_irqsave(&musb->lock, flags); | 2051 | spin_lock_irqsave(&musb->lock, flags); |
| 2052 | if (hep->hcpriv) { | 2052 | if (hep->hcpriv || !next_urb(qh)) { |
| 2053 | /* some concurrent activity submitted another urb to hep... | 2053 | /* some concurrent activity submitted another urb to hep... |
| 2054 | * odd, rare, error prone, but legal. | 2054 | * odd, rare, error prone, but legal. |
| 2055 | */ | 2055 | */ |
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 57a608584e16..c1be687e00ec 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c | |||
| @@ -388,7 +388,7 @@ dma_controller_create(struct musb *musb, void __iomem *base) | |||
| 388 | struct platform_device *pdev = to_platform_device(dev); | 388 | struct platform_device *pdev = to_platform_device(dev); |
| 389 | int irq = platform_get_irq_byname(pdev, "dma"); | 389 | int irq = platform_get_irq_byname(pdev, "dma"); |
| 390 | 390 | ||
| 391 | if (irq == 0) { | 391 | if (irq <= 0) { |
| 392 | dev_err(dev, "No DMA interrupt line!\n"); | 392 | dev_err(dev, "No DMA interrupt line!\n"); |
| 393 | return NULL; | 393 | return NULL; |
| 394 | } | 394 | } |
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 1a1bd9cf40c5..341625442377 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c | |||
| @@ -1215,7 +1215,7 @@ static int __devinit tusb_probe(struct platform_device *pdev) | |||
| 1215 | ret = platform_device_add(musb); | 1215 | ret = platform_device_add(musb); |
| 1216 | if (ret) { | 1216 | if (ret) { |
| 1217 | dev_err(&pdev->dev, "failed to register musb device\n"); | 1217 | dev_err(&pdev->dev, "failed to register musb device\n"); |
| 1218 | goto err1; | 1218 | goto err2; |
| 1219 | } | 1219 | } |
| 1220 | 1220 | ||
| 1221 | return 0; | 1221 | return 0; |
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index ecd173032fd4..143c4e9e1be4 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c | |||
| @@ -818,7 +818,7 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done) | |||
| 818 | usbhs_pipe_is_dcp(pipe)) | 818 | usbhs_pipe_is_dcp(pipe)) |
| 819 | goto usbhsf_pio_prepare_push; | 819 | goto usbhsf_pio_prepare_push; |
| 820 | 820 | ||
| 821 | if (len % 4) /* 32bit alignment */ | 821 | if (len & 0x7) /* 8byte alignment */ |
| 822 | goto usbhsf_pio_prepare_push; | 822 | goto usbhsf_pio_prepare_push; |
| 823 | 823 | ||
| 824 | if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */ | 824 | if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */ |
| @@ -905,7 +905,7 @@ static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done) | |||
| 905 | /* use PIO if packet is less than pio_dma_border */ | 905 | /* use PIO if packet is less than pio_dma_border */ |
| 906 | len = usbhsf_fifo_rcv_len(priv, fifo); | 906 | len = usbhsf_fifo_rcv_len(priv, fifo); |
| 907 | len = min(pkt->length - pkt->actual, len); | 907 | len = min(pkt->length - pkt->actual, len); |
| 908 | if (len % 4) /* 32bit alignment */ | 908 | if (len & 0x7) /* 8byte alignment */ |
| 909 | goto usbhsf_pio_prepare_pop_unselect; | 909 | goto usbhsf_pio_prepare_pop_unselect; |
| 910 | 910 | ||
| 911 | if (len < usbhs_get_dparam(priv, pio_dma_border)) | 911 | if (len < usbhs_get_dparam(priv, pio_dma_border)) |
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 5620db6469e5..f906b3aec217 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
| @@ -704,6 +704,7 @@ static struct usb_device_id id_table_combined [] = { | |||
| 704 | { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) }, | 704 | { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) }, |
| 705 | { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) }, | 705 | { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) }, |
| 706 | { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) }, | 706 | { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) }, |
| 707 | { USB_DEVICE(FTDI_VID, FTDI_NZR_SEM_USB_PID) }, | ||
| 707 | { USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) }, | 708 | { USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) }, |
| 708 | { USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) }, | 709 | { USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) }, |
| 709 | { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) }, | 710 | { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) }, |
| @@ -804,13 +805,32 @@ static struct usb_device_id id_table_combined [] = { | |||
| 804 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, | 805 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, |
| 805 | { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID), | 806 | { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID), |
| 806 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, | 807 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, |
| 807 | { USB_DEVICE(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID) }, | 808 | { USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID, |
| 809 | USB_CLASS_VENDOR_SPEC, | ||
| 810 | USB_SUBCLASS_VENDOR_SPEC, 0x00) }, | ||
| 808 | { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, | 811 | { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, |
| 809 | { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID), | 812 | { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID), |
| 810 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, | 813 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, |
| 811 | { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, | 814 | { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, |
| 812 | { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, | 815 | { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, |
| 816 | { USB_DEVICE(FTDI_VID, PI_C865_PID) }, | ||
| 817 | { USB_DEVICE(FTDI_VID, PI_C857_PID) }, | ||
| 818 | { USB_DEVICE(PI_VID, PI_C866_PID) }, | ||
| 819 | { USB_DEVICE(PI_VID, PI_C663_PID) }, | ||
| 820 | { USB_DEVICE(PI_VID, PI_C725_PID) }, | ||
| 821 | { USB_DEVICE(PI_VID, PI_E517_PID) }, | ||
| 822 | { USB_DEVICE(PI_VID, PI_C863_PID) }, | ||
| 813 | { USB_DEVICE(PI_VID, PI_E861_PID) }, | 823 | { USB_DEVICE(PI_VID, PI_E861_PID) }, |
| 824 | { USB_DEVICE(PI_VID, PI_C867_PID) }, | ||
| 825 | { USB_DEVICE(PI_VID, PI_E609_PID) }, | ||
| 826 | { USB_DEVICE(PI_VID, PI_E709_PID) }, | ||
| 827 | { USB_DEVICE(PI_VID, PI_100F_PID) }, | ||
| 828 | { USB_DEVICE(PI_VID, PI_1011_PID) }, | ||
| 829 | { USB_DEVICE(PI_VID, PI_1012_PID) }, | ||
| 830 | { USB_DEVICE(PI_VID, PI_1013_PID) }, | ||
| 831 | { USB_DEVICE(PI_VID, PI_1014_PID) }, | ||
| 832 | { USB_DEVICE(PI_VID, PI_1015_PID) }, | ||
| 833 | { USB_DEVICE(PI_VID, PI_1016_PID) }, | ||
| 814 | { USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) }, | 834 | { USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) }, |
| 815 | { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, | 835 | { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, |
| 816 | { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID), | 836 | { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID), |
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 5dd96ca6c380..41fe5826100c 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h | |||
| @@ -75,6 +75,9 @@ | |||
| 75 | #define FTDI_OPENDCC_GATEWAY_PID 0xBFDB | 75 | #define FTDI_OPENDCC_GATEWAY_PID 0xBFDB |
| 76 | #define FTDI_OPENDCC_GBM_PID 0xBFDC | 76 | #define FTDI_OPENDCC_GBM_PID 0xBFDC |
| 77 | 77 | ||
| 78 | /* NZR SEM 16+ USB (http://www.nzr.de) */ | ||
| 79 | #define FTDI_NZR_SEM_USB_PID 0xC1E0 /* NZR SEM-LOG16+ */ | ||
| 80 | |||
| 78 | /* | 81 | /* |
| 79 | * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com) | 82 | * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com) |
| 80 | */ | 83 | */ |
| @@ -539,7 +542,10 @@ | |||
| 539 | /* | 542 | /* |
| 540 | * Microchip Technology, Inc. | 543 | * Microchip Technology, Inc. |
| 541 | * | 544 | * |
| 542 | * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are also used by: | 545 | * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are |
| 546 | * used by single function CDC ACM class based firmware demo | ||
| 547 | * applications. The VID/PID has also been used in firmware | ||
| 548 | * emulating FTDI serial chips by: | ||
| 543 | * Hornby Elite - Digital Command Control Console | 549 | * Hornby Elite - Digital Command Control Console |
| 544 | * http://www.hornby.com/hornby-dcc/controllers/ | 550 | * http://www.hornby.com/hornby-dcc/controllers/ |
| 545 | */ | 551 | */ |
| @@ -791,8 +797,27 @@ | |||
| 791 | * Physik Instrumente | 797 | * Physik Instrumente |
| 792 | * http://www.physikinstrumente.com/en/products/ | 798 | * http://www.physikinstrumente.com/en/products/ |
| 793 | */ | 799 | */ |
| 800 | /* These two devices use the VID of FTDI */ | ||
| 801 | #define PI_C865_PID 0xe0a0 /* PI C-865 Piezomotor Controller */ | ||
| 802 | #define PI_C857_PID 0xe0a1 /* PI Encoder Trigger Box */ | ||
| 803 | |||
| 794 | #define PI_VID 0x1a72 /* Vendor ID */ | 804 | #define PI_VID 0x1a72 /* Vendor ID */ |
| 795 | #define PI_E861_PID 0x1008 /* E-861 piezo controller USB connection */ | 805 | #define PI_C866_PID 0x1000 /* PI C-866 Piezomotor Controller */ |
| 806 | #define PI_C663_PID 0x1001 /* PI C-663 Mercury-Step */ | ||
| 807 | #define PI_C725_PID 0x1002 /* PI C-725 Piezomotor Controller */ | ||
| 808 | #define PI_E517_PID 0x1005 /* PI E-517 Digital Piezo Controller Operation Module */ | ||
| 809 | #define PI_C863_PID 0x1007 /* PI C-863 */ | ||
| 810 | #define PI_E861_PID 0x1008 /* PI E-861 Piezomotor Controller */ | ||
| 811 | #define PI_C867_PID 0x1009 /* PI C-867 Piezomotor Controller */ | ||
| 812 | #define PI_E609_PID 0x100D /* PI E-609 Digital Piezo Controller */ | ||
| 813 | #define PI_E709_PID 0x100E /* PI E-709 Digital Piezo Controller */ | ||
| 814 | #define PI_100F_PID 0x100F /* PI Digital Piezo Controller */ | ||
| 815 | #define PI_1011_PID 0x1011 /* PI Digital Piezo Controller */ | ||
| 816 | #define PI_1012_PID 0x1012 /* PI Motion Controller */ | ||
| 817 | #define PI_1013_PID 0x1013 /* PI Motion Controller */ | ||
| 818 | #define PI_1014_PID 0x1014 /* PI Device */ | ||
| 819 | #define PI_1015_PID 0x1015 /* PI Device */ | ||
| 820 | #define PI_1016_PID 0x1016 /* PI Digital Servo Module */ | ||
| 796 | 821 | ||
| 797 | /* | 822 | /* |
| 798 | * Kondo Kagaku Co.Ltd. | 823 | * Kondo Kagaku Co.Ltd. |
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index cc40f47ecea1..5ce88d1bc6f1 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c | |||
| @@ -886,8 +886,6 @@ static const struct usb_device_id option_ids[] = { | |||
| 886 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff), | 886 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff), |
| 887 | .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, | 887 | .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, |
| 888 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) }, | 888 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) }, |
| 889 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1018, 0xff, 0xff, 0xff), | ||
| 890 | .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, | ||
| 891 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) }, | 889 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) }, |
| 892 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) }, | 890 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) }, |
| 893 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) }, | 891 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) }, |
| @@ -1092,6 +1090,10 @@ static const struct usb_device_id option_ids[] = { | |||
| 1092 | .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist }, | 1090 | .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist }, |
| 1093 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff), | 1091 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff), |
| 1094 | .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist }, | 1092 | .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist }, |
| 1093 | { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) }, | ||
| 1094 | { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) }, | ||
| 1095 | { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) }, | ||
| 1096 | |||
| 1095 | { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, | 1097 | { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, |
| 1096 | { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, | 1098 | { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, |
| 1097 | { USB_DEVICE(ALINK_VENDOR_ID, DLINK_PRODUCT_DWM_652_U5) }, /* Yes, ALINK_VENDOR_ID */ | 1099 | { USB_DEVICE(ALINK_VENDOR_ID, DLINK_PRODUCT_DWM_652_U5) }, /* Yes, ALINK_VENDOR_ID */ |
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 211a4920b88a..d8dedc7d3910 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c | |||
| @@ -76,9 +76,24 @@ static int virqfd_wakeup(wait_queue_t *wait, unsigned mode, int sync, void *key) | |||
| 76 | schedule_work(&virqfd->inject); | 76 | schedule_work(&virqfd->inject); |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | if (flags & POLLHUP) | 79 | if (flags & POLLHUP) { |
| 80 | /* The eventfd is closing, detach from VFIO */ | 80 | unsigned long flags; |
| 81 | virqfd_deactivate(virqfd); | 81 | spin_lock_irqsave(&virqfd->vdev->irqlock, flags); |
| 82 | |||
| 83 | /* | ||
| 84 | * The eventfd is closing, if the virqfd has not yet been | ||
| 85 | * queued for release, as determined by testing whether the | ||
| 86 | * vdev pointer to it is still valid, queue it now. As | ||
| 87 | * with kvm irqfds, we know we won't race against the virqfd | ||
| 88 | * going away because we hold wqh->lock to get here. | ||
| 89 | */ | ||
| 90 | if (*(virqfd->pvirqfd) == virqfd) { | ||
| 91 | *(virqfd->pvirqfd) = NULL; | ||
| 92 | virqfd_deactivate(virqfd); | ||
| 93 | } | ||
| 94 | |||
| 95 | spin_unlock_irqrestore(&virqfd->vdev->irqlock, flags); | ||
| 96 | } | ||
| 82 | 97 | ||
| 83 | return 0; | 98 | return 0; |
| 84 | } | 99 | } |
| @@ -93,7 +108,6 @@ static void virqfd_ptable_queue_proc(struct file *file, | |||
| 93 | static void virqfd_shutdown(struct work_struct *work) | 108 | static void virqfd_shutdown(struct work_struct *work) |
| 94 | { | 109 | { |
| 95 | struct virqfd *virqfd = container_of(work, struct virqfd, shutdown); | 110 | struct virqfd *virqfd = container_of(work, struct virqfd, shutdown); |
| 96 | struct virqfd **pvirqfd = virqfd->pvirqfd; | ||
| 97 | u64 cnt; | 111 | u64 cnt; |
| 98 | 112 | ||
| 99 | eventfd_ctx_remove_wait_queue(virqfd->eventfd, &virqfd->wait, &cnt); | 113 | eventfd_ctx_remove_wait_queue(virqfd->eventfd, &virqfd->wait, &cnt); |
| @@ -101,7 +115,6 @@ static void virqfd_shutdown(struct work_struct *work) | |||
| 101 | eventfd_ctx_put(virqfd->eventfd); | 115 | eventfd_ctx_put(virqfd->eventfd); |
| 102 | 116 | ||
| 103 | kfree(virqfd); | 117 | kfree(virqfd); |
| 104 | *pvirqfd = NULL; | ||
| 105 | } | 118 | } |
| 106 | 119 | ||
| 107 | static void virqfd_inject(struct work_struct *work) | 120 | static void virqfd_inject(struct work_struct *work) |
| @@ -122,15 +135,11 @@ static int virqfd_enable(struct vfio_pci_device *vdev, | |||
| 122 | int ret = 0; | 135 | int ret = 0; |
| 123 | unsigned int events; | 136 | unsigned int events; |
| 124 | 137 | ||
| 125 | if (*pvirqfd) | ||
| 126 | return -EBUSY; | ||
| 127 | |||
| 128 | virqfd = kzalloc(sizeof(*virqfd), GFP_KERNEL); | 138 | virqfd = kzalloc(sizeof(*virqfd), GFP_KERNEL); |
| 129 | if (!virqfd) | 139 | if (!virqfd) |
| 130 | return -ENOMEM; | 140 | return -ENOMEM; |
| 131 | 141 | ||
| 132 | virqfd->pvirqfd = pvirqfd; | 142 | virqfd->pvirqfd = pvirqfd; |
| 133 | *pvirqfd = virqfd; | ||
| 134 | virqfd->vdev = vdev; | 143 | virqfd->vdev = vdev; |
| 135 | virqfd->handler = handler; | 144 | virqfd->handler = handler; |
| 136 | virqfd->thread = thread; | 145 | virqfd->thread = thread; |
| @@ -154,6 +163,23 @@ static int virqfd_enable(struct vfio_pci_device *vdev, | |||
| 154 | virqfd->eventfd = ctx; | 163 | virqfd->eventfd = ctx; |
| 155 | 164 | ||
| 156 | /* | 165 | /* |
| 166 | * virqfds can be released by closing the eventfd or directly | ||
| 167 | * through ioctl. These are both done through a workqueue, so | ||
| 168 | * we update the pointer to the virqfd under lock to avoid | ||
| 169 | * pushing multiple jobs to release the same virqfd. | ||
| 170 | */ | ||
| 171 | spin_lock_irq(&vdev->irqlock); | ||
| 172 | |||
| 173 | if (*pvirqfd) { | ||
| 174 | spin_unlock_irq(&vdev->irqlock); | ||
| 175 | ret = -EBUSY; | ||
| 176 | goto fail; | ||
| 177 | } | ||
| 178 | *pvirqfd = virqfd; | ||
| 179 | |||
| 180 | spin_unlock_irq(&vdev->irqlock); | ||
| 181 | |||
| 182 | /* | ||
| 157 | * Install our own custom wake-up handling so we are notified via | 183 | * Install our own custom wake-up handling so we are notified via |
| 158 | * a callback whenever someone signals the underlying eventfd. | 184 | * a callback whenever someone signals the underlying eventfd. |
| 159 | */ | 185 | */ |
| @@ -187,19 +213,29 @@ fail: | |||
| 187 | fput(file); | 213 | fput(file); |
| 188 | 214 | ||
| 189 | kfree(virqfd); | 215 | kfree(virqfd); |
| 190 | *pvirqfd = NULL; | ||
| 191 | 216 | ||
| 192 | return ret; | 217 | return ret; |
| 193 | } | 218 | } |
| 194 | 219 | ||
| 195 | static void virqfd_disable(struct virqfd *virqfd) | 220 | static void virqfd_disable(struct vfio_pci_device *vdev, |
| 221 | struct virqfd **pvirqfd) | ||
| 196 | { | 222 | { |
| 197 | if (!virqfd) | 223 | unsigned long flags; |
| 198 | return; | 224 | |
| 225 | spin_lock_irqsave(&vdev->irqlock, flags); | ||
| 226 | |||
| 227 | if (*pvirqfd) { | ||
| 228 | virqfd_deactivate(*pvirqfd); | ||
| 229 | *pvirqfd = NULL; | ||
| 230 | } | ||
| 199 | 231 | ||
| 200 | virqfd_deactivate(virqfd); | 232 | spin_unlock_irqrestore(&vdev->irqlock, flags); |
| 201 | 233 | ||
| 202 | /* Block until we know all outstanding shutdown jobs have completed. */ | 234 | /* |
| 235 | * Block until we know all outstanding shutdown jobs have completed. | ||
| 236 | * Even if we don't queue the job, flush the wq to be sure it's | ||
| 237 | * been released. | ||
| 238 | */ | ||
| 203 | flush_workqueue(vfio_irqfd_cleanup_wq); | 239 | flush_workqueue(vfio_irqfd_cleanup_wq); |
| 204 | } | 240 | } |
| 205 | 241 | ||
| @@ -392,8 +428,8 @@ static int vfio_intx_set_signal(struct vfio_pci_device *vdev, int fd) | |||
| 392 | static void vfio_intx_disable(struct vfio_pci_device *vdev) | 428 | static void vfio_intx_disable(struct vfio_pci_device *vdev) |
| 393 | { | 429 | { |
| 394 | vfio_intx_set_signal(vdev, -1); | 430 | vfio_intx_set_signal(vdev, -1); |
| 395 | virqfd_disable(vdev->ctx[0].unmask); | 431 | virqfd_disable(vdev, &vdev->ctx[0].unmask); |
| 396 | virqfd_disable(vdev->ctx[0].mask); | 432 | virqfd_disable(vdev, &vdev->ctx[0].mask); |
| 397 | vdev->irq_type = VFIO_PCI_NUM_IRQS; | 433 | vdev->irq_type = VFIO_PCI_NUM_IRQS; |
| 398 | vdev->num_ctx = 0; | 434 | vdev->num_ctx = 0; |
| 399 | kfree(vdev->ctx); | 435 | kfree(vdev->ctx); |
| @@ -539,8 +575,8 @@ static void vfio_msi_disable(struct vfio_pci_device *vdev, bool msix) | |||
| 539 | vfio_msi_set_block(vdev, 0, vdev->num_ctx, NULL, msix); | 575 | vfio_msi_set_block(vdev, 0, vdev->num_ctx, NULL, msix); |
| 540 | 576 | ||
| 541 | for (i = 0; i < vdev->num_ctx; i++) { | 577 | for (i = 0; i < vdev->num_ctx; i++) { |
| 542 | virqfd_disable(vdev->ctx[i].unmask); | 578 | virqfd_disable(vdev, &vdev->ctx[i].unmask); |
| 543 | virqfd_disable(vdev->ctx[i].mask); | 579 | virqfd_disable(vdev, &vdev->ctx[i].mask); |
| 544 | } | 580 | } |
| 545 | 581 | ||
| 546 | if (msix) { | 582 | if (msix) { |
| @@ -577,7 +613,7 @@ static int vfio_pci_set_intx_unmask(struct vfio_pci_device *vdev, | |||
| 577 | vfio_send_intx_eventfd, NULL, | 613 | vfio_send_intx_eventfd, NULL, |
| 578 | &vdev->ctx[0].unmask, fd); | 614 | &vdev->ctx[0].unmask, fd); |
| 579 | 615 | ||
| 580 | virqfd_disable(vdev->ctx[0].unmask); | 616 | virqfd_disable(vdev, &vdev->ctx[0].unmask); |
| 581 | } | 617 | } |
| 582 | 618 | ||
| 583 | return 0; | 619 | return 0; |
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index f75da8758adc..f49181c73113 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c | |||
| @@ -228,7 +228,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev) | |||
| 228 | data->port = pdata->flags; | 228 | data->port = pdata->flags; |
| 229 | if (data->port < 0) { | 229 | if (data->port < 0) { |
| 230 | dev_err(&pdev->dev, "wrong platform data is assigned"); | 230 | dev_err(&pdev->dev, "wrong platform data is assigned"); |
| 231 | kfree(data); | ||
| 232 | return -EINVAL; | 231 | return -EINVAL; |
| 233 | } | 232 | } |
| 234 | 233 | ||
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index b4a632ada401..932abaa58a89 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c | |||
| @@ -553,7 +553,9 @@ static int __init efifb_init(void) | |||
| 553 | int ret; | 553 | int ret; |
| 554 | char *option = NULL; | 554 | char *option = NULL; |
| 555 | 555 | ||
| 556 | dmi_check_system(dmi_system_table); | 556 | if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || |
| 557 | !(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS)) | ||
| 558 | dmi_check_system(dmi_system_table); | ||
| 557 | 559 | ||
| 558 | if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) | 560 | if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) |
| 559 | return -ENODEV; | 561 | return -ENODEV; |
diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c index 4bc2b8a5dd8b..663c308d0e73 100644 --- a/drivers/video/exynos/exynos_mipi_dsi.c +++ b/drivers/video/exynos/exynos_mipi_dsi.c | |||
| @@ -461,7 +461,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) | |||
| 461 | done: | 461 | done: |
| 462 | platform_set_drvdata(pdev, dsim); | 462 | platform_set_drvdata(pdev, dsim); |
| 463 | 463 | ||
| 464 | dev_dbg(&pdev->dev, "%s() completed sucessfuly (%s mode)\n", __func__, | 464 | dev_dbg(&pdev->dev, "%s() completed successfully (%s mode)\n", __func__, |
| 465 | dsim_config->e_interface == DSIM_COMMAND ? "CPU" : "RGB"); | 465 | dsim_config->e_interface == DSIM_COMMAND ? "CPU" : "RGB"); |
| 466 | 466 | ||
| 467 | return 0; | 467 | return 0; |
diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c index 8e4a446b5ed1..b244f060f151 100644 --- a/drivers/video/tmiofb.c +++ b/drivers/video/tmiofb.c | |||
| @@ -694,6 +694,10 @@ static int __devinit tmiofb_probe(struct platform_device *dev) | |||
| 694 | dev_err(&dev->dev, "NULL platform data!\n"); | 694 | dev_err(&dev->dev, "NULL platform data!\n"); |
| 695 | return -EINVAL; | 695 | return -EINVAL; |
| 696 | } | 696 | } |
| 697 | if (ccr == NULL || lcr == NULL || vram == NULL || irq < 0) { | ||
| 698 | dev_err(&dev->dev, "missing resources\n"); | ||
| 699 | return -EINVAL; | ||
| 700 | } | ||
| 697 | 701 | ||
| 698 | info = framebuffer_alloc(sizeof(struct tmiofb_par), &dev->dev); | 702 | info = framebuffer_alloc(sizeof(struct tmiofb_par), &dev->dev); |
| 699 | 703 | ||
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c index 530a2d309063..7c294f4dc0ed 100644 --- a/drivers/w1/masters/ds1wm.c +++ b/drivers/w1/masters/ds1wm.c | |||
| @@ -349,7 +349,7 @@ static void ds1wm_search(void *data, struct w1_master *master_dev, | |||
| 349 | "pass: %d entering ASM\n", pass); | 349 | "pass: %d entering ASM\n", pass); |
| 350 | ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_SRA); | 350 | ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_SRA); |
| 351 | dev_dbg(&ds1wm_data->pdev->dev, | 351 | dev_dbg(&ds1wm_data->pdev->dev, |
| 352 | "pass: %d begining nibble loop\n", pass); | 352 | "pass: %d beginning nibble loop\n", pass); |
| 353 | 353 | ||
| 354 | r_prime = 0; | 354 | r_prime = 0; |
| 355 | d = 0; | 355 | d = 0; |
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 1eff743ec497..ae60406ea8a1 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c | |||
| @@ -814,6 +814,9 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, | |||
| 814 | hpwdt_timer_reg = pci_mem_addr + 0x70; | 814 | hpwdt_timer_reg = pci_mem_addr + 0x70; |
| 815 | hpwdt_timer_con = pci_mem_addr + 0x72; | 815 | hpwdt_timer_con = pci_mem_addr + 0x72; |
| 816 | 816 | ||
| 817 | /* Make sure that timer is disabled until /dev/watchdog is opened */ | ||
| 818 | hpwdt_stop(); | ||
| 819 | |||
| 817 | /* Make sure that we have a valid soft_margin */ | 820 | /* Make sure that we have a valid soft_margin */ |
| 818 | if (hpwdt_change_timer(soft_margin)) | 821 | if (hpwdt_change_timer(soft_margin)) |
| 819 | hpwdt_change_timer(DEFAULT_MARGIN); | 822 | hpwdt_change_timer(DEFAULT_MARGIN); |
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c index 6aa46a90ff02..3796434991fa 100644 --- a/drivers/watchdog/watchdog_core.c +++ b/drivers/watchdog/watchdog_core.c | |||
| @@ -128,11 +128,12 @@ EXPORT_SYMBOL_GPL(watchdog_register_device); | |||
| 128 | void watchdog_unregister_device(struct watchdog_device *wdd) | 128 | void watchdog_unregister_device(struct watchdog_device *wdd) |
| 129 | { | 129 | { |
| 130 | int ret; | 130 | int ret; |
| 131 | int devno = wdd->cdev.dev; | 131 | int devno; |
| 132 | 132 | ||
| 133 | if (wdd == NULL) | 133 | if (wdd == NULL) |
| 134 | return; | 134 | return; |
| 135 | 135 | ||
| 136 | devno = wdd->cdev.dev; | ||
| 136 | ret = watchdog_dev_unregister(wdd); | 137 | ret = watchdog_dev_unregister(wdd); |
| 137 | if (ret) | 138 | if (ret) |
| 138 | pr_err("error unregistering /dev/watchdog (err=%d)\n", ret); | 139 | pr_err("error unregistering /dev/watchdog (err=%d)\n", ret); |
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 1ffd03bf8e10..7f1241608489 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c | |||
| @@ -314,8 +314,9 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) | |||
| 314 | } | 314 | } |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages + offset, | 317 | err = gnttab_unmap_refs(map->unmap_ops + offset, |
| 318 | pages, true); | 318 | use_ptemod ? map->kmap_ops + offset : NULL, map->pages + offset, |
| 319 | pages); | ||
| 319 | if (err) | 320 | if (err) |
| 320 | return err; | 321 | return err; |
| 321 | 322 | ||
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 0bfc1ef11259..006726688baf 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c | |||
| @@ -870,7 +870,8 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, | |||
| 870 | EXPORT_SYMBOL_GPL(gnttab_map_refs); | 870 | EXPORT_SYMBOL_GPL(gnttab_map_refs); |
| 871 | 871 | ||
| 872 | int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, | 872 | int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, |
| 873 | struct page **pages, unsigned int count, bool clear_pte) | 873 | struct gnttab_map_grant_ref *kmap_ops, |
| 874 | struct page **pages, unsigned int count) | ||
| 874 | { | 875 | { |
| 875 | int i, ret; | 876 | int i, ret; |
| 876 | bool lazy = false; | 877 | bool lazy = false; |
| @@ -888,7 +889,8 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, | |||
| 888 | } | 889 | } |
| 889 | 890 | ||
| 890 | for (i = 0; i < count; i++) { | 891 | for (i = 0; i < count; i++) { |
| 891 | ret = m2p_remove_override(pages[i], clear_pte); | 892 | ret = m2p_remove_override(pages[i], kmap_ops ? |
| 893 | &kmap_ops[i] : NULL); | ||
| 892 | if (ret) | 894 | if (ret) |
| 893 | return ret; | 895 | return ret; |
| 894 | } | 896 | } |
