diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2005-06-27 19:28:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-27 21:03:07 -0400 |
commit | ff1fa9ef3c9fb23a6baa06b63f4bdf3de089b29a (patch) | |
tree | 05cd82cc6bbb4c9881de5d9c5584cc64f15262d1 /drivers | |
parent | 7f299bccb422d707be3b074f9a669b34cb207a14 (diff) |
[PATCH] pcmcia: CIS overrid via sysfs
The one thing which surprises me in this patch that cis->Length needs to be
set to count+1. Without it, it doesn't work, but with it, it doesn't make
sense to me.
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pcmcia/cs_internal.h | 1 | ||||
-rw-r--r-- | drivers/pcmcia/ds.c | 6 | ||||
-rw-r--r-- | drivers/pcmcia/socket_sysfs.c | 47 |
3 files changed, 53 insertions, 1 deletions
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 7933a7db49d3..211637390fbc 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h | |||
@@ -160,6 +160,7 @@ struct pcmcia_callback{ | |||
160 | struct module *owner; | 160 | struct module *owner; |
161 | int (*event) (struct pcmcia_socket *s, event_t event, int priority); | 161 | int (*event) (struct pcmcia_socket *s, event_t event, int priority); |
162 | int (*resources_done) (struct pcmcia_socket *s); | 162 | int (*resources_done) (struct pcmcia_socket *s); |
163 | void (*replace_cis) (void); | ||
163 | }; | 164 | }; |
164 | 165 | ||
165 | int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); | 166 | int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); |
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index c0611d56eab2..f657a2a77b2b 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
@@ -653,6 +653,11 @@ static inline void pcmcia_add_pseudo_device(struct pcmcia_bus_socket *s) | |||
653 | return; | 653 | return; |
654 | } | 654 | } |
655 | 655 | ||
656 | static void pcmcia_bus_rescan(void) | ||
657 | { | ||
658 | /* must be called with skt_sem held */ | ||
659 | bus_rescan_devices(&pcmcia_bus_type); | ||
660 | } | ||
656 | 661 | ||
657 | static inline int pcmcia_devmatch(struct pcmcia_device *dev, | 662 | static inline int pcmcia_devmatch(struct pcmcia_device *dev, |
658 | struct pcmcia_device_id *did) | 663 | struct pcmcia_device_id *did) |
@@ -1766,6 +1771,7 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) | |||
1766 | s->callback.owner = THIS_MODULE; | 1771 | s->callback.owner = THIS_MODULE; |
1767 | s->callback.event = &ds_event; | 1772 | s->callback.event = &ds_event; |
1768 | s->callback.resources_done = &pcmcia_card_add; | 1773 | s->callback.resources_done = &pcmcia_card_add; |
1774 | s->callback.replace_cis = &pcmcia_bus_rescan; | ||
1769 | socket->pcmcia = s; | 1775 | socket->pcmcia = s; |
1770 | 1776 | ||
1771 | ret = pccard_register_pcmcia(socket, &s->callback); | 1777 | ret = pccard_register_pcmcia(socket, &s->callback); |
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index fd5a3b0557b3..8e66eeff672e 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c | |||
@@ -282,6 +282,50 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size | |||
282 | return (count); | 282 | return (count); |
283 | } | 283 | } |
284 | 284 | ||
285 | static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
286 | { | ||
287 | struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj)); | ||
288 | cisdump_t *cis; | ||
289 | ssize_t ret = count; | ||
290 | |||
291 | if (off) | ||
292 | return -EINVAL; | ||
293 | |||
294 | if (count >= 0x200) | ||
295 | return -EINVAL; | ||
296 | |||
297 | if (!(s->state & SOCKET_PRESENT)) | ||
298 | return -ENODEV; | ||
299 | |||
300 | cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL); | ||
301 | if (!cis) | ||
302 | return -ENOMEM; | ||
303 | memset(cis, 0, sizeof(cisdump_t)); | ||
304 | |||
305 | cis->Length = count + 1; | ||
306 | memcpy(cis->Data, buf, count); | ||
307 | |||
308 | if (pcmcia_replace_cis(s, cis)) | ||
309 | ret = -EIO; | ||
310 | |||
311 | kfree(cis); | ||
312 | |||
313 | if (!ret) { | ||
314 | down(&s->skt_sem); | ||
315 | if ((s->callback) && (s->state & SOCKET_PRESENT) && | ||
316 | !(s->state & SOCKET_CARDBUS)) { | ||
317 | if (try_module_get(s->callback->owner)) { | ||
318 | s->callback->replace_cis(); | ||
319 | module_put(s->callback->owner); | ||
320 | } | ||
321 | } | ||
322 | up(&s->skt_sem); | ||
323 | } | ||
324 | |||
325 | |||
326 | return (ret); | ||
327 | } | ||
328 | |||
285 | 329 | ||
286 | static struct class_device_attribute *pccard_socket_attributes[] = { | 330 | static struct class_device_attribute *pccard_socket_attributes[] = { |
287 | &class_device_attr_card_type, | 331 | &class_device_attr_card_type, |
@@ -296,9 +340,10 @@ static struct class_device_attribute *pccard_socket_attributes[] = { | |||
296 | }; | 340 | }; |
297 | 341 | ||
298 | static struct bin_attribute pccard_cis_attr = { | 342 | static struct bin_attribute pccard_cis_attr = { |
299 | .attr = { .name = "cis", .mode = S_IRUGO, .owner = THIS_MODULE}, | 343 | .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR, .owner = THIS_MODULE}, |
300 | .size = 0x200, | 344 | .size = 0x200, |
301 | .read = pccard_show_cis, | 345 | .read = pccard_show_cis, |
346 | .write = pccard_store_cis, | ||
302 | }; | 347 | }; |
303 | 348 | ||
304 | static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) | 349 | static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) |