aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2008-10-17 11:51:12 -0400
committerJean Delvare <khali@mahadeva.delvare>2008-10-17 11:51:12 -0400
commitee4cd32ee8a68e22081f698602e4315fb4272853 (patch)
treee44f309816eeb26727a23180ecede53f372705cd
parent0a02002268bf624a8b0eaf3b4eb5c4207bd80d8b (diff)
hwmon: (ams) Fix locking issues
Use a separate mutex to serialize input device creation/removal, otheriwse we deadlock if we try to remove input device while it is being polled. Also do not take ams_info.lock when it is not needed. Signed-off-by: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r--drivers/hwmon/ams/ams-core.c40
-rw-r--r--drivers/hwmon/ams/ams-i2c.c4
-rw-r--r--drivers/hwmon/ams/ams-input.c59
-rw-r--r--drivers/hwmon/ams/ams-pmu.c18
4 files changed, 56 insertions, 65 deletions
diff --git a/drivers/hwmon/ams/ams-core.c b/drivers/hwmon/ams/ams-core.c
index fbefa82a015c..9b4a0e7a564f 100644
--- a/drivers/hwmon/ams/ams-core.c
+++ b/drivers/hwmon/ams/ams-core.c
@@ -223,34 +223,28 @@ int __init ams_init(void)
223 223
224void ams_exit(void) 224void ams_exit(void)
225{ 225{
226 mutex_lock(&ams_info.lock); 226 /* Remove input device */
227 227 ams_input_exit();
228 if (ams_info.has_device) {
229 /* Remove input device */
230 ams_input_exit();
231 228
232 /* Shut down implementation */ 229 /* Remove attributes */
233 ams_info.exit(); 230 device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
234
235 /* Flush interrupt worker
236 *
237 * We do this after ams_info.exit(), because an interrupt might
238 * have arrived before disabling them.
239 */
240 flush_scheduled_work();
241 231
242 /* Remove attributes */ 232 /* Shut down implementation */
243 device_remove_file(&ams_info.of_dev->dev, &dev_attr_current); 233 ams_info.exit();
244 234
245 /* Remove device */ 235 /* Flush interrupt worker
246 of_device_unregister(ams_info.of_dev); 236 *
237 * We do this after ams_info.exit(), because an interrupt might
238 * have arrived before disabling them.
239 */
240 flush_scheduled_work();
247 241
248 /* Remove handler */ 242 /* Remove device */
249 pmf_unregister_irq_client(&ams_shock_client); 243 of_device_unregister(ams_info.of_dev);
250 pmf_unregister_irq_client(&ams_freefall_client);
251 }
252 244
253 mutex_unlock(&ams_info.lock); 245 /* Remove handler */
246 pmf_unregister_irq_client(&ams_shock_client);
247 pmf_unregister_irq_client(&ams_freefall_client);
254} 248}
255 249
256MODULE_AUTHOR("Stelian Pop, Michael Hanselmann"); 250MODULE_AUTHOR("Stelian Pop, Michael Hanselmann");
diff --git a/drivers/hwmon/ams/ams-i2c.c b/drivers/hwmon/ams/ams-i2c.c
index da26de01068e..2cbf8a6506c7 100644
--- a/drivers/hwmon/ams/ams-i2c.c
+++ b/drivers/hwmon/ams/ams-i2c.c
@@ -261,8 +261,6 @@ int __init ams_i2c_init(struct device_node *np)
261{ 261{
262 int result; 262 int result;
263 263
264 mutex_lock(&ams_info.lock);
265
266 /* Set implementation stuff */ 264 /* Set implementation stuff */
267 ams_info.of_node = np; 265 ams_info.of_node = np;
268 ams_info.exit = ams_i2c_exit; 266 ams_info.exit = ams_i2c_exit;
@@ -273,7 +271,5 @@ int __init ams_i2c_init(struct device_node *np)
273 271
274 result = i2c_add_driver(&ams_i2c_driver); 272 result = i2c_add_driver(&ams_i2c_driver);
275 273
276 mutex_unlock(&ams_info.lock);
277
278 return result; 274 return result;
279} 275}
diff --git a/drivers/hwmon/ams/ams-input.c b/drivers/hwmon/ams/ams-input.c
index 48dbf7d6a66d..8a712392cd38 100644
--- a/drivers/hwmon/ams/ams-input.c
+++ b/drivers/hwmon/ams/ams-input.c
@@ -27,6 +27,8 @@ static unsigned int invert;
27module_param(invert, bool, S_IWUSR | S_IRUGO); 27module_param(invert, bool, S_IWUSR | S_IRUGO);
28MODULE_PARM_DESC(invert, "Invert input data on X and Y axis"); 28MODULE_PARM_DESC(invert, "Invert input data on X and Y axis");
29 29
30static DEFINE_MUTEX(ams_input_mutex);
31
30static void ams_idev_poll(struct input_polled_dev *dev) 32static void ams_idev_poll(struct input_polled_dev *dev)
31{ 33{
32 struct input_dev *idev = dev->input; 34 struct input_dev *idev = dev->input;
@@ -50,13 +52,11 @@ static void ams_idev_poll(struct input_polled_dev *dev)
50} 52}
51 53
52/* Call with ams_info.lock held! */ 54/* Call with ams_info.lock held! */
53static void ams_input_enable(void) 55static int ams_input_enable(void)
54{ 56{
55 struct input_dev *input; 57 struct input_dev *input;
56 s8 x, y, z; 58 s8 x, y, z;
57 59 int error;
58 if (ams_info.idev)
59 return;
60 60
61 ams_sensors(&x, &y, &z); 61 ams_sensors(&x, &y, &z);
62 ams_info.xcalib = x; 62 ams_info.xcalib = x;
@@ -65,7 +65,7 @@ static void ams_input_enable(void)
65 65
66 ams_info.idev = input_allocate_polled_device(); 66 ams_info.idev = input_allocate_polled_device();
67 if (!ams_info.idev) 67 if (!ams_info.idev)
68 return; 68 return -ENOMEM;
69 69
70 ams_info.idev->poll = ams_idev_poll; 70 ams_info.idev->poll = ams_idev_poll;
71 ams_info.idev->poll_interval = 25; 71 ams_info.idev->poll_interval = 25;
@@ -84,14 +84,18 @@ static void ams_input_enable(void)
84 set_bit(EV_KEY, input->evbit); 84 set_bit(EV_KEY, input->evbit);
85 set_bit(BTN_TOUCH, input->keybit); 85 set_bit(BTN_TOUCH, input->keybit);
86 86
87 if (input_register_polled_device(ams_info.idev)) { 87 error = input_register_polled_device(ams_info.idev);
88 if (error) {
88 input_free_polled_device(ams_info.idev); 89 input_free_polled_device(ams_info.idev);
89 ams_info.idev = NULL; 90 ams_info.idev = NULL;
90 return; 91 return error;
91 } 92 }
93
94 joystick = 1;
95
96 return 0;
92} 97}
93 98
94/* Call with ams_info.lock held! */
95static void ams_input_disable(void) 99static void ams_input_disable(void)
96{ 100{
97 if (ams_info.idev) { 101 if (ams_info.idev) {
@@ -99,6 +103,8 @@ static void ams_input_disable(void)
99 input_free_polled_device(ams_info.idev); 103 input_free_polled_device(ams_info.idev);
100 ams_info.idev = NULL; 104 ams_info.idev = NULL;
101 } 105 }
106
107 joystick = 0;
102} 108}
103 109
104static ssize_t ams_input_show_joystick(struct device *dev, 110static ssize_t ams_input_show_joystick(struct device *dev,
@@ -110,39 +116,42 @@ static ssize_t ams_input_show_joystick(struct device *dev,
110static ssize_t ams_input_store_joystick(struct device *dev, 116static ssize_t ams_input_store_joystick(struct device *dev,
111 struct device_attribute *attr, const char *buf, size_t count) 117 struct device_attribute *attr, const char *buf, size_t count)
112{ 118{
113 if (sscanf(buf, "%d\n", &joystick) != 1) 119 unsigned long enable;
120 int error = 0;
121
122 if (strict_strtoul(buf, 0, &enable) || enable > 1)
114 return -EINVAL; 123 return -EINVAL;
115 124
116 mutex_lock(&ams_info.lock); 125 mutex_lock(&ams_input_mutex);
117 126
118 if (joystick) 127 if (enable != joystick) {
119 ams_input_enable(); 128 if (enable)
120 else 129 error = ams_input_enable();
121 ams_input_disable(); 130 else
131 ams_input_disable();
132 }
122 133
123 mutex_unlock(&ams_info.lock); 134 mutex_unlock(&ams_input_mutex);
124 135
125 return count; 136 return error ? error : count;
126} 137}
127 138
128static DEVICE_ATTR(joystick, S_IRUGO | S_IWUSR, 139static DEVICE_ATTR(joystick, S_IRUGO | S_IWUSR,
129 ams_input_show_joystick, ams_input_store_joystick); 140 ams_input_show_joystick, ams_input_store_joystick);
130 141
131/* Call with ams_info.lock held! */
132int ams_input_init(void) 142int ams_input_init(void)
133{ 143{
134 int result; 144 if (joystick)
135
136 result = device_create_file(&ams_info.of_dev->dev, &dev_attr_joystick);
137
138 if (!result && joystick)
139 ams_input_enable(); 145 ams_input_enable();
140 return result; 146
147 return device_create_file(&ams_info.of_dev->dev, &dev_attr_joystick);
141} 148}
142 149
143/* Call with ams_info.lock held! */
144void ams_input_exit(void) 150void ams_input_exit(void)
145{ 151{
146 ams_input_disable();
147 device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick); 152 device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick);
153
154 mutex_lock(&ams_input_mutex);
155 ams_input_disable();
156 mutex_unlock(&ams_input_mutex);
148} 157}
diff --git a/drivers/hwmon/ams/ams-pmu.c b/drivers/hwmon/ams/ams-pmu.c
index 9463e9768f6f..fb18b3d3162b 100644
--- a/drivers/hwmon/ams/ams-pmu.c
+++ b/drivers/hwmon/ams/ams-pmu.c
@@ -149,8 +149,6 @@ int __init ams_pmu_init(struct device_node *np)
149 const u32 *prop; 149 const u32 *prop;
150 int result; 150 int result;
151 151
152 mutex_lock(&ams_info.lock);
153
154 /* Set implementation stuff */ 152 /* Set implementation stuff */
155 ams_info.of_node = np; 153 ams_info.of_node = np;
156 ams_info.exit = ams_pmu_exit; 154 ams_info.exit = ams_pmu_exit;
@@ -161,10 +159,9 @@ int __init ams_pmu_init(struct device_node *np)
161 159
162 /* Get PMU command, should be 0x4e, but we can never know */ 160 /* Get PMU command, should be 0x4e, but we can never know */
163 prop = of_get_property(ams_info.of_node, "reg", NULL); 161 prop = of_get_property(ams_info.of_node, "reg", NULL);
164 if (!prop) { 162 if (!prop)
165 result = -ENODEV; 163 return -ENODEV;
166 goto exit; 164
167 }
168 ams_pmu_cmd = ((*prop) >> 8) & 0xff; 165 ams_pmu_cmd = ((*prop) >> 8) & 0xff;
169 166
170 /* Disable interrupts */ 167 /* Disable interrupts */
@@ -175,7 +172,7 @@ int __init ams_pmu_init(struct device_node *np)
175 172
176 result = ams_sensor_attach(); 173 result = ams_sensor_attach();
177 if (result < 0) 174 if (result < 0)
178 goto exit; 175 return result;
179 176
180 /* Set default values */ 177 /* Set default values */
181 ams_pmu_set_register(AMS_FF_LOW_LIMIT, 0x15); 178 ams_pmu_set_register(AMS_FF_LOW_LIMIT, 0x15);
@@ -198,10 +195,5 @@ int __init ams_pmu_init(struct device_node *np)
198 195
199 printk(KERN_INFO "ams: Found PMU based motion sensor\n"); 196 printk(KERN_INFO "ams: Found PMU based motion sensor\n");
200 197
201 result = 0; 198 return 0;
202
203exit:
204 mutex_unlock(&ams_info.lock);
205
206 return result;
207} 199}