Blame view

drivers/char/ps3flash.c 11 KB
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  /*
   * PS3 FLASH ROM Storage Driver
   *
   * Copyright (C) 2007 Sony Computer Entertainment Inc.
   * Copyright 2007 Sony Corp.
   *
   * 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; version 2 of the License.
   *
   * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
   */
  
  #include <linux/fs.h>
  #include <linux/miscdevice.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
23
  #include <linux/slab.h>
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
24
  #include <linux/uaccess.h>
c22405c98   Paul Gortmaker   drivers/char: Add...
25
  #include <linux/module.h>
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
26
27
28
29
30
31
32
33
34
35
36
37
  
  #include <asm/lv1call.h>
  #include <asm/ps3stor.h>
  
  
  #define DEVICE_NAME		"ps3flash"
  
  #define FLASH_BLOCK_SIZE	(256*1024)
  
  
  struct ps3flash_private {
  	struct mutex mutex;	/* Bounce buffer mutex */
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
38
39
40
  	u64 chunk_sectors;
  	int tag;		/* Start sector of buffer, -1 if invalid */
  	bool dirty;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
41
42
43
  };
  
  static struct ps3_storage_device *ps3flash_dev;
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
44
  static int ps3flash_read_write_sectors(struct ps3_storage_device *dev,
42e27bfc4   Geert Uytterhoeven   ps3flash: Always ...
45
  				       u64 start_sector, int write)
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
46
  {
42e27bfc4   Geert Uytterhoeven   ps3flash: Always ...
47
48
49
  	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
  	u64 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar,
  					     start_sector, priv->chunk_sectors,
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
50
51
  					     write);
  	if (res) {
4c33d2dc3   Stephen Rothwell   powerpc/ps3: Prin...
52
53
  		dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx
  ", __func__,
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
54
55
56
  			__LINE__, write ? "write" : "read", res);
  		return -EIO;
  	}
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
57
  	return 0;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
58
  }
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
59
  static int ps3flash_writeback(struct ps3_storage_device *dev)
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
60
  {
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
61
62
  	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
  	int res;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
63

6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
64
65
  	if (!priv->dirty || priv->tag < 0)
  		return 0;
42e27bfc4   Geert Uytterhoeven   ps3flash: Always ...
66
  	res = ps3flash_read_write_sectors(dev, priv->tag, 1);
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
67
68
  	if (res)
  		return res;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
69

6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
70
71
  	priv->dirty = false;
  	return 0;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
72
  }
