This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / mtd / chips / gen_probe.c
index 3615fd8..bae2fb5 100644 (file)
@@ -2,7 +2,7 @@
  * Routines common to all CFI-type probes.
  * (C) 2001-2003 Red Hat, Inc.
  * GPL'd
- * $Id: gen_probe.c,v 1.19 2004/07/13 22:33:32 dwmw2 Exp $
+ * $Id: gen_probe.c,v 1.13 2003/06/25 11:50:37 dwmw2 Exp $
  */
 
 #include <linux/kernel.h>
@@ -50,15 +50,16 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
 EXPORT_SYMBOL(mtd_do_chip_probe);
 
 
-static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
+struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
 {
+       unsigned long base=0;
        struct cfi_private cfi;
        struct cfi_private *retcfi;
-       unsigned long *chip_map;
-       int i, j, mapsize;
-       int max_chips;
+       struct flchip chip[MAX_CFI_CHIPS];
+       int i;
 
        memset(&cfi, 0, sizeof(cfi));
+       memset(&chip[0], 0, sizeof(chip));
 
        /* Call the probetype-specific code with all permutations of 
           interleave and device type, etc. */
@@ -79,47 +80,46 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
                return NULL;
        }
 #endif
+       chip[0].start = 0;
+       chip[0].state = FL_READY;
        cfi.chipshift = cfi.cfiq->DevSize;
 
-       if (cfi_interleave_is_1(&cfi)) {
-               ;
-       } else if (cfi_interleave_is_2(&cfi)) {
+       switch(cfi.interleave) {
+#ifdef CFIDEV_INTERLEAVE_1
+       case 1:
+               break;
+#endif
+#ifdef CFIDEV_INTERLEAVE_2
+       case 2:
                cfi.chipshift++;
-       } else if (cfi_interleave_is_4((&cfi))) {
-               cfi.chipshift += 2;
-       } else if (cfi_interleave_is_8(&cfi)) {
-               cfi.chipshift += 3;
-       } else {
+               break;
+#endif
+#ifdef CFIDEV_INTERLEAVE_4
+       case 4:
+               cfi.chipshift+=2;
+               break;
+#endif
+       default:
                BUG();
        }
                
        cfi.numchips = 1;
 
-       /* 
-        * Allocate memory for bitmap of valid chips. 
-        * Align bitmap storage size to full byte. 
-        */ 
-       max_chips = map->size >> cfi.chipshift;
-       mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0);
-       chip_map = kmalloc(mapsize, GFP_KERNEL);
-       if (!chip_map) {
-               printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
-               kfree(cfi.cfiq);
-               return NULL;
-       }
-       memset (chip_map, 0, mapsize);
-
-       set_bit(0, chip_map); /* Mark first chip valid */
-
        /*
         * Now probe for other chips, checking sensibly for aliases while
         * we're at it. The new_chip probe above should have let the first
         * chip in read mode.
+        *
+        * NOTE: Here, we're checking if there is room for another chip
+        *       the same size within the mapping. Therefore, 
+        *       base + chipsize <= map->size is the correct thing to do, 
+        *       because, base + chipsize would be the  _first_ byte of the
+        *       next chip, not the one we're currently pondering.
         */
 
-       for (i = 1; i < max_chips; i++) {
-               cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi);
-       }
+       for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size;
+            base += (1<<cfi.chipshift))
+               cp->probe_chip(map, base, &chip[0], &cfi);
 
        /*
         * Now allocate the space for the structures we need to return to 
@@ -131,26 +131,19 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
        if (!retcfi) {
                printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name);
                kfree(cfi.cfiq);
-               kfree(chip_map);
                return NULL;
        }
 
        memcpy(retcfi, &cfi, sizeof(cfi));
-       memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips);
-
-       for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) {
-               if(test_bit(i, chip_map)) {
-                       struct flchip *pchip = &retcfi->chips[j++];
-
-                       pchip->start = (i << cfi.chipshift);
-                       pchip->state = FL_READY;
-                       init_waitqueue_head(&pchip->wq);
-                       spin_lock_init(&pchip->_spinlock);
-                       pchip->mutex = &pchip->_spinlock;
-               }
+       memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips);
+
+       /* Fix up the stuff that breaks when you move it */
+       for (i=0; i< retcfi->numchips; i++) {
+               init_waitqueue_head(&retcfi->chips[i].wq);
+               spin_lock_init(&retcfi->chips[i]._spinlock);
+               retcfi->chips[i].mutex = &retcfi->chips[i]._spinlock;
        }
 
-       kfree(chip_map);
        return retcfi;
 }
 
