diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2005-06-28 03:28:09 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-28 05:03:07 +0400 |
commit | ff1fa9ef3c9fb23a6baa06b63f4bdf3de089b29a (patch) | |
tree | 05cd82cc6bbb4c9881de5d9c5584cc64f15262d1 /drivers/pcmcia | |
parent | 7f299bccb422d707be3b074f9a669b34cb207a14 (diff) | |
download | linux-ff1fa9ef3c9fb23a6baa06b63f4bdf3de089b29a.tar.xz |
[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/pcmcia')
-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{ struct module *owner; int (*event) (struct pcmcia_socket *s, event_t event, int priority); int (*resources_done) (struct pcmcia_socket *s); + void (*replace_cis) (void); }; 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) return; } +static void pcmcia_bus_rescan(void) +{ + /* must be called with skt_sem held */ + bus_rescan_devices(&pcmcia_bus_type); +} static inline int pcmcia_devmatch(struct pcmcia_device *dev, struct pcmcia_device_id *did) @@ -1766,6 +1771,7 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) s->callback.owner = THIS_MODULE; s->callback.event = &ds_event; s->callback.resources_done = &pcmcia_card_add; + s->callback.replace_cis = &pcmcia_bus_rescan; socket->pcmcia = s; 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 return (count); } +static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj)); + cisdump_t *cis; + ssize_t ret = count; + + if (off) + return -EINVAL; + + if (count >= 0x200) + return -EINVAL; + + if (!(s->state & SOCKET_PRESENT)) + return -ENODEV; + + cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL); + if (!cis) + return -ENOMEM; + memset(cis, 0, sizeof(cisdump_t)); + + cis->Length = count + 1; + memcpy(cis->Data, buf, count); + + if (pcmcia_replace_cis(s, cis)) + ret = -EIO; + + kfree(cis); + + if (!ret) { + down(&s->skt_sem); + if ((s->callback) && (s->state & SOCKET_PRESENT) && + !(s->state & SOCKET_CARDBUS)) { + if (try_module_get(s->callback->owner)) { + s->callback->replace_cis(); + module_put(s->callback->owner); + } + } + up(&s->skt_sem); + } + + + return (ret); +} + static struct class_device_attribute *pccard_socket_attributes[] = { &class_device_attr_card_type, @@ -296,9 +340,10 @@ static struct class_device_attribute *pccard_socket_attributes[] = { }; static struct bin_attribute pccard_cis_attr = { - .attr = { .name = "cis", .mode = S_IRUGO, .owner = THIS_MODULE}, + .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR, .owner = THIS_MODULE}, .size = 0x200, .read = pccard_show_cis, + .write = pccard_store_cis, }; static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) |