Blame view

drivers/mtd/mtdchar.c 27.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
a1452a377   David Woodhouse   mtd: Update copyr...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   * Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
   *
   */
15fdc52f3   Thomas Gleixner   [MTD] Tidy up Tim...
19
20
  #include <linux/device.h>
  #include <linux/fs.h>
0c1eafdb0   Andrew Morton   mtdchar build fix
21
  #include <linux/mm.h>
9c74034f8   Artem Bityutskiy   [MTD] return erro...
22
  #include <linux/err.h>
15fdc52f3   Thomas Gleixner   [MTD] Tidy up Tim...
23
  #include <linux/init.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  #include <linux/kernel.h>
  #include <linux/module.h>
15fdc52f3   Thomas Gleixner   [MTD] Tidy up Tim...
26
27
  #include <linux/slab.h>
  #include <linux/sched.h>
5aa82940b   Arnd Bergmann   mtd: autoconvert ...
28
  #include <linux/mutex.h>
402d32651   David Howells   NOMMU: Present ba...
29
  #include <linux/backing-dev.h>
977185404   Kevin Cernekee   mtd: compat_ioctl...
30
  #include <linux/compat.h>
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
31
  #include <linux/mount.h>
d0f7959e2   Roman Tereshonkov   mtd: add BLKPG AP...
32
  #include <linux/blkpg.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  #include <linux/mtd/mtd.h>
d0f7959e2   Roman Tereshonkov   mtd: add BLKPG AP...
34
  #include <linux/mtd/partitions.h>
dd02b67d5   Anatolij Gustschin   mtd: mtdchar: fix...
35
  #include <linux/mtd/map.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36

15fdc52f3   Thomas Gleixner   [MTD] Tidy up Tim...
37
  #include <asm/uaccess.h>
9bc7b3873   Todd Poynor   [MTD] mtdchar.c: ...
38

cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
39
  #define MTD_INODE_FS_MAGIC 0x11307854
5aa82940b   Arnd Bergmann   mtd: autoconvert ...
40
  static DEFINE_MUTEX(mtd_mutex);
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
41
  static struct vfsmount *mtd_inode_mnt __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42

045e9a5d5   Nicolas Pitre   [MTD] Unabuse fil...
43
  /*
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
44
   * Data structure to hold the pointer to the mtd device as well
92394b5c2   Brian Norris   mtd: spelling fixes
45
   * as mode information of various use cases.
045e9a5d5   Nicolas Pitre   [MTD] Unabuse fil...
46
   */
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
47
48
  struct mtd_file_info {
  	struct mtd_info *mtd;
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
49
  	struct inode *ino;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
50
51
  	enum mtd_file_modes mode;
  };
31f4233ba   Nicolas Pitre   [MTD] User interf...
52

