~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/mtd/mtdpart.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Simple MTD partitioning layer
  3  *
  4  * (C) 2000 Nicolas Pitre <nico@cam.org>
  5  *
  6  * This code is GPL
  7  *
  8  * $Id: mtdpart.c,v 1.7 2000/12/09 23:29:47 dwmw2 Exp $
  9  */
 10 
 11 #include <linux/module.h>
 12 #include <linux/types.h>
 13 #include <linux/kernel.h>
 14 #include <linux/malloc.h>
 15 #include <linux/list.h>
 16 
 17 #include <linux/mtd/mtd.h>
 18 #include <linux/mtd/partitions.h>
 19 
 20 
 21 /* Our partition linked list */
 22 static LIST_HEAD(mtd_partitions);
 23 
 24 /* Our partition node structure */
 25 struct mtd_part {
 26         struct mtd_info mtd;
 27         struct mtd_info *master;
 28         loff_t offset;
 29         int index;
 30         struct list_head list;
 31 };
 32 
 33 /*
 34  * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
 35  * the pointer to that structure with this macro.
 36  */
 37 #define PART(x)  ((struct mtd_part *)(x))
 38 
 39         
 40 /* 
 41  * MTD methods which simply translate the effective address and pass through
 42  * to the _real_ device.
 43  */
 44 
 45 static int part_read (struct mtd_info *mtd, loff_t from, size_t len, 
 46                         size_t *retlen, u_char *buf)
 47 {
 48         struct mtd_part *part = PART(mtd);
 49         if (from >= mtd->size)
 50                 len = 0;
 51         else if (from + len > mtd->size)
 52                 len = mtd->size - from;
 53         return part->master->read (part->master, from + part->offset, 
 54                                         len, retlen, buf);
 55 }
 56 
 57 static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
 58                         size_t *retlen, const u_char *buf)
 59 {
 60         struct mtd_part *part = PART(mtd);
 61         if (!(mtd->flags & MTD_WRITEABLE))
 62                 return -EROFS;
 63         if (to >= mtd->size)
 64                 len = 0;
 65         else if (to + len > mtd->size)
 66                 len = mtd->size - to;
 67         return part->master->write (part->master, to + part->offset, 
 68                                         len, retlen, buf);
 69 }
 70 
 71 static int part_writev (struct mtd_info *mtd,  const struct iovec *vecs,
 72                          unsigned long count, loff_t to, size_t *retlen)
 73 {
 74         struct mtd_part *part = PART(mtd);
 75         if (!(mtd->flags & MTD_WRITEABLE))
 76                 return -EROFS;
 77         return part->master->writev (part->master, vecs, count,
 78                                         to + part->offset, retlen);
 79 }
 80 
 81 static int part_readv (struct mtd_info *mtd,  struct iovec *vecs,
 82                          unsigned long count, loff_t from, size_t *retlen)
 83 {
 84         struct mtd_part *part = PART(mtd);
 85         return part->master->readv (part->master, vecs, count,
 86                                         from + part->offset, retlen);
 87 }
 88 
 89 static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
 90 {
 91         struct mtd_part *part = PART(mtd);
 92         if (!(mtd->flags & MTD_WRITEABLE))
 93                 return -EROFS;
 94         if (instr->addr >= mtd->size)
 95                 return -EINVAL;
 96         instr->addr += part->offset;
 97         return part->master->erase(part->master, instr);
 98 }
 99 
