diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-27 19:18:30 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-27 19:18:30 -0500 |
commit | 8d37a371b6869920e6c40c495c68eabba1ef3909 (patch) | |
tree | dad784512b13832f4f5494cfe0791965c6a2b0f6 /drivers/pcmcia/socket_sysfs.c | |
parent | ef1a8de8ea004a689b2aa9f5cefcba2b1a0262f2 (diff) | |
parent | 7b4884ca8853a638df0eb5d251d80d67777b8b1a (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6: (49 commits)
pcmcia: validate late-added resources
pcmcia: allow for extension of resource interval
pcmcia: remove useless msleep in ds.c
pcmcia: use read_cis_mem return value
pcmcia: handle error in serial_cs config calls
pcmcia: add locking to pcmcia_{read,write}_cis_mem
pcmcia: avoid prod_id memleak
pcmcia: avoid sysfs-related lockup for cardbus
pcmcia: use state machine for extended requery
pcmcia: delay re-scanning and re-querying of PCMCIA bus
pcmcia: use pccardd to handle eject, insert, suspend and resume requests
pcmcia: use ops_mutex for rsrc_{mgr,nonstatic} locking
pcmcia: use mutex for dynid lock
pcmcia: assert locking to struct pcmcia_device
pcmcia: add locking documentation
pcmcia: simplify locking
pcmcia: add locking to struct pcmcia_socket->pcmcia_state()
pcmcia: protect s->device_count
pcmcia: properly lock skt->irq, skt->irq_mask
pcmcia: lock ops->set_socket
...
Diffstat (limited to 'drivers/pcmcia/socket_sysfs.c')
-rw-r--r-- | drivers/pcmcia/socket_sysfs.c | 196 |
1 files changed, 21 insertions, 175 deletions
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index 7a456000332a..08278016e58d 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c | |||
@@ -88,15 +88,14 @@ static DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL); | |||
88 | static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr, | 88 | static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr, |
89 | const char *buf, size_t count) | 89 | const char *buf, size_t count) |
90 | { | 90 | { |
91 | ssize_t ret; | ||
92 | struct pcmcia_socket *s = to_socket(dev); | 91 | struct pcmcia_socket *s = to_socket(dev); |
93 | 92 | ||
94 | if (!count) | 93 | if (!count) |
95 | return -EINVAL; | 94 | return -EINVAL; |
96 | 95 | ||
97 | ret = pcmcia_insert_card(s); | 96 | pcmcia_parse_uevents(s, PCMCIA_UEVENT_INSERT); |
98 | 97 | ||
99 | return ret ? ret : count; | 98 | return count; |
100 | } | 99 | } |
101 | static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert); | 100 | static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert); |
102 | 101 | ||
@@ -113,18 +112,22 @@ static ssize_t pccard_store_card_pm_state(struct device *dev, | |||
113 | struct device_attribute *attr, | 112 | struct device_attribute *attr, |
114 | const char *buf, size_t count) | 113 | const char *buf, size_t count) |
115 | { | 114 | { |
116 | ssize_t ret = -EINVAL; | ||
117 | struct pcmcia_socket *s = to_socket(dev); | 115 | struct pcmcia_socket *s = to_socket(dev); |
116 | ssize_t ret = count; | ||
118 | 117 | ||
119 | if (!count) | 118 | if (!count) |
120 | return -EINVAL; | 119 | return -EINVAL; |
121 | 120 | ||
122 | if (!(s->state & SOCKET_SUSPEND) && !strncmp(buf, "off", 3)) | 121 | if (!strncmp(buf, "off", 3)) |
123 | ret = pcmcia_suspend_card(s); | 122 | pcmcia_parse_uevents(s, PCMCIA_UEVENT_SUSPEND); |
124 | else if ((s->state & SOCKET_SUSPEND) && !strncmp(buf, "on", 2)) | 123 | else { |
125 | ret = pcmcia_resume_card(s); | 124 | if (!strncmp(buf, "on", 2)) |
125 | pcmcia_parse_uevents(s, PCMCIA_UEVENT_RESUME); | ||
126 | else | ||
127 | ret = -EINVAL; | ||
128 | } | ||
126 | 129 | ||
127 | return ret ? -ENODEV : count; | 130 | return ret; |
128 | } | 131 | } |
129 | static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state); | 132 | static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state); |
130 | 133 | ||
@@ -132,15 +135,14 @@ static ssize_t pccard_store_eject(struct device *dev, | |||
132 | struct device_attribute *attr, | 135 | struct device_attribute *attr, |
133 | const char *buf, size_t count) | 136 | const char *buf, size_t count) |
134 | { | 137 | { |
135 | ssize_t ret; | ||
136 | struct pcmcia_socket *s = to_socket(dev); | 138 | struct pcmcia_socket *s = to_socket(dev); |
137 | 139 | ||
138 | if (!count) | 140 | if (!count) |
139 | return -EINVAL; | 141 | return -EINVAL; |
140 | 142 | ||
141 | ret = pcmcia_eject_card(s); | 143 | pcmcia_parse_uevents(s, PCMCIA_UEVENT_EJECT); |
142 | 144 | ||
143 | return ret ? ret : count; | 145 | return count; |
144 | } | 146 | } |
145 | static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); | 147 | static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); |
146 | 148 | ||
@@ -167,7 +169,9 @@ static ssize_t pccard_store_irq_mask(struct device *dev, | |||
167 | ret = sscanf(buf, "0x%x\n", &mask); | 169 | ret = sscanf(buf, "0x%x\n", &mask); |
168 | 170 | ||
169 | if (ret == 1) { | 171 | if (ret == 1) { |
172 | mutex_lock(&s->ops_mutex); | ||
170 | s->irq_mask &= mask; | 173 | s->irq_mask &= mask; |
174 | mutex_unlock(&s->ops_mutex); | ||
171 | ret = 0; | 175 | ret = 0; |
172 | } | 176 | } |
173 | 177 | ||
@@ -187,163 +191,21 @@ static ssize_t pccard_store_resource(struct device *dev, | |||
187 | struct device_attribute *attr, | 191 | struct device_attribute *attr, |
188 | const char *buf, size_t count) | 192 | const char *buf, size_t count) |
189 | { | 193 | { |
190 | unsigned long flags; | ||
191 | struct pcmcia_socket *s = to_socket(dev); | 194 | struct pcmcia_socket *s = to_socket(dev); |
192 | 195 | ||
193 | if (!count) | 196 | if (!count) |
194 | return -EINVAL; | 197 | return -EINVAL; |
195 | 198 | ||
196 | spin_lock_irqsave(&s->lock, flags); | 199 | mutex_lock(&s->ops_mutex); |
197 | if (!s->resource_setup_done) | 200 | if (!s->resource_setup_done) |
198 | s->resource_setup_done = 1; | 201 | s->resource_setup_done = 1; |
199 | spin_unlock_irqrestore(&s->lock, flags); | 202 | mutex_unlock(&s->ops_mutex); |
200 | |||
201 | mutex_lock(&s->skt_mutex); | ||
202 | if ((s->callback) && | ||
203 | (s->state & SOCKET_PRESENT) && | ||
204 | !(s->state & SOCKET_CARDBUS)) { | ||
205 | if (try_module_get(s->callback->owner)) { | ||
206 | s->callback->requery(s, 0); | ||
207 | module_put(s->callback->owner); | ||
208 | } | ||
209 | } | ||
210 | mutex_unlock(&s->skt_mutex); | ||
211 | |||
212 | return count; | ||
213 | } | ||
214 | static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); | ||
215 | 203 | ||
216 | 204 | pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY); | |
217 | static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count) | ||
218 | { | ||
219 | tuple_t tuple; | ||
220 | int status, i; | ||
221 | loff_t pointer = 0; | ||
222 | ssize_t ret = 0; | ||
223 | u_char *tuplebuffer; | ||
224 | u_char *tempbuffer; | ||
225 | |||
226 | tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL); | ||
227 | if (!tuplebuffer) | ||
228 | return -ENOMEM; | ||
229 | |||
230 | tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL); | ||
231 | if (!tempbuffer) { | ||
232 | ret = -ENOMEM; | ||
233 | goto free_tuple; | ||
234 | } | ||
235 | |||
236 | memset(&tuple, 0, sizeof(tuple_t)); | ||
237 | |||
238 | tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON; | ||
239 | tuple.DesiredTuple = RETURN_FIRST_TUPLE; | ||
240 | tuple.TupleOffset = 0; | ||
241 | |||
242 | status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple); | ||
243 | while (!status) { | ||
244 | tuple.TupleData = tuplebuffer; | ||
245 | tuple.TupleDataMax = 255; | ||
246 | memset(tuplebuffer, 0, sizeof(u_char) * 255); | ||
247 | |||
248 | status = pccard_get_tuple_data(s, &tuple); | ||
249 | if (status) | ||
250 | break; | ||
251 | |||
252 | if (off < (pointer + 2 + tuple.TupleDataLen)) { | ||
253 | tempbuffer[0] = tuple.TupleCode & 0xff; | ||
254 | tempbuffer[1] = tuple.TupleLink & 0xff; | ||
255 | for (i = 0; i < tuple.TupleDataLen; i++) | ||
256 | tempbuffer[i + 2] = tuplebuffer[i] & 0xff; | ||
257 | |||
258 | for (i = 0; i < (2 + tuple.TupleDataLen); i++) { | ||
259 | if (((i + pointer) >= off) && | ||
260 | (i + pointer) < (off + count)) { | ||
261 | buf[ret] = tempbuffer[i]; | ||
262 | ret++; | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | |||
267 | pointer += 2 + tuple.TupleDataLen; | ||
268 | |||
269 | if (pointer >= (off + count)) | ||
270 | break; | ||
271 | |||
272 | if (tuple.TupleCode == CISTPL_END) | ||
273 | break; | ||
274 | status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple); | ||
275 | } | ||
276 | |||
277 | kfree(tempbuffer); | ||
278 | free_tuple: | ||
279 | kfree(tuplebuffer); | ||
280 | |||
281 | return ret; | ||
282 | } | ||
283 | |||
284 | static ssize_t pccard_show_cis(struct kobject *kobj, | ||
285 | struct bin_attribute *bin_attr, | ||
286 | char *buf, loff_t off, size_t count) | ||
287 | { | ||
288 | unsigned int size = 0x200; | ||
289 | |||
290 | if (off >= size) | ||
291 | count = 0; | ||
292 | else { | ||
293 | struct pcmcia_socket *s; | ||
294 | unsigned int chains; | ||
295 | |||
296 | if (off + count > size) | ||
297 | count = size - off; | ||
298 | |||
299 | s = to_socket(container_of(kobj, struct device, kobj)); | ||
300 | |||
301 | if (!(s->state & SOCKET_PRESENT)) | ||
302 | return -ENODEV; | ||
303 | if (pccard_validate_cis(s, &chains)) | ||
304 | return -EIO; | ||
305 | if (!chains) | ||
306 | return -ENODATA; | ||
307 | |||
308 | count = pccard_extract_cis(s, buf, off, count); | ||
309 | } | ||
310 | |||
311 | return count; | ||
312 | } | ||
313 | |||
314 | static ssize_t pccard_store_cis(struct kobject *kobj, | ||
315 | struct bin_attribute *bin_attr, | ||
316 | char *buf, loff_t off, size_t count) | ||
317 | { | ||
318 | struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj)); | ||
319 | int error; | ||
320 | |||
321 | if (off) | ||
322 | return -EINVAL; | ||
323 | |||
324 | if (count >= CISTPL_MAX_CIS_SIZE) | ||
325 | return -EINVAL; | ||
326 | |||
327 | if (!(s->state & SOCKET_PRESENT)) | ||
328 | return -ENODEV; | ||
329 | |||
330 | error = pcmcia_replace_cis(s, buf, count); | ||
331 | if (error) | ||
332 | return -EIO; | ||
333 | |||
334 | mutex_lock(&s->skt_mutex); | ||
335 | if ((s->callback) && (s->state & SOCKET_PRESENT) && | ||
336 | !(s->state & SOCKET_CARDBUS)) { | ||
337 | if (try_module_get(s->callback->owner)) { | ||
338 | s->callback->requery(s, 1); | ||
339 | module_put(s->callback->owner); | ||
340 | } | ||
341 | } | ||
342 | mutex_unlock(&s->skt_mutex); | ||
343 | 205 | ||
344 | return count; | 206 | return count; |
345 | } | 207 | } |
346 | 208 | static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); | |
347 | 209 | ||
348 | static struct attribute *pccard_socket_attributes[] = { | 210 | static struct attribute *pccard_socket_attributes[] = { |
349 | &dev_attr_card_type.attr, | 211 | &dev_attr_card_type.attr, |
@@ -362,28 +224,12 @@ static const struct attribute_group socket_attrs = { | |||
362 | .attrs = pccard_socket_attributes, | 224 | .attrs = pccard_socket_attributes, |
363 | }; | 225 | }; |
364 | 226 | ||
365 | static struct bin_attribute pccard_cis_attr = { | ||
366 | .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR }, | ||
367 | .size = 0x200, | ||
368 | .read = pccard_show_cis, | ||
369 | .write = pccard_store_cis, | ||
370 | }; | ||
371 | |||
372 | int pccard_sysfs_add_socket(struct device *dev) | 227 | int pccard_sysfs_add_socket(struct device *dev) |
373 | { | 228 | { |
374 | int ret = 0; | 229 | return sysfs_create_group(&dev->kobj, &socket_attrs); |
375 | |||
376 | ret = sysfs_create_group(&dev->kobj, &socket_attrs); | ||
377 | if (!ret) { | ||
378 | ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr); | ||
379 | if (ret) | ||
380 | sysfs_remove_group(&dev->kobj, &socket_attrs); | ||
381 | } | ||
382 | return ret; | ||
383 | } | 230 | } |
384 | 231 | ||
385 | void pccard_sysfs_remove_socket(struct device *dev) | 232 | void pccard_sysfs_remove_socket(struct device *dev) |
386 | { | 233 | { |
387 | sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr); | ||
388 | sysfs_remove_group(&dev->kobj, &socket_attrs); | 234 | sysfs_remove_group(&dev->kobj, &socket_attrs); |
389 | } | 235 | } |