[PATCH] pcmcia: CIS overrid via sysfs
Dominik Brodowski [Mon, 27 Jun 2005 23:28:09 +0000 (16:28 -0700)]
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>

drivers/pcmcia/cs_internal.h
drivers/pcmcia/ds.c
drivers/pcmcia/socket_sysfs.c

index 7933a7d..2116373 100644 (file)
@@ -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);
index c0611d5..f657a2a 100644 (file)
@@ -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);
index fd5a3b0..8e66eef 100644 (file)
@@ -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)