100 static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
101 {
102         struct mtd_part *part = PART(mtd);
103         return part->master->lock(part->master, ofs + part->offset, len);
104 }
105 
106 static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
107 {
108         struct mtd_part *part = PART(mtd);
109         return part->master->unlock(part->master, ofs + part->offset, len);
110 }
111 
112 
113 /* 
114  * This function unregisters and destroy all slave MTD objects which are 
115  * attached to the given master MTD object.
116  */
117 
118 int del_mtd_partitions(struct mtd_info *master)
119 {
120         struct list_head *node;
121         struct mtd_part *slave;
122 
123         for (node = mtd_partitions.next;
124              node != &mtd_partitions;
125              node = node->next) {
126                 slave = list_entry(node, struct mtd_part, list);
127                 if (slave->master == master) {
128                         struct list_head *prev = node->prev;
129                         __list_del(prev, node->next);
130                         del_mtd_device(&slave->mtd);
131                         kfree(slave);
132                         node = prev;
133                         MOD_DEC_USE_COUNT;
134                 }
135         }
136 
137         return 0;
138 }
139 
140 
141 /*
142  * This function, given a master MTD object and a partition table, creates
143  * and registers slave MTD objects which are bound to the master according to
144  * the partition definitions.
145  * (Q: should we register the master MTD object as well?)
146  */
147 
148 int add_mtd_partitions(struct mtd_info *master, 
149                        struct mtd_partition *parts,
150                        int nbparts)
151 {
152         struct mtd_part *slave;
153         u_long cur_offset = 0;
154         int i;
155 
156         for (i = 0; i < nbparts; i++) {
157                 /* allocate the partition structure */
158                 slave = kmalloc (sizeof(*slave), GFP_KERNEL);
159                 if (!slave) {
160                         printk ("memory allocation error while creating partitions for \"%s\"\n",
161                                 master->name);
162                         del_mtd_partitions(master);
163                         return -ENOMEM;
164                 }
165                 list_add(&slave->list, &mtd_partitions);
166 
167                 /* set up the MTD object for this partition */
168                 slave->mtd = *master;
169                 slave->mtd.name = parts[i].name;
170                 slave->mtd.size = parts[i].size;
171                 slave->mtd.flags &= ~parts[i].mask_flags;
172                 slave->mtd.read = part_read;
173                 slave->mtd.write = part_write;
174                 if (slave->mtd.writev)
175                         slave->mtd.writev = part_writev;
176                 if (slave->mtd.readv)
177                         slave->mtd.readv = part_readv;
178                 if (slave->mtd.lock)
179                         slave->mtd.lock = part_lock;
180                 if (slave->mtd.unlock)
181                         slave->mtd.unlock = part_unlock;
182                 slave->mtd.erase = part_erase;
183                 slave->master = master;
184                 slave->offset = parts[i].offset;
185                 slave->index = i;
186 
187                 if (slave->offset == 0)
188                         slave->offset = cur_offset;
189                 if (slave->mtd.size == 0)
190                         slave->mtd.size = master->size - slave->offset;
191                 cur_offset = slave->offset + slave->mtd.size;
192 
193                 /* let's do some sanity checks */
194                 if ((slave->mtd.flags & MTD_WRITEABLE) && 
195                     (parts[i].offset % master->erasesize)) {
196                         slave->mtd.flags &= ~MTD_WRITEABLE;
197                         printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
198                                         parts[i].name);
199                 }
200                 if ((slave->mtd.flags & MTD_WRITEABLE) && 
201                     (parts[i].size % master->erasesize)) {
202                         slave->mtd.flags &= ~MTD_WRITEABLE;
203                         printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
204                                         parts[i].name);
205                 }
206                 if (parts[i].offset >= master->size) {
207                         /* let's register it anyway to preserve ordering */
208                         slave->offset = 0;
209                         slave->mtd.size = 0;
210                         printk ("mtd: partition \"%s\" is out of reach -- disabled\n",
211                                         parts[i].name);
212                 }
213                 if (parts[i].offset + parts[i].size > master->size) {
214                         slave->mtd.size = master->size - parts[i].offset;
215                         printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#lx\n",
216                                         parts[i].name, master->name, slave->mtd.size);
217                 }
218 
219                 /* register our partition */
220                 add_mtd_device(&slave->mtd);
221                 MOD_INC_USE_COUNT;
222         }
223 
224         return 0;
225 }
226 
227 EXPORT_SYMBOL(add_mtd_partitions);
228 EXPORT_SYMBOL(del_mtd_partitions);
229 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.