@@ -158,27 +151,131 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
 static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
                             struct cfi_private *cfi)
 {
-       int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */
-       int max_chips = map_bankwidth(map); /* And minimum 1 */
-       int nr_chips, type;
-
-       for (nr_chips = min_chips; nr_chips <= max_chips; nr_chips <<= 1) {
-
-               if (!cfi_interleave_supported(nr_chips))
-                   continue;
-
-               cfi->interleave = nr_chips;
-
-               for (type = 0; type < 3; type++) {
-                       cfi->device_type = 1<<type;
-
-                       if (cp->probe_chip(map, 0, NULL, cfi))
-                               return 1;
-               }
+       switch (map->buswidth) {
+#ifdef CFIDEV_BUSWIDTH_1               
+       case CFIDEV_BUSWIDTH_1:
+               cfi->interleave = CFIDEV_INTERLEAVE_1;
+
+               cfi->device_type = CFI_DEVICETYPE_X8;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+
+               cfi->device_type = CFI_DEVICETYPE_X16;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+               break;                  
+#endif /* CFIDEV_BUSWITDH_1 */
+
+#ifdef CFIDEV_BUSWIDTH_2               
+       case CFIDEV_BUSWIDTH_2:
+#ifdef CFIDEV_INTERLEAVE_1
+               cfi->interleave = CFIDEV_INTERLEAVE_1;
+
+               cfi->device_type = CFI_DEVICETYPE_X16;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+#endif /* CFIDEV_INTERLEAVE_1 */
+#ifdef CFIDEV_INTERLEAVE_2
+               cfi->interleave = CFIDEV_INTERLEAVE_2;
+
+               cfi->device_type = CFI_DEVICETYPE_X8;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+
+               cfi->device_type = CFI_DEVICETYPE_X16;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+#endif /* CFIDEV_INTERLEAVE_2 */
+               break;                  
+#endif /* CFIDEV_BUSWIDTH_2 */
+
+#ifdef CFIDEV_BUSWIDTH_4
+       case CFIDEV_BUSWIDTH_4:
+#if defined(CFIDEV_INTERLEAVE_1) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
+                cfi->interleave = CFIDEV_INTERLEAVE_1;
+
+                cfi->device_type = CFI_DEVICETYPE_X32;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+#endif /* CFIDEV_INTERLEAVE_1 */
+#ifdef CFIDEV_INTERLEAVE_2
+               cfi->interleave = CFIDEV_INTERLEAVE_2;
+
+#ifdef SOMEONE_ACTUALLY_MAKES_THESE
+               cfi->device_type = CFI_DEVICETYPE_X32;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+#endif
+               cfi->device_type = CFI_DEVICETYPE_X16;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+
+               cfi->device_type = CFI_DEVICETYPE_X8;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+#endif /* CFIDEV_INTERLEAVE_2 */
+#ifdef CFIDEV_INTERLEAVE_4
+               cfi->interleave = CFIDEV_INTERLEAVE_4;
+
+#ifdef SOMEONE_ACTUALLY_MAKES_THESE
+               cfi->device_type = CFI_DEVICETYPE_X32;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+#endif
+               cfi->device_type = CFI_DEVICETYPE_X16;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+
+               cfi->device_type = CFI_DEVICETYPE_X8;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+#endif /* CFIDEV_INTERLEAVE_4 */
+               break;
+#endif /* CFIDEV_BUSWIDTH_4 */
+
+#ifdef CFIDEV_BUSWIDTH_8
+       case CFIDEV_BUSWIDTH_8:
+#if defined(CFIDEV_INTERLEAVE_2) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
+                cfi->interleave = CFIDEV_INTERLEAVE_2;
+
+                cfi->device_type = CFI_DEVICETYPE_X32;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+#endif /* CFIDEV_INTERLEAVE_2 */
+#ifdef CFIDEV_INTERLEAVE_4
+               cfi->interleave = CFIDEV_INTERLEAVE_4;
+
+#ifdef SOMEONE_ACTUALLY_MAKES_THESE
+               cfi->device_type = CFI_DEVICETYPE_X32;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+#endif
+               cfi->device_type = CFI_DEVICETYPE_X16;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+#endif /* CFIDEV_INTERLEAVE_4 */
+#ifdef CFIDEV_INTERLEAVE_8
+               cfi->interleave = CFIDEV_INTERLEAVE_8;
+
+               cfi->device_type = CFI_DEVICETYPE_X16;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+
+               cfi->device_type = CFI_DEVICETYPE_X8;
+               if (cp->probe_chip(map, 0, NULL, cfi))
+                       return 1;
+#endif /* CFIDEV_INTERLEAVE_8 */
+               break;
+#endif /* CFIDEV_BUSWIDTH_8 */
+
+       default:
+               printk(KERN_WARNING "genprobe_new_chip called with unsupported buswidth %d\n", map->buswidth);
+               return 0;
        }
        return 0;
 }
 
+
 typedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int);
 
 extern cfi_cmdset_fn_t cfi_cmdset_0001;