aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pnp/pnpacpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-01-10 15:23:16 -0500
committerLen Brown <len.brown@intel.com>2011-01-11 15:20:40 -0500
commitcc8e7a355c1ec64b06a5b8126c47c5cb47f44fce (patch)
treec2188b1abcab9ac29d47b75f78e48b4007184ff4 /drivers/pnp/pnpacpi
parent3c0eee3fe6a3a1c745379547c7e7c904aa64f6d5 (diff)
PNP / ACPI: Use DEVICE_ACPI_HANDLE() for device ACPI handle access
The PNP ACPI driver squirrels the ACPI handles of PNP devices' ACPI companions, but this isn't correct, because those handles should be accessed using the DEVICE_ACPI_HANDLE() macro operating on struct device objects. Using DEVICE_ACPI_HANDLE() in the PNP ACPI driver instead of the driver's own copies of the ACPI handles allows us to avoid a problem with docking stations where a machine docked before suspend to RAM and undocked while suspended crashes during the subsequent resume (in that case the ACPI companion of the PNP device in question doesn't exist any more while the device is being resumed). It also allows us to avoid the problem where suspend to RAM fails when the machine was undocked while suspended before (again, the ACPI companion of the PNP device is not present any more while it is being suspended). This change doesn't fix all of the the PNP ACPI driver's problems with PNP devices in docking stations (generally speaking, the driver has no idea that devices can come and go and doesn't even attempt to handle such events), but at least it makes suspend work for the users of docking stations who don't use the PNP devices located in there. References: https://bugzilla.kernel.org/show_bug.cgi?id=15100 Reported-and-tested-by: Toralf Förster <toralf.foerster@gmx.de> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Bjorn Helgaas <bjorn.helgaas@hp.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/pnp/pnpacpi')
-rw-r--r--drivers/pnp/pnpacpi/core.c93
1 files changed, 67 insertions, 26 deletions
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 57313f4658bc..ca84d5099ce7 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -81,12 +81,19 @@ static int pnpacpi_get_resources(struct pnp_dev *dev)
81 81
82static int pnpacpi_set_resources(struct pnp_dev *dev) 82static int pnpacpi_set_resources(struct pnp_dev *dev)
83{ 83{
84 struct acpi_device *acpi_dev = dev->data; 84 struct acpi_device *acpi_dev;
85 acpi_handle handle = acpi_dev->handle; 85 acpi_handle handle;
86 struct acpi_buffer buffer; 86 struct acpi_buffer buffer;
87 int ret; 87 int ret;
88 88
89 pnp_dbg(&dev->dev, "set resources\n"); 89 pnp_dbg(&dev->dev, "set resources\n");
90
91 handle = DEVICE_ACPI_HANDLE(&dev->dev);
92 if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
93 dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
94 return -ENODEV;
95 }
96
90 ret = pnpacpi_build_resource_template(dev, &buffer); 97 ret = pnpacpi_build_resource_template(dev, &buffer);
91 if (ret) 98 if (ret)
92 return ret; 99 return ret;
@@ -105,12 +112,18 @@ static int pnpacpi_set_resources(struct pnp_dev *dev)
105 112
106static int pnpacpi_disable_resources(struct pnp_dev *dev) 113static int pnpacpi_disable_resources(struct pnp_dev *dev)
107{ 114{
108 struct acpi_device *acpi_dev = dev->data; 115 struct acpi_device *acpi_dev;
109 acpi_handle handle = acpi_dev->handle; 116 acpi_handle handle;
110 int ret; 117 int ret;
111 118
112 dev_dbg(&dev->dev, "disable resources\n"); 119 dev_dbg(&dev->dev, "disable resources\n");
113 120
121 handle = DEVICE_ACPI_HANDLE(&dev->dev);
122 if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
123 dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
124 return 0;
125 }
126
114 /* acpi_unregister_gsi(pnp_irq(dev, 0)); */ 127 /* acpi_unregister_gsi(pnp_irq(dev, 0)); */
115 ret = 0; 128 ret = 0;
116 if (acpi_bus_power_manageable(handle)) 129 if (acpi_bus_power_manageable(handle))
@@ -124,46 +137,74 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
124#ifdef CONFIG_ACPI_SLEEP 137#ifdef CONFIG_ACPI_SLEEP
125static bool pnpacpi_can_wakeup(struct pnp_dev *dev) 138static bool pnpacpi_can_wakeup(struct pnp_dev *dev)
126{ 139{
127 struct acpi_device *acpi_dev = dev->data; 140 struct acpi_device *acpi_dev;
128 acpi_handle handle = acpi_dev->handle; 141 acpi_handle handle;
142
143 handle = DEVICE_ACPI_HANDLE(&dev->dev);
144 if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
145 dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
146 return false;
147 }
129 148
130 return acpi_bus_can_wakeup(handle); 149 return acpi_bus_can_wakeup(handle);
131} 150}
132 151
133static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state) 152static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
134{ 153{
135 struct acpi_device *acpi_dev = dev->data; 154 struct acpi_device *acpi_dev;
136 acpi_handle handle = acpi_dev->handle; 155 acpi_handle handle;
137 int power_state; 156 int error = 0;
157
158 handle = DEVICE_ACPI_HANDLE(&dev->dev);
159 if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
160 dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
161 return 0;
162 }
138 163
139 if (device_can_wakeup(&dev->dev)) { 164 if (device_can_wakeup(&dev->dev)) {
140 int rc = acpi_pm_device_sleep_wake(&dev->dev, 165 error = acpi_pm_device_sleep_wake(&dev->dev,
141 device_may_wakeup(&dev->dev)); 166 device_may_wakeup(&dev->dev));
167 if (error)
168 return error;
169 }
170
171 if (acpi_bus_power_manageable(handle)) {
172 int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL);
173
174 if (power_state < 0)
175 power_state = (state.event == PM_EVENT_ON) ?
176 ACPI_STATE_D0 : ACPI_STATE_D3;
142 177
143 if (rc) 178 /*
144 return rc; 179 * acpi_bus_set_power() often fails (keyboard port can't be
180 * powered-down?), and in any case, our return value is ignored
181 * by pnp_bus_suspend(). Hence we don't revert the wakeup
182 * setting if the set_power fails.
183 */
184 error = acpi_bus_set_power(handle, power_state);
145 } 185 }
146 power_state = acpi_pm_device_sleep_state(&dev->dev, NULL); 186
147 if (power_state < 0) 187 return error;
148 power_state = (state.event == PM_EVENT_ON) ?
149 ACPI_STATE_D0 : ACPI_STATE_D3;
150
151 /* acpi_bus_set_power() often fails (keyboard port can't be
152 * powered-down?), and in any case, our return value is ignored
153 * by pnp_bus_suspend(). Hence we don't revert the wakeup
154 * setting if the set_power fails.
155 */
156 return acpi_bus_set_power(handle, power_state);
157} 188}
158 189
159static int pnpacpi_resume(struct pnp_dev *dev) 190static int pnpacpi_resume(struct pnp_dev *dev)
160{ 191{
161 struct acpi_device *acpi_dev = dev->data; 192 struct acpi_device *acpi_dev;
162 acpi_handle handle = acpi_dev->handle; 193 acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
194 int error = 0;
195
196 if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
197 dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
198 return -ENODEV;
199 }
163 200
164 if (device_may_wakeup(&dev->dev)) 201 if (device_may_wakeup(&dev->dev))
165 acpi_pm_device_sleep_wake(&dev->dev, false); 202 acpi_pm_device_sleep_wake(&dev->dev, false);
166 return acpi_bus_set_power(handle, ACPI_STATE_D0); 203
204 if (acpi_bus_power_manageable(handle))
205 error = acpi_bus_set_power(handle, ACPI_STATE_D0);
206
207 return error;
167} 208}
168#endif 209#endif
169 210