2 * Simple MTD partitioning layer
4 * (C) 2000 Nicolas Pitre <nico@cam.org>
8 * $Id: mtdpart.c,v 1.23 2001/10/02 15:05:11 dwmw2 Exp $
11 #include <linux/module.h>
12 #include <linux/types.h>
13 #include <linux/kernel.h>
14 #include <linux/slab.h>
15 #include <linux/list.h>
17 #include <linux/mtd/mtd.h>
18 #include <linux/mtd/partitions.h>
21 /* Our partition linked list */
22 static LIST_HEAD(mtd_partitions
);
24 /* Our partition node structure */
27 struct mtd_info
*master
;
30 struct list_head list
;
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.
37 #define PART(x) ((struct mtd_part *)(x))
41 * MTD methods which simply translate the effective address and pass through
42 * to the _real_ device.
45 static int part_read (struct mtd_info
*mtd
, loff_t from
, size_t len
,
46 size_t *retlen
, u_char
*buf
)
48 struct mtd_part
*part
= PART(mtd
);
49 if (from
>= mtd
->size
)
51 else if (from
+ len
> mtd
->size
)
52 len
= mtd
->size
- from
;
53 return part
->master
->read (part
->master
, from
+ part
->offset
,
57 static int part_write (struct mtd_info
*mtd
, loff_t to
, size_t len
,
58 size_t *retlen
, const u_char
*buf
)
60 struct mtd_part
*part
= PART(mtd
);
61 if (!(mtd
->flags
& MTD_WRITEABLE
))
65 else if (to
+ len
> mtd
->size
)
67 return part
->master
->write (part
->master
, to
+ part
->offset
,
71 static int part_writev (struct mtd_info
*mtd
, const struct iovec
*vecs
,
72 unsigned long count
, loff_t to
, size_t *retlen
)
74 struct mtd_part
*part
= PART(mtd
);
75 if (!(mtd
->flags
& MTD_WRITEABLE
))
77 return part
->master
->writev (part
->master
, vecs
, count
,
78 to
+ part
->offset
, retlen
);
81 static int part_readv (struct mtd_info
*mtd
, struct iovec
*vecs
,
82 unsigned long count
, loff_t from
, size_t *retlen
)
84 struct mtd_part
*part
= PART(mtd
);
85 return part
->master
->readv (part
->master
, vecs
, count
,
86 from
+ part
->offset
, retlen
);
89 static int part_erase (struct mtd_info
*mtd
, struct erase_info
*instr
)
91 struct mtd_part
*part
= PART(mtd
);
92 if (!(mtd
->flags
& MTD_WRITEABLE
))
94 if (instr
->addr
>= mtd
->size
)
96 instr
->addr
+= part
->offset
;
97 return part
->master
->erase(part
->master
, instr
);
100 static int part_lock (struct mtd_info
*mtd
, loff_t ofs
, size_t len
)
102 struct mtd_part
*part
= PART(mtd
);
103 if ((len
+ ofs
) > mtd
->size
)
105 return part
->master
->lock(part
->master
, ofs
+ part
->offset
, len
);
108 static int part_unlock (struct mtd_info
*mtd
, loff_t ofs
, size_t len
)
110 struct mtd_part
*part
= PART(mtd
);
111 if ((len
+ ofs
) > mtd
->size
)
113 return part
->master
->unlock(part
->master
, ofs
+ part
->offset
, len
);
116 static void part_sync(struct mtd_info
*mtd
)
118 struct mtd_part
*part
= PART(mtd
);
119 part
->master
->sync(part
->master
);
122 static int part_suspend(struct mtd_info
*mtd
)
124 struct mtd_part
*part
= PART(mtd
);
125 return part
->master
->suspend(part
->master
);
128 static void part_resume(struct mtd_info
*mtd
)
130 struct mtd_part
*part
= PART(mtd
);
131 part
->master
->resume(part
->master
);
135 * This function unregisters and destroy all slave MTD objects which are
136 * attached to the given master MTD object.
139 int del_mtd_partitions(struct mtd_info
*master
)
141 struct list_head
*node
;
142 struct mtd_part
*slave
;
144 for (node
= mtd_partitions
.next
;
145 node
!= &mtd_partitions
;
147 slave
= list_entry(node
, struct mtd_part
, list
);
148 if (slave
->master
== master
) {
149 struct list_head
*prev
= node
->prev
;
150 __list_del(prev
, node
->next
);
151 del_mtd_device(&slave
->mtd
);
161 * This function, given a master MTD object and a partition table, creates
162 * and registers slave MTD objects which are bound to the master according to
163 * the partition definitions.
164 * (Q: should we register the master MTD object as well?)
167 int add_mtd_partitions(struct mtd_info
*master
,
168 struct mtd_partition
*parts
,
171 struct mtd_part
*slave
;
172 u_int32_t cur_offset
= 0;
175 printk (KERN_NOTICE
"Creating %d MTD partitions on \"%s\":\n", nbparts
, master
->name
);
177 for (i
= 0; i
< nbparts
; i
++) {
179 /* allocate the partition structure */
180 slave
= kmalloc (sizeof(*slave
), GFP_KERNEL
);
182 printk ("memory allocation error while creating partitions for \"%s\"\n",
184 del_mtd_partitions(master
);
187 memset(slave
, 0, sizeof(*slave
));
188 list_add(&slave
->list
, &mtd_partitions
);
190 /* set up the MTD object for this partition */
191 slave
->mtd
.type
= master
->type
;
192 slave
->mtd
.flags
= master
->flags
& ~parts
[i
].mask_flags
;
193 slave
->mtd
.size
= parts
[i
].size
;
194 slave
->mtd
.oobblock
= master
->oobblock
;
195 slave
->mtd
.oobsize
= master
->oobsize
;
196 slave
->mtd
.ecctype
= master
->ecctype
;
197 slave
->mtd
.eccsize
= master
->eccsize
;
199 slave
->mtd
.name
= parts
[i
].name
;
200 slave
->mtd
.bank_size
= master
->bank_size
;
202 slave
->mtd
.module
= master
->module
;
204 slave
->mtd
.read
= part_read
;
205 slave
->mtd
.write
= part_write
;
207 slave
->mtd
.sync
= part_sync
;
208 if (!i
&& master
->suspend
&& master
->resume
) {
209 slave
->mtd
.suspend
= part_suspend
;
210 slave
->mtd
.resume
= part_resume
;
214 slave
->mtd
.writev
= part_writev
;
216 slave
->mtd
.readv
= part_readv
;
218 slave
->mtd
.lock
= part_lock
;
220 slave
->mtd
.unlock
= part_unlock
;
221 slave
->mtd
.erase
= part_erase
;
222 slave
->master
= master
;
223 slave
->offset
= parts
[i
].offset
;
226 if (slave
->offset
== MTDPART_OFS_APPEND
)
227 slave
->offset
= cur_offset
;
228 if (slave
->mtd
.size
== MTDPART_SIZ_FULL
)
229 slave
->mtd
.size
= master
->size
- slave
->offset
;
230 cur_offset
= slave
->offset
+ slave
->mtd
.size
;
232 printk (KERN_NOTICE
"0x%08x-0x%08x : \"%s\"\n", slave
->offset
,
233 slave
->offset
+ slave
->mtd
.size
, slave
->mtd
.name
);
235 /* let's do some sanity checks */
236 if (slave
->offset
>= master
->size
) {
237 /* let's register it anyway to preserve ordering */
240 printk ("mtd: partition \"%s\" is out of reach -- disabled\n",
243 if (slave
->offset
+ slave
->mtd
.size
> master
->size
) {
244 slave
->mtd
.size
= master
->size
- slave
->offset
;
245 printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n",
246 parts
[i
].name
, master
->name
, slave
->mtd
.size
);
248 if (master
->numeraseregions
>1) {
249 /* Deal with variable erase size stuff */
251 struct mtd_erase_region_info
*regions
= master
->eraseregions
;
253 /* Find the first erase regions which is part of this partition. */
254 for (i
=0; i
< master
->numeraseregions
&& slave
->offset
>= regions
[i
].offset
; i
++)
257 for (i
--; i
< master
->numeraseregions
&& slave
->offset
+ slave
->mtd
.size
> regions
[i
].offset
; i
++) {
258 if (slave
->mtd
.erasesize
< regions
[i
].erasesize
) {
259 slave
->mtd
.erasesize
= regions
[i
].erasesize
;
263 /* Single erase size */
264 slave
->mtd
.erasesize
= master
->erasesize
;
267 if ((slave
->mtd
.flags
& MTD_WRITEABLE
) &&
268 (slave
->offset
% slave
->mtd
.erasesize
)) {
269 /* Doesn't start on a boundary of major erase size */
270 /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
271 slave
->mtd
.flags
&= ~MTD_WRITEABLE
;
272 printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
275 if ((slave
->mtd
.flags
& MTD_WRITEABLE
) &&
276 (slave
->mtd
.size
% slave
->mtd
.erasesize
)) {
277 slave
->mtd
.flags
&= ~MTD_WRITEABLE
;
278 printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
282 /* register our partition */
283 add_mtd_device(&slave
->mtd
);
289 EXPORT_SYMBOL(add_mtd_partitions
);
290 EXPORT_SYMBOL(del_mtd_partitions
);
293 MODULE_LICENSE("GPL");
294 MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
295 MODULE_DESCRIPTION("Generic support for partitioning of MTD devices");