]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/pcmcia/rsrc_nonstatic.c
Merge master.kernel.org:/home/rmk/linux-2.6-arm
[karo-tx-linux.git] / drivers / pcmcia / rsrc_nonstatic.c
index 6b463609a3aa91f6ff862e82905845398ca1e515..00960a379b9c177b6071d8bf0d76a9b386ae8938 100644 (file)
@@ -372,6 +372,9 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
           base, base+num-1);
     bad = fail = 0;
     step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
+    /* don't allow too large steps */
+    if (step > 0x800000)
+       step = 0x800000;
     /* cis_readable wants to map 2x map_size */
     if (step < 2 * s->map_size)
        step = 2 * s->map_size;
@@ -465,8 +468,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
 
        for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
                mm = *m;
-               if (do_mem_probe(mm.base, mm.num, s))
-                       break;
+               do_mem_probe(mm.base, mm.num, s);
        }
 }
 
@@ -689,7 +691,7 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned
        unsigned long size = end - start + 1;
        int ret = 0;
 
-       if (end <= start)
+       if (end < start)
                return -EINVAL;
 
        down(&rsrc_sem);
@@ -722,7 +724,7 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long
        unsigned long size = end - start + 1;
        int ret = 0;
 
-       if (end <= start)
+       if (end < start)
                return -EINVAL;
 
        if (end > IO_SPACE_LIMIT)
@@ -768,6 +770,69 @@ static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj
        return CS_UNSUPPORTED_FUNCTION;
 }
 
+#ifdef CONFIG_PCI
+static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
+{
+       struct resource *res;
+       int i, done = 0;
+
+       if (!s->cb_dev || !s->cb_dev->bus)
+               return -ENODEV;
+
+#if defined(CONFIG_X86)
+       /* If this is the root bus, the risk of hitting
+        * some strange system devices which aren't protected
+        * by either ACPI resource tables or properly requested
+        * resources is too big. Therefore, don't do auto-adding
+        * of resources at the moment.
+        */
+       if (s->cb_dev->bus->number == 0)
+               return -EINVAL;
+#endif
+
+       for (i=0; i < PCI_BUS_NUM_RESOURCES; i++) {
+               res = s->cb_dev->bus->resource[i];
+               if (!res)
+                       continue;
+
+               if (res->flags & IORESOURCE_IO) {
+                       if (res == &ioport_resource)
+                               continue;
+                       printk(KERN_INFO "pcmcia: parent PCI bridge I/O window: 0x%lx - 0x%lx\n",
+                              res->start, res->end);
+                       if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
+                               done |= IORESOURCE_IO;
+
+               }
+
+               if (res->flags & IORESOURCE_MEM) {
+                       if (res == &iomem_resource)
+                               continue;
+                       printk(KERN_INFO "pcmcia: parent PCI bridge Memory window: 0x%lx - 0x%lx\n",
+                              res->start, res->end);
+                       if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
+                               done |= IORESOURCE_MEM;
+               }
+       }
+
+       /* if we got at least one of IO, and one of MEM, we can be glad and
+        * activate the PCMCIA subsystem */
+       if (done == (IORESOURCE_MEM | IORESOURCE_IO))
+               s->resource_setup_done = 1;
+
+       return 0;
+}
+
+#else
+
+static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
+{
+       return -ENODEV;
+}
+
+#endif
+
+
 static int nonstatic_init(struct pcmcia_socket *s)
 {
        struct socket_data *data;
@@ -782,6 +847,8 @@ static int nonstatic_init(struct pcmcia_socket *s)
 
        s->resource_data = (void *) data;
 
+       nonstatic_autoadd_resources(s);
+
        return 0;
 }
 
@@ -858,10 +925,12 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size
                                return -EINVAL;
                }
        }
-       if (end_addr <= start_addr)
+       if (end_addr < start_addr)
                return -EINVAL;
 
        ret = adjust_io(s, add, start_addr, end_addr);
+       if (!ret)
+               s->resource_setup_new = 1;
 
        return ret ? ret : count;
 }
@@ -908,10 +977,12 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz
                                return -EINVAL;
                }
        }
-       if (end_addr <= start_addr)
+       if (end_addr < start_addr)
                return -EINVAL;
 
        ret = adjust_memory(s, add, start_addr, end_addr);
+       if (!ret)
+               s->resource_setup_new = 1;
 
        return ret ? ret : count;
 }
@@ -923,7 +994,8 @@ static struct class_device_attribute *pccard_rsrc_attributes[] = {
        NULL,
 };
 
-static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev)
+static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev,
+                                          struct class_interface *class_intf)
 {
        struct pcmcia_socket *s = class_get_devdata(class_dev);
        struct class_device_attribute **attr;
@@ -940,7 +1012,8 @@ static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev)
        return ret;
 }
 
-static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev)
+static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev,
+                                              struct class_interface *class_intf)
 {
        struct pcmcia_socket *s = class_get_devdata(class_dev);
        struct class_device_attribute **attr;