42e27bfc4   Geert Uytterhoeven   ps3flash: Always ...
73
  static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector)
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
74
  {
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
75
  	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
76
  	int res;
42e27bfc4   Geert Uytterhoeven   ps3flash: Always ...
77
  	if (start_sector == priv->tag)
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
78
79
80
81
82
83
84
  		return 0;
  
  	res = ps3flash_writeback(dev);
  	if (res)
  		return res;
  
  	priv->tag = -1;
42e27bfc4   Geert Uytterhoeven   ps3flash: Always ...
85
  	res = ps3flash_read_write_sectors(dev, start_sector, 0);
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
86
87
  	if (res)
  		return res;
42e27bfc4   Geert Uytterhoeven   ps3flash: Always ...
88
  	priv->tag = start_sector;
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
89
  	return 0;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
90
91
92
93
94
95
96
97
98
  }
  
  static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
  {
  	struct ps3_storage_device *dev = ps3flash_dev;
  	loff_t res;
  
  	mutex_lock(&file->f_mapping->host->i_mutex);
  	switch (origin) {
22735068d   Josef Bacik   drivers: fix up v...
99
100
  	case 0:
  		break;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
101
102
103
104
105
106
  	case 1:
  		offset += file->f_pos;
  		break;
  	case 2:
  		offset += dev->regions[dev->region_idx].size*dev->blk_size;
  		break;
22735068d   Josef Bacik   drivers: fix up v...
107
108
  	default:
  		offset = -1;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
109
110
111
112
113
114
115
116
117
118
119
120
121
  	}
  	if (offset < 0) {
  		res = -EINVAL;
  		goto out;
  	}
  
  	file->f_pos = offset;
  	res = file->f_pos;
  
  out:
  	mutex_unlock(&file->f_mapping->host->i_mutex);
  	return res;
  }
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
122
123
  static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
  			     size_t count, loff_t *pos)
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
124
125
  {
  	struct ps3_storage_device *dev = ps3flash_dev;
559dc87f5   Geert Uytterhoeven   ps3flash: Use ps3...
126
  	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
42e27bfc4   Geert Uytterhoeven   ps3flash: Always ...
127
  	u64 size, sector, offset;
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
128
  	int res;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
129
  	size_t remaining, n;
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
130
  	const void *src;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
131
132
  
  	dev_dbg(&dev->sbd.core,
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
133
134
135
  		"%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p
  ",
  		__func__, __LINE__, count, *pos, userbuf, kernelbuf);
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
136
137
138
139
140
141
142
143
144
145
146
147
  
  	size = dev->regions[dev->region_idx].size*dev->blk_size;
  	if (*pos >= size || !count)
  		return 0;
  
  	if (*pos + count > size) {
  		dev_dbg(&dev->sbd.core,
  			"%s:%u Truncating count from %zu to %llu
  ", __func__,
  			__LINE__, count, size - *pos);
  		count = size - *pos;
  	}
42e27bfc4   Geert Uytterhoeven   ps3flash: Always ...
148
  	sector = *pos / dev->bounce_size * priv->chunk_sectors;
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
149
  	offset = *pos % dev->bounce_size;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
150
151
152
  
  	remaining = count;
  	do {
42e27bfc4   Geert Uytterhoeven   ps3flash: Always ...
153
154
  		n = min_t(u64, remaining, dev->bounce_size - offset);
  		src = dev->bounce_buf + offset;
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
155

f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
156
  		mutex_lock(&priv->mutex);
42e27bfc4   Geert Uytterhoeven   ps3flash: Always ...
157
  		res = ps3flash_fetch(dev, sector);
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
158
  		if (res)
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
159
  			goto fail;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
160

f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
161
  		dev_dbg(&dev->sbd.core,
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
162
163
164
165
166
  			"%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p
  ",
  			__func__, __LINE__, n, src, userbuf, kernelbuf);
  		if (userbuf) {
  			if (copy_to_user(userbuf, src, n)) {
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
167
  				res = -EFAULT;
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
168
169
170
171
172
173
174
  				goto fail;
  			}
  			userbuf += n;
  		}
  		if (kernelbuf) {
  			memcpy(kernelbuf, src, n);
  			kernelbuf += n;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
175
176
177
178
179
  		}
  
  		mutex_unlock(&priv->mutex);
  
  		*pos += n;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
180
  		remaining -= n;
42e27bfc4   Geert Uytterhoeven   ps3flash: Always ...
181
  		sector += priv->chunk_sectors;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
182
183
184
185
186
187
  		offset = 0;
  	} while (remaining > 0);
  
  	return count;
  
  fail:
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
188
189
  	mutex_unlock(&priv->mutex);
  	return res;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
190
  }
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
191
192
  static ssize_t ps3flash_write(const char __user *userbuf,
  			      const void *kernelbuf, size_t count, loff_t *pos)
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
193
194
  {
  	struct ps3_storage_device *dev = ps3flash_dev;
559dc87f5   Geert Uytterhoeven   ps3flash: Use ps3...
195
  	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
196
197
  	u64 size, sector, offset;
  	int res = 0;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
198
  	size_t remaining, n;
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
199
  	void *dst;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
200
201
  
  	dev_dbg(&dev->sbd.core,
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
202
203
204
  		"%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p
  ",
  		__func__, __LINE__, count, *pos, userbuf, kernelbuf);
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
205
206
207
208
209
210
211
212
213
214
215
216
  
  	size = dev->regions[dev->region_idx].size*dev->blk_size;
  	if (*pos >= size || !count)
  		return 0;
  
  	if (*pos + count > size) {
  		dev_dbg(&dev->sbd.core,
  			"%s:%u Truncating count from %zu to %llu
  ", __func__,
  			__LINE__, count, size - *pos);
  		count = size - *pos;
  	}
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
217
  	sector = *pos / dev->bounce_size * priv->chunk_sectors;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
218
  	offset = *pos % dev->bounce_size;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
219
220
221
  
  	remaining = count;
  	do {
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
222
  		n = min_t(u64, remaining, dev->bounce_size - offset);
42e27bfc4   Geert Uytterhoeven   ps3flash: Always ...
223
  		dst = dev->bounce_buf + offset;
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
224

f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
225
  		mutex_lock(&priv->mutex);
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
226
  		if (n != dev->bounce_size)
42e27bfc4   Geert Uytterhoeven   ps3flash: Always ...
227
  			res = ps3flash_fetch(dev, sector);
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
228
229
230
231
  		else if (sector != priv->tag)
  			res = ps3flash_writeback(dev);
  		if (res)
  			goto fail;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
232

f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
233
  		dev_dbg(&dev->sbd.core,
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
234
235
236
237
238
239
240
241
242
243
244
245
246
  			"%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p
  ",
  			__func__, __LINE__, n, userbuf, kernelbuf, dst);
  		if (userbuf) {
  			if (copy_from_user(dst, userbuf, n)) {
  				res = -EFAULT;
  				goto fail;
  			}
  			userbuf += n;
  		}
  		if (kernelbuf) {
  			memcpy(dst, kernelbuf, n);
  			kernelbuf += n;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
247
  		}
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
248
249
  		priv->tag = sector;
  		priv->dirty = true;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
250
251
252
253
  
  		mutex_unlock(&priv->mutex);
  
  		*pos += n;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
254
  		remaining -= n;
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
255
  		sector += priv->chunk_sectors;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
256
257
258
259
260
261
262
263
264
  		offset = 0;
  	} while (remaining > 0);
  
  	return count;
  
  fail:
  	mutex_unlock(&priv->mutex);
  	return res;
  }
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  static ssize_t ps3flash_user_read(struct file *file, char __user *buf,
  				  size_t count, loff_t *pos)
  {
  	return ps3flash_read(buf, NULL, count, pos);
  }
  
  static ssize_t ps3flash_user_write(struct file *file, const char __user *buf,
  				   size_t count, loff_t *pos)
  {
  	return ps3flash_write(buf, NULL, count, pos);
  }
  
  static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos)
  {
  	return ps3flash_read(NULL, buf, count, &pos);
  }
  
  static ssize_t ps3flash_kernel_write(const void *buf, size_t count,
  				     loff_t pos)
  {
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
285
286
287
288
289
290
291
292
293
294
295
296
297
  	ssize_t res;
  	int wb;
  
  	res = ps3flash_write(NULL, buf, count, &pos);
  	if (res < 0)
  		return res;
  
  	/* Make kernel writes synchronous */
  	wb = ps3flash_writeback(ps3flash_dev);
  	if (wb)
  		return wb;
  
  	return res;
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
298
  }
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
299
300
301
302
  static int ps3flash_flush(struct file *file, fl_owner_t id)
  {
  	return ps3flash_writeback(ps3flash_dev);
  }