969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
53
  static loff_t mtdchar_lseek(struct file *file, loff_t offset, int orig)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  {
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
55
56
  	struct mtd_file_info *mfi = file->private_data;
  	struct mtd_info *mtd = mfi->mtd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
  
  	switch (orig) {
ea59830db   Josef 'Jeff' Sipek   [MTD] Use SEEK_{S...
59
  	case SEEK_SET:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  		break;
ea59830db   Josef 'Jeff' Sipek   [MTD] Use SEEK_{S...
61
  	case SEEK_CUR:
8b491d750   Todd Poynor   [MTD] mtdchar: Re...
62
  		offset += file->f_pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  		break;
ea59830db   Josef 'Jeff' Sipek   [MTD] Use SEEK_{S...
64
  	case SEEK_END:
8b491d750   Todd Poynor   [MTD] mtdchar: Re...
65
  		offset += mtd->size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
69
  		break;
  	default:
  		return -EINVAL;
  	}
1887f517e   Herbert Valerio Riedel   [MTD] CORE mtdcha...
70
  	if (offset >= 0 && offset <= mtd->size)
8b491d750   Todd Poynor   [MTD] mtdchar: Re...
71
  		return file->f_pos = offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72

8b491d750   Todd Poynor   [MTD] mtdchar: Re...
73
  	return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  }
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
75
  static int mtdchar_open(struct inode *inode, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
  {
  	int minor = iminor(inode);
  	int devnum = minor >> 1;
6071239ef   Jonathan Corbet   mtdchar: cdev loc...
79
  	int ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
  	struct mtd_info *mtd;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
81
  	struct mtd_file_info *mfi;
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
82
  	struct inode *mtd_ino;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83

289c05222   Brian Norris   mtd: replace DEBU...
84
85
  	pr_debug("MTD_open
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
  	/* You can't open the RO devices RW */
aeb5d7270   Al Viro   [PATCH] introduce...
88
  	if ((file->f_mode & FMODE_WRITE) && (minor & 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  		return -EACCES;
5aa82940b   Arnd Bergmann   mtd: autoconvert ...
90
  	mutex_lock(&mtd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  	mtd = get_mtd_device(NULL, devnum);
97894cda5   Thomas Gleixner   [MTD] core: Clean...
92

6071239ef   Jonathan Corbet   mtdchar: cdev loc...
93
94
95
96
  	if (IS_ERR(mtd)) {
  		ret = PTR_ERR(mtd);
  		goto out;
  	}
97894cda5   Thomas Gleixner   [MTD] core: Clean...
97

402d32651   David Howells   NOMMU: Present ba...
98
  	if (mtd->type == MTD_ABSENT) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
  		put_mtd_device(mtd);
6071239ef   Jonathan Corbet   mtdchar: cdev loc...
100
101
  		ret = -ENODEV;
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  	}
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
103
104
105
106
107
108
109
110
111
112
113
114
115
  	mtd_ino = iget_locked(mtd_inode_mnt->mnt_sb, devnum);
  	if (!mtd_ino) {
  		put_mtd_device(mtd);
  		ret = -ENOMEM;
  		goto out;
  	}
  	if (mtd_ino->i_state & I_NEW) {
  		mtd_ino->i_private = mtd;
  		mtd_ino->i_mode = S_IFCHR;
  		mtd_ino->i_data.backing_dev_info = mtd->backing_dev_info;
  		unlock_new_inode(mtd_ino);
  	}
  	file->f_mapping = mtd_ino->i_mapping;
402d32651   David Howells   NOMMU: Present ba...
116

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
  	/* You can't open it RW if it's not a writeable device */
aeb5d7270   Al Viro   [PATCH] introduce...
118
  	if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) {
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
119
  		iput(mtd_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  		put_mtd_device(mtd);
6071239ef   Jonathan Corbet   mtdchar: cdev loc...
121
122
  		ret = -EACCES;
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  	}
97894cda5   Thomas Gleixner   [MTD] core: Clean...
124

f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
125
126
  	mfi = kzalloc(sizeof(*mfi), GFP_KERNEL);
  	if (!mfi) {
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
127
  		iput(mtd_ino);
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
128
  		put_mtd_device(mtd);
6071239ef   Jonathan Corbet   mtdchar: cdev loc...
129
130
  		ret = -ENOMEM;
  		goto out;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
131
  	}
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
132
  	mfi->ino = mtd_ino;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
133
134
  	mfi->mtd = mtd;
  	file->private_data = mfi;
6071239ef   Jonathan Corbet   mtdchar: cdev loc...
135
  out:
5aa82940b   Arnd Bergmann   mtd: autoconvert ...
136
  	mutex_unlock(&mtd_mutex);
6071239ef   Jonathan Corbet   mtdchar: cdev loc...
137
  	return ret;
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
138
  } /* mtdchar_open */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
  
  /*====================================================================*/
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
141
  static int mtdchar_close(struct inode *inode, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  {
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
143
144
  	struct mtd_file_info *mfi = file->private_data;
  	struct mtd_info *mtd = mfi->mtd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145

289c05222   Brian Norris   mtd: replace DEBU...
146
147
  	pr_debug("MTD_close
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148

7eafaed55   Joakim Tjernlund   [MTD] Only call m...
149
  	/* Only sync if opened RW */
327cf2922   Artem Bityutskiy   mtd: do not use m...
150
  	if ((file->f_mode & FMODE_WRITE))
85f2f2a80   Artem Bityutskiy   mtd: introduce mt...
151
  		mtd_sync(mtd);
97894cda5   Thomas Gleixner   [MTD] core: Clean...
152

cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
153
  	iput(mfi->ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  	put_mtd_device(mtd);
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
155
156
  	file->private_data = NULL;
  	kfree(mfi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
  
  	return 0;
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
159
  } /* mtdchar_close */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160

3e45cf5e8   Grant Erickson   mtd: mtdchar: ret...
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  /* Back in June 2001, dwmw2 wrote:
   *
   *   FIXME: This _really_ needs to die. In 2.5, we should lock the
   *   userspace buffer down and use it directly with readv/writev.
   *
   * The implementation below, using mtd_kmalloc_up_to, mitigates
   * allocation failures when the system is under low-memory situations
   * or if memory is highly fragmented at the cost of reducing the
   * performance of the requested transfer due to a smaller buffer size.
   *
   * A more complex but more memory-efficient implementation based on
   * get_user_pages and iovecs to cover extents of those pages is a
   * longer-term goal, as intimated by dwmw2 above. However, for the
   * write case, this requires yet more complex head and tail transfer
   * handling when those head and tail offsets and sizes are such that
   * alignment requirements are not met in the NAND subdriver.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178

969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
179
180
  static ssize_t mtdchar_read(struct file *file, char __user *buf, size_t count,
  			loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  {
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
182
183
  	struct mtd_file_info *mfi = file->private_data;
  	struct mtd_info *mtd = mfi->mtd;
30fa98480   Artem Bityutskiy   mtd: remove extra...
184
  	size_t retlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
  	size_t total_retlen=0;
  	int ret=0;
  	int len;
3e45cf5e8   Grant Erickson   mtd: mtdchar: ret...
188
  	size_t size = count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  	char *kbuf;
97894cda5   Thomas Gleixner   [MTD] core: Clean...
190

289c05222   Brian Norris   mtd: replace DEBU...
191
192
  	pr_debug("MTD_read
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
195
196
197
198
  
  	if (*ppos + count > mtd->size)
  		count = mtd->size - *ppos;
  
  	if (!count)
  		return 0;
97894cda5   Thomas Gleixner   [MTD] core: Clean...
199

3e45cf5e8   Grant Erickson   mtd: mtdchar: ret...
200
  	kbuf = mtd_kmalloc_up_to(mtd, &size);
b802c0741   Thago Galesi   [PATCH] Remove un...
201
202
  	if (!kbuf)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
  	while (count) {
3e45cf5e8   Grant Erickson   mtd: mtdchar: ret...
204
  		len = min_t(size_t, count, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205

f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
206
  		switch (mfi->mode) {
beb133fc1   Brian Norris   mtd: rename MTD_M...
207
  		case MTD_FILE_MODE_OTP_FACTORY:
d264f72ae   Artem Bityutskiy   mtd: introduce mt...
208
209
  			ret = mtd_read_fact_prot_reg(mtd, *ppos, len,
  						     &retlen, kbuf);
31f4233ba   Nicolas Pitre   [MTD] User interf...
210
  			break;
beb133fc1   Brian Norris   mtd: rename MTD_M...
211
  		case MTD_FILE_MODE_OTP_USER:
4ea1cabb9   Artem Bityutskiy   mtd: introduce mt...
212
213
  			ret = mtd_read_user_prot_reg(mtd, *ppos, len,
  						     &retlen, kbuf);
31f4233ba   Nicolas Pitre   [MTD] User interf...
214
  			break;
beb133fc1   Brian Norris   mtd: rename MTD_M...
215
  		case MTD_FILE_MODE_RAW:
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
216
217
  		{
  			struct mtd_oob_ops ops;
0612b9ddc   Brian Norris   mtd: rename MTD_O...
218
  			ops.mode = MTD_OPS_RAW;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
219
220
221
  			ops.datbuf = kbuf;
  			ops.oobbuf = NULL;
  			ops.len = len;
fd2819bbc   Artem Bityutskiy   mtd: introduce mt...
222
  			ret = mtd_read_oob(mtd, *ppos, &ops);
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
223
224
225
  			retlen = ops.retlen;
  			break;
  		}
31f4233ba   Nicolas Pitre   [MTD] User interf...
226
  		default:
329ad399a   Artem Bityutskiy   mtd: introduce mt...
227
  			ret = mtd_read(mtd, *ppos, len, &retlen, kbuf);
31f4233ba   Nicolas Pitre   [MTD] User interf...
228
  		}
7854d3f74   Brian Norris   mtd: spelling, ca...
229
  		/* Nand returns -EBADMSG on ECC errors, but it returns
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  		 * the data. For our userspace tools it is important
7854d3f74   Brian Norris   mtd: spelling, ca...
231
  		 * to dump areas with ECC errors!
9a1fcdfd4   Thomas Gleixner   [MTD] NAND Signal...
232
  		 * For kernel internal usage it also might return -EUCLEAN
25985edce   Lucas De Marchi   Fix common misspe...
233
  		 * to signal the caller that a bitflip has occurred and has
9a1fcdfd4   Thomas Gleixner   [MTD] NAND Signal...
234
  		 * been corrected by the ECC algorithm.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
  		 * Userspace software which accesses NAND this way
  		 * must be aware of the fact that it deals with NAND
  		 */
d57f40544   Brian Norris   mtd: utilize `mtd...
238
  		if (!ret || mtd_is_bitflip_or_eccerr(ret)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
  			*ppos += retlen;
  			if (copy_to_user(buf, kbuf, retlen)) {
f4a43cfce   Thomas Gleixner   [MTD] Remove sill...
241
  				kfree(kbuf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
244
245
246
247
248
  				return -EFAULT;
  			}
  			else
  				total_retlen += retlen;
  
  			count -= retlen;
  			buf += retlen;
31f4233ba   Nicolas Pitre   [MTD] User interf...
249
250
  			if (retlen == 0)
  				count = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
254
255
  		}
  		else {
  			kfree(kbuf);
  			return ret;
  		}
97894cda5   Thomas Gleixner   [MTD] core: Clean...
256

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  	}
b802c0741   Thago Galesi   [PATCH] Remove un...
258
  	kfree(kbuf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
  	return total_retlen;
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
260
  } /* mtdchar_read */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261

969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
262
263
  static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t count,
  			loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
  {
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
265
266
  	struct mtd_file_info *mfi = file->private_data;
  	struct mtd_info *mtd = mfi->mtd;
3e45cf5e8   Grant Erickson   mtd: mtdchar: ret...
267
  	size_t size = count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
271
272
  	char *kbuf;
  	size_t retlen;
  	size_t total_retlen=0;
  	int ret=0;
  	int len;
289c05222   Brian Norris   mtd: replace DEBU...
273
274
  	pr_debug("MTD_write
  ");
97894cda5   Thomas Gleixner   [MTD] core: Clean...
275

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
  	if (*ppos == mtd->size)
  		return -ENOSPC;
97894cda5   Thomas Gleixner   [MTD] core: Clean...
278

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
282
283
  	if (*ppos + count > mtd->size)
  		count = mtd->size - *ppos;
  
  	if (!count)
  		return 0;
3e45cf5e8   Grant Erickson   mtd: mtdchar: ret...
284
  	kbuf = mtd_kmalloc_up_to(mtd, &size);
b802c0741   Thago Galesi   [PATCH] Remove un...
285
286
  	if (!kbuf)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  	while (count) {
3e45cf5e8   Grant Erickson   mtd: mtdchar: ret...
288
  		len = min_t(size_t, count, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
292
293
  		if (copy_from_user(kbuf, buf, len)) {
  			kfree(kbuf);
  			return -EFAULT;
  		}
97894cda5   Thomas Gleixner   [MTD] core: Clean...
294

f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
295
  		switch (mfi->mode) {
beb133fc1   Brian Norris   mtd: rename MTD_M...
296
  		case MTD_FILE_MODE_OTP_FACTORY:
31f4233ba   Nicolas Pitre   [MTD] User interf...
297
298
  			ret = -EROFS;
  			break;
beb133fc1   Brian Norris   mtd: rename MTD_M...
299
  		case MTD_FILE_MODE_OTP_USER:
482b43adb   Artem Bityutskiy   mtd: introduce mt...
300
301
  			ret = mtd_write_user_prot_reg(mtd, *ppos, len,
  						      &retlen, kbuf);
31f4233ba   Nicolas Pitre   [MTD] User interf...
302
  			break;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
303

beb133fc1   Brian Norris   mtd: rename MTD_M...
304
  		case MTD_FILE_MODE_RAW:
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
305
306
  		{
  			struct mtd_oob_ops ops;
0612b9ddc   Brian Norris   mtd: rename MTD_O...
307
  			ops.mode = MTD_OPS_RAW;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
308
309
  			ops.datbuf = kbuf;
  			ops.oobbuf = NULL;
bf5140817   Peter Wippich   mtd: mtdchar: add...
310
  			ops.ooboffs = 0;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
311
  			ops.len = len;
a2cc5ba07   Artem Bityutskiy   mtd: introduce mt...
312
  			ret = mtd_write_oob(mtd, *ppos, &ops);
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
313
314
315
  			retlen = ops.retlen;
  			break;
  		}
31f4233ba   Nicolas Pitre   [MTD] User interf...
316
  		default:
eda95cbf7   Artem Bityutskiy   mtd: introduce mt...
317
  			ret = mtd_write(mtd, *ppos, len, &retlen, kbuf);
31f4233ba   Nicolas Pitre   [MTD] User interf...
318
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
321
322
323
324
325
326
327
328
  		if (!ret) {
  			*ppos += retlen;
  			total_retlen += retlen;
  			count -= retlen;
  			buf += retlen;
  		}
  		else {
  			kfree(kbuf);
  			return ret;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
  	}
b802c0741   Thago Galesi   [PATCH] Remove un...
330
  	kfree(kbuf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
  	return total_retlen;
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
332
  } /* mtdchar_write */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
336
337
338
339
340
341
342
  
  /*======================================================================
  
      IOCTL calls for getting device parameters.
  
  ======================================================================*/
  static void mtdchar_erase_callback (struct erase_info *instr)
  {
  	wake_up((wait_queue_head_t *)instr->priv);
  }
34a82443b   David Brownell   [MTD] dataflash O...
343
  #ifdef CONFIG_HAVE_MTD_OTP
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
344
345
346
  static int otp_select_filemode(struct mtd_file_info *mfi, int mode)
  {
  	struct mtd_info *mtd = mfi->mtd;
b6de3d6cb   Artem Bityutskiy   mtd: do not use m...
347
  	size_t retlen;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
348
  	int ret = 0;
b6de3d6cb   Artem Bityutskiy   mtd: do not use m...
349
350
351
352
353
354
  	/*
  	 * Make a fake call to mtd_read_fact_prot_reg() to check if OTP
  	 * operations are supported.
  	 */
  	if (mtd_read_fact_prot_reg(mtd, -1, -1, &retlen, NULL) == -EOPNOTSUPP)
  		return -EOPNOTSUPP;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
355
356
  	switch (mode) {
  	case MTD_OTP_FACTORY:
b6de3d6cb   Artem Bityutskiy   mtd: do not use m...
357
  		mfi->mode = MTD_FILE_MODE_OTP_FACTORY;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
358
359
  		break;
  	case MTD_OTP_USER:
b6de3d6cb   Artem Bityutskiy   mtd: do not use m...
360
  		mfi->mode = MTD_FILE_MODE_OTP_USER;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
361
362
363
364
365
366
367
368
369
370
371
  		break;
  	default:
  		ret = -EINVAL;
  	case MTD_OTP_OFF:
  		break;
  	}
  	return ret;
  }
  #else
  # define otp_select_filemode(f,m)	-EOPNOTSUPP
  #endif
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
372
  static int mtdchar_writeoob(struct file *file, struct mtd_info *mtd,
977185404   Kevin Cernekee   mtd: compat_ioctl...
373
374
375
  	uint64_t start, uint32_t length, void __user *ptr,
  	uint32_t __user *retp)
  {
9ce244b3f   Brian Norris   mtd: support writ...
376
  	struct mtd_file_info *mfi = file->private_data;
977185404   Kevin Cernekee   mtd: compat_ioctl...
377
378
379
380
381
382
383
384
385
386
387
388
389
  	struct mtd_oob_ops ops;
  	uint32_t retlen;
  	int ret = 0;
  
  	if (!(file->f_mode & FMODE_WRITE))
  		return -EPERM;
  
  	if (length > 4096)
  		return -EINVAL;
  
  	if (!mtd->write_oob)
  		ret = -EOPNOTSUPP;
  	else
0040476b0   Roel Kluin   mtd: change posit...
390
  		ret = access_ok(VERIFY_READ, ptr, length) ? 0 : -EFAULT;
977185404   Kevin Cernekee   mtd: compat_ioctl...
391
392
393
394
395
  
  	if (ret)
  		return ret;
  
  	ops.ooblen = length;
305b93f18   Brian Norris   mtd: do not assum...
396
  	ops.ooboffs = start & (mtd->writesize - 1);
977185404   Kevin Cernekee   mtd: compat_ioctl...
397
  	ops.datbuf = NULL;
beb133fc1   Brian Norris   mtd: rename MTD_M...
398
  	ops.mode = (mfi->mode == MTD_FILE_MODE_RAW) ? MTD_OPS_RAW :
0612b9ddc   Brian Norris   mtd: rename MTD_O...
399
  		MTD_OPS_PLACE_OOB;
977185404   Kevin Cernekee   mtd: compat_ioctl...
400
401
402
  
  	if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
  		return -EINVAL;
df1f1d1cb   Julia Lawall   drivers/mtd: Use ...
403
404
405
  	ops.oobbuf = memdup_user(ptr, length);
  	if (IS_ERR(ops.oobbuf))
  		return PTR_ERR(ops.oobbuf);
977185404   Kevin Cernekee   mtd: compat_ioctl...
406

305b93f18   Brian Norris   mtd: do not assum...
407
  	start &= ~((uint64_t)mtd->writesize - 1);
a2cc5ba07   Artem Bityutskiy   mtd: introduce mt...
408
  	ret = mtd_write_oob(mtd, start, &ops);
977185404   Kevin Cernekee   mtd: compat_ioctl...
409
410
411
412
413
414
415
416
417
418
  
  	if (ops.oobretlen > 0xFFFFFFFFU)
  		ret = -EOVERFLOW;
  	retlen = ops.oobretlen;
  	if (copy_to_user(retp, &retlen, sizeof(length)))
  		ret = -EFAULT;
  
  	kfree(ops.oobbuf);
  	return ret;
  }
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
419
  static int mtdchar_readoob(struct file *file, struct mtd_info *mtd,
c46f6483d   Brian Norris   mtd: support read...
420
421
  	uint64_t start, uint32_t length, void __user *ptr,
  	uint32_t __user *retp)
977185404   Kevin Cernekee   mtd: compat_ioctl...
422
  {
c46f6483d   Brian Norris   mtd: support read...
423
  	struct mtd_file_info *mfi = file->private_data;
977185404   Kevin Cernekee   mtd: compat_ioctl...
424
425
426
427
428
  	struct mtd_oob_ops ops;
  	int ret = 0;
  
  	if (length > 4096)
  		return -EINVAL;
dac2639f9   Artem Bityutskiy   mtd: do not use m...
429
430
  	if (!access_ok(VERIFY_WRITE, ptr, length))
  		return -EFAULT;
977185404   Kevin Cernekee   mtd: compat_ioctl...
431
432
  
  	ops.ooblen = length;
305b93f18   Brian Norris   mtd: do not assum...
433
  	ops.ooboffs = start & (mtd->writesize - 1);
977185404   Kevin Cernekee   mtd: compat_ioctl...
434
  	ops.datbuf = NULL;
beb133fc1   Brian Norris   mtd: rename MTD_M...
435
  	ops.mode = (mfi->mode == MTD_FILE_MODE_RAW) ? MTD_OPS_RAW :
0612b9ddc   Brian Norris   mtd: rename MTD_O...
436
  		MTD_OPS_PLACE_OOB;
977185404   Kevin Cernekee   mtd: compat_ioctl...
437
438
439
440
441
442
443
  
  	if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
  		return -EINVAL;
  
  	ops.oobbuf = kmalloc(length, GFP_KERNEL);
  	if (!ops.oobbuf)
  		return -ENOMEM;
305b93f18   Brian Norris   mtd: do not assum...
444
  	start &= ~((uint64_t)mtd->writesize - 1);
fd2819bbc   Artem Bityutskiy   mtd: introduce mt...
445
  	ret = mtd_read_oob(mtd, start, &ops);
977185404   Kevin Cernekee   mtd: compat_ioctl...
446
447
448
449
450
451
452
453
  
  	if (put_user(ops.oobretlen, retp))
  		ret = -EFAULT;
  	else if (ops.oobretlen && copy_to_user(ptr, ops.oobbuf,
  					    ops.oobretlen))
  		ret = -EFAULT;
  
  	kfree(ops.oobbuf);
041e4575f   Brian Norris   mtd: nand: handle...
454
455
456
457
458
459
460
461
462
  
  	/*
  	 * NAND returns -EBADMSG on ECC errors, but it returns the OOB
  	 * data. For our userspace tools it is important to dump areas
  	 * with ECC errors!
  	 * For kernel internal usage it also might return -EUCLEAN
  	 * to signal the caller that a bitflip has occured and has
  	 * been corrected by the ECC algorithm.
  	 *
c478d7e44   Brian Norris   mtd: edit NAND-re...
463
464
465
  	 * Note: currently the standard NAND function, nand_read_oob_std,
  	 * does not calculate ECC for the OOB area, so do not rely on
  	 * this behavior unless you have replaced it with your own.
041e4575f   Brian Norris   mtd: nand: handle...
466
  	 */
d57f40544   Brian Norris   mtd: utilize `mtd...
467
  	if (mtd_is_bitflip_or_eccerr(ret))
041e4575f   Brian Norris   mtd: nand: handle...
468
  		return 0;
977185404   Kevin Cernekee   mtd: compat_ioctl...
469
470
  	return ret;
  }
cc26c3cd3   Brian Norris   mtd: nand: expand...
471
472
473
  /*
   * Copies (and truncates, if necessary) data from the larger struct,
   * nand_ecclayout, to the smaller, deprecated layout struct,
92394b5c2   Brian Norris   mtd: spelling fixes
474
   * nand_ecclayout_user. This is necessary only to support the deprecated
cc26c3cd3   Brian Norris   mtd: nand: expand...
475
476
477
478
479
480
481
482
483
484
485
486
487
   * API ioctl ECCGETLAYOUT while allowing all new functionality to use
   * nand_ecclayout flexibly (i.e. the struct may change size in new
   * releases without requiring major rewrites).
   */
  static int shrink_ecclayout(const struct nand_ecclayout *from,
  		struct nand_ecclayout_user *to)
  {
  	int i;
  
  	if (!from || !to)
  		return -EINVAL;
  
  	memset(to, 0, sizeof(*to));
0ceacf36e   Brian Norris   mtd: edit comment...
488
  	to->eccbytes = min((int)from->eccbytes, MTD_MAX_ECCPOS_ENTRIES);
cc26c3cd3   Brian Norris   mtd: nand: expand...
489
490
491
492
493
494
495
496
497
498
499
500
501
  	for (i = 0; i < to->eccbytes; i++)
  		to->eccpos[i] = from->eccpos[i];
  
  	for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
  		if (from->oobfree[i].length == 0 &&
  				from->oobfree[i].offset == 0)
  			break;
  		to->oobavail += from->oobfree[i].length;
  		to->oobfree[i] = from->oobfree[i];
  	}
  
  	return 0;
  }
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
502
  static int mtdchar_blkpg_ioctl(struct mtd_info *mtd,
d0f7959e2   Roman Tereshonkov   mtd: add BLKPG AP...
503
504
505
506
507
508
509
  			   struct blkpg_ioctl_arg __user *arg)
  {
  	struct blkpg_ioctl_arg a;
  	struct blkpg_partition p;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
d0f7959e2   Roman Tereshonkov   mtd: add BLKPG AP...
510
511
512
513
514
515
516
517
  	if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
  		return -EFAULT;
  
  	if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
  		return -EFAULT;
  
  	switch (a.op) {
  	case BLKPG_ADD_PARTITION:
a7e93dcd9   Roman Tereshonkov   mtd: fix master d...
518
519
520
  		/* Only master mtd device must be used to add partitions */
  		if (mtd_is_partition(mtd))
  			return -EINVAL;
d0f7959e2   Roman Tereshonkov   mtd: add BLKPG AP...
521
522
523
524
525
526
527
528
529
530
531
532
533
  		return mtd_add_partition(mtd, p.devname, p.start, p.length);
  
  	case BLKPG_DEL_PARTITION:
  
  		if (p.pno < 0)
  			return -EINVAL;
  
  		return mtd_del_partition(mtd, p.pno);
  
  	default:
  		return -EINVAL;
  	}
  }
d0f7959e2   Roman Tereshonkov   mtd: add BLKPG AP...
534

969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
535
  static int mtdchar_write_ioctl(struct mtd_info *mtd,
e99d8b089   Brian Norris   mtd: add MEMWRITE...
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  		struct mtd_write_req __user *argp)
  {
  	struct mtd_write_req req;
  	struct mtd_oob_ops ops;
  	void __user *usr_data, *usr_oob;
  	int ret;
  
  	if (copy_from_user(&req, argp, sizeof(req)) ||
  			!access_ok(VERIFY_READ, req.usr_data, req.len) ||
  			!access_ok(VERIFY_READ, req.usr_oob, req.ooblen))
  		return -EFAULT;
  	if (!mtd->write_oob)
  		return -EOPNOTSUPP;
  
  	ops.mode = req.mode;
  	ops.len = (size_t)req.len;
  	ops.ooblen = (size_t)req.ooblen;
  	ops.ooboffs = 0;
  
  	usr_data = (void __user *)(uintptr_t)req.usr_data;
  	usr_oob = (void __user *)(uintptr_t)req.usr_oob;
  
  	if (req.usr_data) {
  		ops.datbuf = memdup_user(usr_data, ops.len);
  		if (IS_ERR(ops.datbuf))
  			return PTR_ERR(ops.datbuf);
  	} else {
  		ops.datbuf = NULL;
  	}
  
  	if (req.usr_oob) {
  		ops.oobbuf = memdup_user(usr_oob, ops.ooblen);
  		if (IS_ERR(ops.oobbuf)) {
  			kfree(ops.datbuf);
  			return PTR_ERR(ops.oobbuf);
  		}
  	} else {
  		ops.oobbuf = NULL;
  	}
a2cc5ba07   Artem Bityutskiy   mtd: introduce mt...
575
  	ret = mtd_write_oob(mtd, (loff_t)req.start, &ops);
e99d8b089   Brian Norris   mtd: add MEMWRITE...
576
577
578
579
580
581
  
  	kfree(ops.datbuf);
  	kfree(ops.oobbuf);
  
  	return ret;
  }
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
582
  static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  {
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
584
585
  	struct mtd_file_info *mfi = file->private_data;
  	struct mtd_info *mtd = mfi->mtd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
588
  	void __user *argp = (void __user *)arg;
  	int ret = 0;
  	u_long size;
73c619ea0   Joern Engel   [MTD] Disconnect ...
589
  	struct mtd_info_user info;
97894cda5   Thomas Gleixner   [MTD] core: Clean...
590

289c05222   Brian Norris   mtd: replace DEBU...
591
592
  	pr_debug("MTD_ioctl
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
596
597
598
599
600
601
602
  
  	size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
  	if (cmd & IOC_IN) {
  		if (!access_ok(VERIFY_READ, argp, size))
  			return -EFAULT;
  	}
  	if (cmd & IOC_OUT) {
  		if (!access_ok(VERIFY_WRITE, argp, size))
  			return -EFAULT;
  	}
97894cda5   Thomas Gleixner   [MTD] core: Clean...
603

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
605
606
607
608
609
610
611
  	switch (cmd) {
  	case MEMGETREGIONCOUNT:
  		if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int)))
  			return -EFAULT;
  		break;
  
  	case MEMGETREGIONINFO:
  	{
b67c5f87c   Zev Weiss   [MTD] mtdchar.c: ...
612
613
  		uint32_t ur_idx;
  		struct mtd_erase_region_info *kr;
bcc98a46e   H Hartley Sweeten   mtd: fix differen...
614
  		struct region_info_user __user *ur = argp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615

b67c5f87c   Zev Weiss   [MTD] mtdchar.c: ...
616
  		if (get_user(ur_idx, &(ur->regionindex)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
  			return -EFAULT;
5e59be1f3   Dan Carpenter   mtd: sanity check...
618
619
  		if (ur_idx >= mtd->numeraseregions)
  			return -EINVAL;
b67c5f87c   Zev Weiss   [MTD] mtdchar.c: ...
620
621
622
623
624
  		kr = &(mtd->eraseregions[ur_idx]);
  
  		if (put_user(kr->offset, &(ur->offset))
  		    || put_user(kr->erasesize, &(ur->erasesize))
  		    || put_user(kr->numblocks, &(ur->numblocks)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
  			return -EFAULT;
b67c5f87c   Zev Weiss   [MTD] mtdchar.c: ...
626

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
630
  		break;
  	}
  
  	case MEMGETINFO:
a0c5a3944   Vasiliy Kulikov   mtd: mtdchar: fix...
631
  		memset(&info, 0, sizeof(info));
73c619ea0   Joern Engel   [MTD] Disconnect ...
632
633
634
635
636
637
  		info.type	= mtd->type;
  		info.flags	= mtd->flags;
  		info.size	= mtd->size;
  		info.erasesize	= mtd->erasesize;
  		info.writesize	= mtd->writesize;
  		info.oobsize	= mtd->oobsize;
19fb4341a   Brian Norris   mtd: kill old fie...
638
639
  		/* The below field is obsolete */
  		info.padding	= 0;
73c619ea0   Joern Engel   [MTD] Disconnect ...
640
  		if (copy_to_user(argp, &info, sizeof(struct mtd_info_user)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
  			return -EFAULT;
  		break;
  
  	case MEMERASE:
0dc54e9f3   Kevin Cernekee   mtd: add MEMERASE...
645
  	case MEMERASE64:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
  	{
  		struct erase_info *erase;
aeb5d7270   Al Viro   [PATCH] introduce...
648
  		if(!(file->f_mode & FMODE_WRITE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
  			return -EPERM;
95b93a0cd   Burman Yan   [MTD] replace kma...
650
  		erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
654
655
656
657
  		if (!erase)
  			ret = -ENOMEM;
  		else {
  			wait_queue_head_t waitq;
  			DECLARE_WAITQUEUE(wait, current);
  
  			init_waitqueue_head(&waitq);
0dc54e9f3   Kevin Cernekee   mtd: add MEMERASE...
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
  			if (cmd == MEMERASE64) {
  				struct erase_info_user64 einfo64;
  
  				if (copy_from_user(&einfo64, argp,
  					    sizeof(struct erase_info_user64))) {
  					kfree(erase);
  					return -EFAULT;
  				}
  				erase->addr = einfo64.start;
  				erase->len = einfo64.length;
  			} else {
  				struct erase_info_user einfo32;
  
  				if (copy_from_user(&einfo32, argp,
  					    sizeof(struct erase_info_user))) {
  					kfree(erase);
  					return -EFAULT;
  				}
  				erase->addr = einfo32.start;
  				erase->len = einfo32.length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
680
681
  			}
  			erase->mtd = mtd;
  			erase->callback = mtdchar_erase_callback;
  			erase->priv = (unsigned long)&waitq;
97894cda5   Thomas Gleixner   [MTD] core: Clean...
682

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
685
  			/*
  			  FIXME: Allow INTERRUPTIBLE. Which means
  			  not having the wait_queue head on the stack.
97894cda5   Thomas Gleixner   [MTD] core: Clean...
686

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
688
689
690
691
  			  If the wq_head is on the stack, and we
  			  leave because we got interrupted, then the
  			  wq_head is no longer there when the
  			  callback routine tries to wake us up.
  			*/
7e1f0dc05   Artem Bityutskiy   mtd: introduce mt...
692
  			ret = mtd_erase(mtd, erase);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
  			if (!ret) {
  				set_current_state(TASK_UNINTERRUPTIBLE);
  				add_wait_queue(&waitq, &wait);
  				if (erase->state != MTD_ERASE_DONE &&
  				    erase->state != MTD_ERASE_FAILED)
  					schedule();
  				remove_wait_queue(&waitq, &wait);
  				set_current_state(TASK_RUNNING);
  
  				ret = (erase->state == MTD_ERASE_FAILED)?-EIO:0;
  			}
  			kfree(erase);
  		}
  		break;
  	}
  
  	case MEMWRITEOOB:
  	{
  		struct mtd_oob_buf buf;
977185404   Kevin Cernekee   mtd: compat_ioctl...
712
  		struct mtd_oob_buf __user *buf_user = argp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713

977185404   Kevin Cernekee   mtd: compat_ioctl...
714
715
  		/* NOTE: writes return length to buf_user->length */
  		if (copy_from_user(&buf, argp, sizeof(buf)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
  			ret = -EFAULT;
977185404   Kevin Cernekee   mtd: compat_ioctl...
717
  		else
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
718
  			ret = mtdchar_writeoob(file, mtd, buf.start, buf.length,
977185404   Kevin Cernekee   mtd: compat_ioctl...
719
  				buf.ptr, &buf_user->length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
723
724
725
  	}
  
  	case MEMREADOOB:
  	{
  		struct mtd_oob_buf buf;
977185404   Kevin Cernekee   mtd: compat_ioctl...
726
  		struct mtd_oob_buf __user *buf_user = argp;
8593fbc68   Thomas Gleixner   [MTD] Rework the ...
727

977185404   Kevin Cernekee   mtd: compat_ioctl...
728
729
  		/* NOTE: writes return length to buf_user->start */
  		if (copy_from_user(&buf, argp, sizeof(buf)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  			ret = -EFAULT;
977185404   Kevin Cernekee   mtd: compat_ioctl...
731
  		else
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
732
  			ret = mtdchar_readoob(file, mtd, buf.start, buf.length,
977185404   Kevin Cernekee   mtd: compat_ioctl...
733
  				buf.ptr, &buf_user->start);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
  		break;
  	}
aea7cea9f   Kevin Cernekee   mtd: add OOB ioct...
736
737
738
739
740
741
742
743
  	case MEMWRITEOOB64:
  	{
  		struct mtd_oob_buf64 buf;
  		struct mtd_oob_buf64 __user *buf_user = argp;
  
  		if (copy_from_user(&buf, argp, sizeof(buf)))
  			ret = -EFAULT;
  		else
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
744
  			ret = mtdchar_writeoob(file, mtd, buf.start, buf.length,
aea7cea9f   Kevin Cernekee   mtd: add OOB ioct...
745
746
747
748
749
750
751
752
753
754
755
756
757
  				(void __user *)(uintptr_t)buf.usr_ptr,
  				&buf_user->length);
  		break;
  	}
  
  	case MEMREADOOB64:
  	{
  		struct mtd_oob_buf64 buf;
  		struct mtd_oob_buf64 __user *buf_user = argp;
  
  		if (copy_from_user(&buf, argp, sizeof(buf)))
  			ret = -EFAULT;
  		else
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
758
  			ret = mtdchar_readoob(file, mtd, buf.start, buf.length,
aea7cea9f   Kevin Cernekee   mtd: add OOB ioct...
759
760
761
762
  				(void __user *)(uintptr_t)buf.usr_ptr,
  				&buf_user->length);
  		break;
  	}
e99d8b089   Brian Norris   mtd: add MEMWRITE...
763
764
  	case MEMWRITE:
  	{
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
765
  		ret = mtdchar_write_ioctl(mtd,
e99d8b089   Brian Norris   mtd: add MEMWRITE...
766
767
768
  		      (struct mtd_write_req __user *)arg);
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
  	case MEMLOCK:
  	{
175428b2b   Harvey Harrison   [MTD] mtdchar.c r...
771
  		struct erase_info_user einfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772

175428b2b   Harvey Harrison   [MTD] mtdchar.c r...
773
  		if (copy_from_user(&einfo, argp, sizeof(einfo)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
  			return -EFAULT;
381345652   Artem Bityutskiy   mtd: do not use m...
775
  		ret = mtd_lock(mtd, einfo.start, einfo.length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
777
778
779
780
  		break;
  	}
  
  	case MEMUNLOCK:
  	{
175428b2b   Harvey Harrison   [MTD] mtdchar.c r...
781
  		struct erase_info_user einfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782

175428b2b   Harvey Harrison   [MTD] mtdchar.c r...
783
  		if (copy_from_user(&einfo, argp, sizeof(einfo)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
  			return -EFAULT;
381345652   Artem Bityutskiy   mtd: do not use m...
785
  		ret = mtd_unlock(mtd, einfo.start, einfo.length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
  		break;
  	}
9938424f0   Richard Cochran   mtd: add an ioctl...
788
789
790
791
792
793
  	case MEMISLOCKED:
  	{
  		struct erase_info_user einfo;
  
  		if (copy_from_user(&einfo, argp, sizeof(einfo)))
  			return -EFAULT;
381345652   Artem Bityutskiy   mtd: do not use m...
794
  		ret = mtd_is_locked(mtd, einfo.start, einfo.length);
9938424f0   Richard Cochran   mtd: add an ioctl...
795
796
  		break;
  	}
5bd34c091   Thomas Gleixner   [MTD] NAND Replac...
797
  	/* Legacy interface */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
  	case MEMGETOOBSEL:
  	{
5bd34c091   Thomas Gleixner   [MTD] NAND Replac...
800
801
802
803
804
805
806
807
808
809
810
  		struct nand_oobinfo oi;
  
  		if (!mtd->ecclayout)
  			return -EOPNOTSUPP;
  		if (mtd->ecclayout->eccbytes > ARRAY_SIZE(oi.eccpos))
  			return -EINVAL;
  
  		oi.useecc = MTD_NANDECC_AUTOPLACE;
  		memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos));
  		memcpy(&oi.oobfree, mtd->ecclayout->oobfree,
  		       sizeof(oi.oobfree));
d25ade71e   Ricard Wanderlöf   [MTD] mtdchar: Fi...
811
  		oi.eccbytes = mtd->ecclayout->eccbytes;
5bd34c091   Thomas Gleixner   [MTD] NAND Replac...
812
813
  
  		if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
816
817
818
819
820
  			return -EFAULT;
  		break;
  	}
  
  	case MEMGETBADBLOCK:
  	{
  		loff_t offs;
97894cda5   Thomas Gleixner   [MTD] core: Clean...
821

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
823
  		if (copy_from_user(&offs, argp, sizeof(loff_t)))
  			return -EFAULT;
8f461a730   Artem Bityutskiy   mtd: introduce mt...
824
  		return mtd_block_isbad(mtd, offs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
827
828
829
830
831
832
833
  		break;
  	}
  
  	case MEMSETBADBLOCK:
  	{
  		loff_t offs;
  
  		if (copy_from_user(&offs, argp, sizeof(loff_t)))
  			return -EFAULT;
800ffd349   Artem Bityutskiy   mtd: do not use m...
834
  		return mtd_block_markbad(mtd, offs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
  		break;
  	}
34a82443b   David Brownell   [MTD] dataflash O...
837
  #ifdef CONFIG_HAVE_MTD_OTP
31f4233ba   Nicolas Pitre   [MTD] User interf...
838
839
840
841
842
  	case OTPSELECT:
  	{
  		int mode;
  		if (copy_from_user(&mode, argp, sizeof(int)))
  			return -EFAULT;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
843

beb133fc1   Brian Norris   mtd: rename MTD_M...
844
  		mfi->mode = MTD_FILE_MODE_NORMAL;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
845
846
  
  		ret = otp_select_filemode(mfi, mode);
81dba4887   Nicolas Pitre   [MTD] Reset file ...
847
  		file->f_pos = 0;
31f4233ba   Nicolas Pitre   [MTD] User interf...
848
849
850
851
852
853
854
855
856
  		break;
  	}
  
  	case OTPGETREGIONCOUNT:
  	case OTPGETREGIONINFO:
  	{
  		struct otp_info *buf = kmalloc(4096, GFP_KERNEL);
  		if (!buf)
  			return -ENOMEM;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
857
  		switch (mfi->mode) {
beb133fc1   Brian Norris   mtd: rename MTD_M...
858
  		case MTD_FILE_MODE_OTP_FACTORY:
87e858a97   Artem Bityutskiy   mtd: do not use m...
859
  			ret = mtd_get_fact_prot_info(mtd, buf, 4096);
31f4233ba   Nicolas Pitre   [MTD] User interf...
860
  			break;
beb133fc1   Brian Norris   mtd: rename MTD_M...
861
  		case MTD_FILE_MODE_OTP_USER:
87e858a97   Artem Bityutskiy   mtd: do not use m...
862
  			ret = mtd_get_user_prot_info(mtd, buf, 4096);
31f4233ba   Nicolas Pitre   [MTD] User interf...
863
  			break;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
864
  		default:
87e858a97   Artem Bityutskiy   mtd: do not use m...
865
  			ret = -EINVAL;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
866
  			break;
31f4233ba   Nicolas Pitre   [MTD] User interf...
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
  		}
  		if (ret >= 0) {
  			if (cmd == OTPGETREGIONCOUNT) {
  				int nbr = ret / sizeof(struct otp_info);
  				ret = copy_to_user(argp, &nbr, sizeof(int));
  			} else
  				ret = copy_to_user(argp, buf, ret);
  			if (ret)
  				ret = -EFAULT;
  		}
  		kfree(buf);
  		break;
  	}
  
  	case OTPLOCK:
  	{
175428b2b   Harvey Harrison   [MTD] mtdchar.c r...
883
  		struct otp_info oinfo;
31f4233ba   Nicolas Pitre   [MTD] User interf...
884

beb133fc1   Brian Norris   mtd: rename MTD_M...
885
  		if (mfi->mode != MTD_FILE_MODE_OTP_USER)
31f4233ba   Nicolas Pitre   [MTD] User interf...
886
  			return -EINVAL;
175428b2b   Harvey Harrison   [MTD] mtdchar.c r...
887
  		if (copy_from_user(&oinfo, argp, sizeof(oinfo)))
31f4233ba   Nicolas Pitre   [MTD] User interf...
888
  			return -EFAULT;
4403dbfb4   Artem Bityutskiy   mtd: introduce mt...
889
  		ret = mtd_lock_user_prot_reg(mtd, oinfo.start, oinfo.length);
31f4233ba   Nicolas Pitre   [MTD] User interf...
890
891
892
  		break;
  	}
  #endif
7854d3f74   Brian Norris   mtd: spelling, ca...
893
  	/* This ioctl is being deprecated - it truncates the ECC layout */
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
894
895
  	case ECCGETLAYOUT:
  	{
cc26c3cd3   Brian Norris   mtd: nand: expand...
896
  		struct nand_ecclayout_user *usrlay;
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
897
898
  		if (!mtd->ecclayout)
  			return -EOPNOTSUPP;
cc26c3cd3   Brian Norris   mtd: nand: expand...
899
900
901
902
903
904
905
906
907
  		usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL);
  		if (!usrlay)
  			return -ENOMEM;
  
  		shrink_ecclayout(mtd->ecclayout, usrlay);
  
  		if (copy_to_user(argp, usrlay, sizeof(*usrlay)))
  			ret = -EFAULT;
  		kfree(usrlay);
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
  		break;
  	}
  
  	case ECCGETSTATS:
  	{
  		if (copy_to_user(argp, &mtd->ecc_stats,
  				 sizeof(struct mtd_ecc_stats)))
  			return -EFAULT;
  		break;
  	}
  
  	case MTDFILEMODE:
  	{
  		mfi->mode = 0;
  
  		switch(arg) {
beb133fc1   Brian Norris   mtd: rename MTD_M...
924
925
  		case MTD_FILE_MODE_OTP_FACTORY:
  		case MTD_FILE_MODE_OTP_USER:
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
926
927
  			ret = otp_select_filemode(mfi, arg);
  			break;
beb133fc1   Brian Norris   mtd: rename MTD_M...
928
  		case MTD_FILE_MODE_RAW:
fc002e3c3   Artem Bityutskiy   mtd: introduce mt...
929
  			if (!mtd_has_oob(mtd))
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
930
931
  				return -EOPNOTSUPP;
  			mfi->mode = arg;
beb133fc1   Brian Norris   mtd: rename MTD_M...
932
  		case MTD_FILE_MODE_NORMAL:
f1a28c028   Thomas Gleixner   [MTD] NAND Expose...
933
934
935
936
937
938
939
  			break;
  		default:
  			ret = -EINVAL;
  		}
  		file->f_pos = 0;
  		break;
  	}
d0f7959e2   Roman Tereshonkov   mtd: add BLKPG AP...
940
941
  	case BLKPG:
  	{
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
942
  		ret = mtdchar_blkpg_ioctl(mtd,
d0f7959e2   Roman Tereshonkov   mtd: add BLKPG AP...
943
944
945
946
947
948
949
950
951
952
  		      (struct blkpg_ioctl_arg __user *)arg);
  		break;
  	}
  
  	case BLKRRPART:
  	{
  		/* No reread partition feature. Just return ok */
  		ret = 0;
  		break;
  	}
d0f7959e2   Roman Tereshonkov   mtd: add BLKPG AP...
953

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
955
956
957
958
959
  	default:
  		ret = -ENOTTY;
  	}
  
  	return ret;
  } /* memory_ioctl */
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
960
  static long mtdchar_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
55929332c   Arnd Bergmann   drivers: Push dow...
961
962
  {
  	int ret;
5aa82940b   Arnd Bergmann   mtd: autoconvert ...
963
  	mutex_lock(&mtd_mutex);
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
964
  	ret = mtdchar_ioctl(file, cmd, arg);
5aa82940b   Arnd Bergmann   mtd: autoconvert ...
965
  	mutex_unlock(&mtd_mutex);
55929332c   Arnd Bergmann   drivers: Push dow...
966
967
968
  
  	return ret;
  }
977185404   Kevin Cernekee   mtd: compat_ioctl...
969
970
971
972
973
974
975
976
977
978
  #ifdef CONFIG_COMPAT
  
  struct mtd_oob_buf32 {
  	u_int32_t start;
  	u_int32_t length;
  	compat_caddr_t ptr;	/* unsigned char* */
  };
  
  #define MEMWRITEOOB32		_IOWR('M', 3, struct mtd_oob_buf32)
  #define MEMREADOOB32		_IOWR('M', 4, struct mtd_oob_buf32)
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
979
  static long mtdchar_compat_ioctl(struct file *file, unsigned int cmd,
977185404   Kevin Cernekee   mtd: compat_ioctl...
980
981
982
983
  	unsigned long arg)
  {
  	struct mtd_file_info *mfi = file->private_data;
  	struct mtd_info *mtd = mfi->mtd;
0b6585ce0   David Woodhouse   mtd: Fix pointer ...
984
  	void __user *argp = compat_ptr(arg);
977185404   Kevin Cernekee   mtd: compat_ioctl...
985
  	int ret = 0;
5aa82940b   Arnd Bergmann   mtd: autoconvert ...
986
  	mutex_lock(&mtd_mutex);
977185404   Kevin Cernekee   mtd: compat_ioctl...
987
988
989
990
991
992
993
994
995
996
  
  	switch (cmd) {
  	case MEMWRITEOOB32:
  	{
  		struct mtd_oob_buf32 buf;
  		struct mtd_oob_buf32 __user *buf_user = argp;
  
  		if (copy_from_user(&buf, argp, sizeof(buf)))
  			ret = -EFAULT;
  		else
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
997
  			ret = mtdchar_writeoob(file, mtd, buf.start,
977185404   Kevin Cernekee   mtd: compat_ioctl...
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
  				buf.length, compat_ptr(buf.ptr),
  				&buf_user->length);
  		break;
  	}
  
  	case MEMREADOOB32:
  	{
  		struct mtd_oob_buf32 buf;
  		struct mtd_oob_buf32 __user *buf_user = argp;
  
  		/* NOTE: writes return length to buf->start */
  		if (copy_from_user(&buf, argp, sizeof(buf)))
  			ret = -EFAULT;
  		else
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
1012
  			ret = mtdchar_readoob(file, mtd, buf.start,
977185404   Kevin Cernekee   mtd: compat_ioctl...
1013
1014
1015
1016
1017
  				buf.length, compat_ptr(buf.ptr),
  				&buf_user->start);
  		break;
  	}
  	default:
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
1018
  		ret = mtdchar_ioctl(file, cmd, (unsigned long)argp);
977185404   Kevin Cernekee   mtd: compat_ioctl...
1019
  	}
5aa82940b   Arnd Bergmann   mtd: autoconvert ...
1020
  	mutex_unlock(&mtd_mutex);
977185404   Kevin Cernekee   mtd: compat_ioctl...
1021
1022
1023
1024
1025
  
  	return ret;
  }
  
  #endif /* CONFIG_COMPAT */
402d32651   David Howells   NOMMU: Present ba...
1026
1027
1028
1029
1030
1031
  /*
   * try to determine where a shared mapping can be made
   * - only supported for NOMMU at the moment (MMU can't doesn't copy private
   *   mappings)
   */
  #ifndef CONFIG_MMU
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
1032
  static unsigned long mtdchar_get_unmapped_area(struct file *file,
402d32651   David Howells   NOMMU: Present ba...
1033
1034
1035
1036
1037
1038
1039
  					   unsigned long addr,
  					   unsigned long len,
  					   unsigned long pgoff,
  					   unsigned long flags)
  {
  	struct mtd_file_info *mfi = file->private_data;
  	struct mtd_info *mtd = mfi->mtd;
cd621274b   Artem Bityutskiy   mtd: do not use m...
1040
1041
  	unsigned long offset;
  	int ret;
402d32651   David Howells   NOMMU: Present ba...
1042

cd621274b   Artem Bityutskiy   mtd: do not use m...
1043
1044
  	if (addr != 0)
  		return (unsigned long) -EINVAL;
402d32651   David Howells   NOMMU: Present ba...
1045

cd621274b   Artem Bityutskiy   mtd: do not use m...
1046
1047
  	if (len > mtd->size || pgoff >= (mtd->size >> PAGE_SHIFT))
  		return (unsigned long) -EINVAL;
402d32651   David Howells   NOMMU: Present ba...
1048

cd621274b   Artem Bityutskiy   mtd: do not use m...
1049
1050
1051
  	offset = pgoff << PAGE_SHIFT;
  	if (offset > mtd->size - len)
  		return (unsigned long) -EINVAL;
402d32651   David Howells   NOMMU: Present ba...
1052

cd621274b   Artem Bityutskiy   mtd: do not use m...
1053
1054
  	ret = mtd_get_unmapped_area(mtd, len, offset, flags);
  	return ret == -EOPNOTSUPP ? -ENOSYS : ret;
402d32651   David Howells   NOMMU: Present ba...
1055
1056
1057
1058
1059
1060
  }
  #endif
  
  /*
   * set up a mapping for shared memory segments
   */
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
1061
  static int mtdchar_mmap(struct file *file, struct vm_area_struct *vma)
402d32651   David Howells   NOMMU: Present ba...
1062
1063
1064
1065
  {
  #ifdef CONFIG_MMU
  	struct mtd_file_info *mfi = file->private_data;
  	struct mtd_info *mtd = mfi->mtd;
dd02b67d5   Anatolij Gustschin   mtd: mtdchar: fix...
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
  	struct map_info *map = mtd->priv;
  	unsigned long start;
  	unsigned long off;
  	u32 len;
  
  	if (mtd->type == MTD_RAM || mtd->type == MTD_ROM) {
  		off = vma->vm_pgoff << PAGE_SHIFT;
  		start = map->phys;
  		len = PAGE_ALIGN((start & ~PAGE_MASK) + map->size);
  		start &= PAGE_MASK;
  		if ((vma->vm_end - vma->vm_start + off) > len)
  			return -EINVAL;
  
  		off += start;
  		vma->vm_pgoff = off >> PAGE_SHIFT;
  		vma->vm_flags |= VM_IO | VM_RESERVED;
  
  #ifdef pgprot_noncached
  		if (file->f_flags & O_DSYNC || off >= __pa(high_memory))
  			vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
  #endif
  		if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
  				       vma->vm_end - vma->vm_start,
  				       vma->vm_page_prot))
  			return -EAGAIN;
402d32651   David Howells   NOMMU: Present ba...
1091

402d32651   David Howells   NOMMU: Present ba...
1092
  		return 0;
dd02b67d5   Anatolij Gustschin   mtd: mtdchar: fix...
1093
  	}
402d32651   David Howells   NOMMU: Present ba...
1094
1095
1096
1097
1098
  	return -ENOSYS;
  #else
  	return vma->vm_flags & VM_SHARED ? 0 : -ENOSYS;
  #endif
  }
d54b1fdb1   Arjan van de Ven   [PATCH] mark stru...
1099
  static const struct file_operations mtd_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100
  	.owner		= THIS_MODULE,
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
1101
1102
1103
1104
  	.llseek		= mtdchar_lseek,
  	.read		= mtdchar_read,
  	.write		= mtdchar_write,
  	.unlocked_ioctl	= mtdchar_unlocked_ioctl,
977185404   Kevin Cernekee   mtd: compat_ioctl...
1105
  #ifdef CONFIG_COMPAT
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
1106
  	.compat_ioctl	= mtdchar_compat_ioctl,
977185404   Kevin Cernekee   mtd: compat_ioctl...
1107
  #endif
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
1108
1109
1110
  	.open		= mtdchar_open,
  	.release	= mtdchar_close,
  	.mmap		= mtdchar_mmap,
402d32651   David Howells   NOMMU: Present ba...
1111
  #ifndef CONFIG_MMU
969e57adc   Artem Bityutskiy   mtd: mtdchar: ren...
1112
  	.get_unmapped_area = mtdchar_get_unmapped_area,
402d32651   David Howells   NOMMU: Present ba...
1113
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114
  };
51139adac   Al Viro   convert get_sb_ps...
1115
1116
  static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type,
  				int flags, const char *dev_name, void *data)
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
1117
  {
c74a1cbb3   Al Viro   pass default dent...
1118
  	return mount_pseudo(fs_type, "mtd_inode:", NULL, NULL, MTD_INODE_FS_MAGIC);
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
1119
1120
1121
1122
  }
  
  static struct file_system_type mtd_inodefs_type = {
         .name = "mtd_inodefs",
51139adac   Al Viro   convert get_sb_ps...
1123
         .mount = mtd_inodefs_mount,
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
         .kill_sb = kill_anon_super,
  };
  
  static void mtdchar_notify_add(struct mtd_info *mtd)
  {
  }
  
  static void mtdchar_notify_remove(struct mtd_info *mtd)
  {
  	struct inode *mtd_ino = ilookup(mtd_inode_mnt->mnt_sb, mtd->index);
  
  	if (mtd_ino) {
  		/* Destroy the inode if it exists */
6d6b77f16   Miklos Szeredi   filesystems: add ...
1137
  		clear_nlink(mtd_ino);
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
1138
1139
1140
1141
1142
1143
1144
1145
  		iput(mtd_ino);
  	}
  }
  
  static struct mtd_notifier mtdchar_notifier = {
  	.add = mtdchar_notify_add,
  	.remove = mtdchar_notify_remove,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146
1147
  static int __init init_mtdchar(void)
  {
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
1148
  	int ret;
1f24b5a8e   David Brownell   [MTD] driver mode...
1149

cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
1150
  	ret = __register_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS,
dad0db318   Ben Hutchings   mtdchar: Register...
1151
  				   "mtd", &mtd_fops);
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
1152
1153
1154
1155
1156
  	if (ret < 0) {
  		pr_notice("Can't allocate major number %d for "
  				"Memory Technology Devices.
  ", MTD_CHAR_MAJOR);
  		return ret;
9bc7b3873   Todd Poynor   [MTD] mtdchar.c: ...
1157
  	}
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
  	ret = register_filesystem(&mtd_inodefs_type);
  	if (ret) {
  		pr_notice("Can't register mtd_inodefs filesystem: %d
  ", ret);
  		goto err_unregister_chdev;
  	}
  
  	mtd_inode_mnt = kern_mount(&mtd_inodefs_type);
  	if (IS_ERR(mtd_inode_mnt)) {
  		ret = PTR_ERR(mtd_inode_mnt);
  		pr_notice("Error mounting mtd_inodefs filesystem: %d
  ", ret);
  		goto err_unregister_filesystem;
  	}
  	register_mtd_user(&mtdchar_notifier);
  
  	return ret;
  
  err_unregister_filesystem:
  	unregister_filesystem(&mtd_inodefs_type);
  err_unregister_chdev:
  	__unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd");
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
1182
1183
1184
  }
  
  static void __exit cleanup_mtdchar(void)
  {
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
1185
  	unregister_mtd_user(&mtdchar_notifier);
423e0ab08   Tim Chen   VFS : mount lock ...
1186
  	kern_unmount(mtd_inode_mnt);
cd874237d   Kirill A. Shutemov   mtd: mtdchar: Do ...
1187
  	unregister_filesystem(&mtd_inodefs_type);
dad0db318   Ben Hutchings   mtdchar: Register...
1188
  	__unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189
1190
1191
1192
  }
  
  module_init(init_mtdchar);
  module_exit(cleanup_mtdchar);
1f24b5a8e   David Brownell   [MTD] driver mode...
1193
  MODULE_ALIAS_CHARDEV_MAJOR(MTD_CHAR_MAJOR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
1195
1196
1197
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
  MODULE_DESCRIPTION("Direct character-device access to MTD devices");
90160e13b   Scott James Remnant   [MTD] Auto-load m...
1198
  MODULE_ALIAS_CHARDEV_MAJOR(MTD_CHAR_MAJOR);