02c24a821   Josef Bacik   fs: push i_mutex ...
303
  static int ps3flash_fsync(struct file *file, loff_t start, loff_t end, int datasync)
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
304
  {
02c24a821   Josef Bacik   fs: push i_mutex ...
305
306
307
308
309
310
  	struct inode *inode = file->f_path.dentry->d_inode;
  	int err;
  	mutex_lock(&inode->i_mutex);
  	err = ps3flash_writeback(ps3flash_dev);
  	mutex_unlock(&inode->i_mutex);
  	return err;
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
311
  }
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
312
313
314
315
316
317
318
319
320
321
322
  
  static irqreturn_t ps3flash_interrupt(int irq, void *data)
  {
  	struct ps3_storage_device *dev = data;
  	int res;
  	u64 tag, status;
  
  	res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
  
  	if (tag != dev->tag)
  		dev_err(&dev->sbd.core,
4c33d2dc3   Stephen Rothwell   powerpc/ps3: Prin...
323
324
  			"%s:%u: tag mismatch, got %llx, expected %llx
  ",
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
325
326
327
  			__func__, __LINE__, tag, dev->tag);
  
  	if (res) {
4c33d2dc3   Stephen Rothwell   powerpc/ps3: Prin...
328
329
  		dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx
  ",
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
330
331
332
333
334
335
336
  			__func__, __LINE__, res, status);
  	} else {
  		dev->lv1_status = status;
  		complete(&dev->done);
  	}
  	return IRQ_HANDLED;
  }
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
337
338
339
  static const struct file_operations ps3flash_fops = {
  	.owner	= THIS_MODULE,
  	.llseek	= ps3flash_llseek,
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
340
341
  	.read	= ps3flash_user_read,
  	.write	= ps3flash_user_write,
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
342
343
  	.flush	= ps3flash_flush,
  	.fsync	= ps3flash_fsync,
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
344
345
346
347
348
  };
  
  static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = {
  	.read	= ps3flash_kernel_read,
  	.write	= ps3flash_kernel_write,
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
  };
  
  static struct miscdevice ps3flash_misc = {
  	.minor	= MISC_DYNAMIC_MINOR,
  	.name	= DEVICE_NAME,
  	.fops	= &ps3flash_fops,
  };
  
  static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
  {
  	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
  	struct ps3flash_private *priv;
  	int error;
  	unsigned long tmp;
  
  	tmp = dev->regions[dev->region_idx].start*dev->blk_size;
  	if (tmp % FLASH_BLOCK_SIZE) {
  		dev_err(&dev->sbd.core,
  			"%s:%u region start %lu is not aligned
  ", __func__,
  			__LINE__, tmp);
  		return -EINVAL;
  	}
  	tmp = dev->regions[dev->region_idx].size*dev->blk_size;
  	if (tmp % FLASH_BLOCK_SIZE) {
  		dev_err(&dev->sbd.core,
  			"%s:%u region size %lu is not aligned
  ", __func__,
  			__LINE__, tmp);
  		return -EINVAL;
  	}
  
  	/* use static buffer, kmalloc cannot allocate 256 KiB */
  	if (!ps3flash_bounce_buffer.address)
  		return -ENODEV;
  
  	if (ps3flash_dev) {
  		dev_err(&dev->sbd.core,
  			"Only one FLASH device is supported
  ");
  		return -EBUSY;
  	}
  
  	ps3flash_dev = dev;
  
  	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  	if (!priv) {
  		error = -ENOMEM;
  		goto fail;
  	}
559dc87f5   Geert Uytterhoeven   ps3flash: Use ps3...
399
  	ps3_system_bus_set_drvdata(&dev->sbd, priv);
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
400
  	mutex_init(&priv->mutex);
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
401
  	priv->tag = -1;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
402
403
404
  
  	dev->bounce_size = ps3flash_bounce_buffer.size;
  	dev->bounce_buf = ps3flash_bounce_buffer.address;
6bd57f2e5   Geert Uytterhoeven   ps3flash: Cache t...
405
  	priv->chunk_sectors = dev->bounce_size / dev->blk_size;
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
  
  	error = ps3stor_setup(dev, ps3flash_interrupt);
  	if (error)
  		goto fail_free_priv;
  
  	ps3flash_misc.parent = &dev->sbd.core;
  	error = misc_register(&ps3flash_misc);
  	if (error) {
  		dev_err(&dev->sbd.core, "%s:%u: misc_register failed %d
  ",
  			__func__, __LINE__, error);
  		goto fail_teardown;
  	}
  
  	dev_info(&dev->sbd.core, "%s:%u: registered misc device %d
  ",
  		 __func__, __LINE__, ps3flash_misc.minor);
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
423
424
  
  	ps3_os_area_flash_register(&ps3flash_kernel_ops);
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
425
426
427
428
429
430
  	return 0;
  
  fail_teardown:
  	ps3stor_teardown(dev);
  fail_free_priv:
  	kfree(priv);
559dc87f5   Geert Uytterhoeven   ps3flash: Use ps3...
431
  	ps3_system_bus_set_drvdata(&dev->sbd, NULL);
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
432
433
434
435
436
437
438
439
  fail:
  	ps3flash_dev = NULL;
  	return error;
  }
  
  static int ps3flash_remove(struct ps3_system_bus_device *_dev)
  {
  	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
a4e623fbc   Geert Uytterhoeven   ps3: Replace dire...
440
  	ps3_os_area_flash_register(NULL);
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
441
442
  	misc_deregister(&ps3flash_misc);
  	ps3stor_teardown(dev);
559dc87f5   Geert Uytterhoeven   ps3flash: Use ps3...
443
444
  	kfree(ps3_system_bus_get_drvdata(&dev->sbd));
  	ps3_system_bus_set_drvdata(&dev->sbd, NULL);
f96526354   Geert Uytterhoeven   ps3: FLASH ROM St...
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
  	ps3flash_dev = NULL;
  	return 0;
  }
  
  
  static struct ps3_system_bus_driver ps3flash = {
  	.match_id	= PS3_MATCH_ID_STOR_FLASH,
  	.core.name	= DEVICE_NAME,
  	.core.owner	= THIS_MODULE,
  	.probe		= ps3flash_probe,
  	.remove		= ps3flash_remove,
  	.shutdown	= ps3flash_remove,
  };
  
  
  static int __init ps3flash_init(void)
  {
  	return ps3_system_bus_driver_register(&ps3flash);
  }
  
  static void __exit ps3flash_exit(void)
  {
  	ps3_system_bus_driver_unregister(&ps3flash);
  }
  
  module_init(ps3flash_init);
  module_exit(ps3flash_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("PS3 FLASH ROM Storage Driver");
  MODULE_AUTHOR("Sony Corporation");
  MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH);