aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/ps3flash.c
diff options
context:
space:
mode:
authorGeert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>2009-06-10 00:39:06 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-06-15 02:47:26 -0400
commita4e623fbc9b201930abcf78df6db5e49aa8e00cb (patch)
tree60017689df8260806cba7c007f9f9d85e3758b31 /drivers/char/ps3flash.c
parent47cb996b059e0e5696b8daa1f62881a6462a251a (diff)
ps3: Replace direct file operations by callback
Currently the FLASH database is updated by the kernel using file operations, meant for userspace only. While this works for us because copy_{from,to}_user() on powerpc can handle kernel pointers, this is unportable and a bad example. Replace the file operations by callbacks, registered by the ps3flash driver. Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com> Cc: Geoff Levand <geoffrey.levand@am.sony.com> Acked-by: Geoff Levand <geoffrey.levand@am.sony.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'drivers/char/ps3flash.c')
-rw-r--r--drivers/char/ps3flash.c94
1 files changed, 70 insertions, 24 deletions
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c
index 184e6ed2393d..f7f21f47ea02 100644
--- a/drivers/char/ps3flash.c
+++ b/drivers/char/ps3flash.c
@@ -104,18 +104,19 @@ out:
104 return res; 104 return res;
105} 105}
106 106
107static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, 107static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
108 loff_t *pos) 108 size_t count, loff_t *pos)
109{ 109{
110 struct ps3_storage_device *dev = ps3flash_dev; 110 struct ps3_storage_device *dev = ps3flash_dev;
111 struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); 111 struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
112 u64 size, start_sector, end_sector, offset; 112 u64 size, start_sector, end_sector, offset;
113 ssize_t sectors_read; 113 ssize_t sectors_read;
114 size_t remaining, n; 114 size_t remaining, n;
115 const void *src;
115 116
116 dev_dbg(&dev->sbd.core, 117 dev_dbg(&dev->sbd.core,
117 "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n", 118 "%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n",
118 __func__, __LINE__, count, *pos, buf); 119 __func__, __LINE__, count, *pos, userbuf, kernelbuf);
119 120
120 size = dev->regions[dev->region_idx].size*dev->blk_size; 121 size = dev->regions[dev->region_idx].size*dev->blk_size;
121 if (*pos >= size || !count) 122 if (*pos >= size || !count)
@@ -145,19 +146,26 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
145 } 146 }
146 147
147 n = min_t(u64, remaining, sectors_read*dev->blk_size-offset); 148 n = min_t(u64, remaining, sectors_read*dev->blk_size-offset);
149 src = dev->bounce_buf+offset;
148 dev_dbg(&dev->sbd.core, 150 dev_dbg(&dev->sbd.core,
149 "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n", 151 "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n",
150 __func__, __LINE__, n, dev->bounce_buf+offset, buf); 152 __func__, __LINE__, n, src, userbuf, kernelbuf);
151 if (copy_to_user(buf, dev->bounce_buf+offset, n)) { 153 if (userbuf) {
152 mutex_unlock(&priv->mutex); 154 if (copy_to_user(userbuf, src, n)) {
153 sectors_read = -EFAULT; 155 mutex_unlock(&priv->mutex);
154 goto fail; 156 sectors_read = -EFAULT;
157 goto fail;
158 }
159 userbuf += n;
160 }
161 if (kernelbuf) {
162 memcpy(kernelbuf, src, n);
163 kernelbuf += n;
155 } 164 }
156 165
157 mutex_unlock(&priv->mutex); 166 mutex_unlock(&priv->mutex);
158 167
159 *pos += n; 168 *pos += n;
160 buf += n;
161 remaining -= n; 169 remaining -= n;
162 start_sector += sectors_read; 170 start_sector += sectors_read;
163 offset = 0; 171 offset = 0;
@@ -169,8 +177,8 @@ fail:
169 return sectors_read; 177 return sectors_read;
170} 178}
171 179
172static ssize_t ps3flash_write(struct file *file, const char __user *buf, 180static ssize_t ps3flash_write(const char __user *userbuf,
173 size_t count, loff_t *pos) 181 const void *kernelbuf, size_t count, loff_t *pos)
174{ 182{
175 struct ps3_storage_device *dev = ps3flash_dev; 183 struct ps3_storage_device *dev = ps3flash_dev;
176 struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); 184 struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
@@ -179,10 +187,11 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf,
179 ssize_t res; 187 ssize_t res;
180 size_t remaining, n; 188 size_t remaining, n;
181 unsigned int sec_off; 189 unsigned int sec_off;
190 void *dst;
182 191
183 dev_dbg(&dev->sbd.core, 192 dev_dbg(&dev->sbd.core,
184 "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n", 193 "%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n",
185 __func__, __LINE__, count, *pos, buf); 194 __func__, __LINE__, count, *pos, userbuf, kernelbuf);
186 195
187 size = dev->regions[dev->region_idx].size*dev->blk_size; 196 size = dev->regions[dev->region_idx].size*dev->blk_size;
188 if (*pos >= size || !count) 197 if (*pos >= size || !count)
@@ -259,12 +268,20 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf,
259 } 268 }
260 269
261 n = min_t(u64, remaining, dev->bounce_size-offset); 270 n = min_t(u64, remaining, dev->bounce_size-offset);
271 dst = dev->bounce_buf+offset;
262 dev_dbg(&dev->sbd.core, 272 dev_dbg(&dev->sbd.core,
263 "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n", 273 "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n",
264 __func__, __LINE__, n, buf, dev->bounce_buf+offset); 274 __func__, __LINE__, n, userbuf, kernelbuf, dst);
265 if (copy_from_user(dev->bounce_buf+offset, buf, n)) { 275 if (userbuf) {
266 res = -EFAULT; 276 if (copy_from_user(dst, userbuf, n)) {
267 goto fail; 277 res = -EFAULT;
278 goto fail;
279 }
280 userbuf += n;
281 }
282 if (kernelbuf) {
283 memcpy(dst, kernelbuf, n);
284 kernelbuf += n;
268 } 285 }
269 286
270 res = ps3flash_write_chunk(dev, start_write_sector); 287 res = ps3flash_write_chunk(dev, start_write_sector);
@@ -274,7 +291,6 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf,
274 mutex_unlock(&priv->mutex); 291 mutex_unlock(&priv->mutex);
275 292
276 *pos += n; 293 *pos += n;
277 buf += n;
278 remaining -= n; 294 remaining -= n;
279 start_write_sector += chunk_sectors; 295 start_write_sector += chunk_sectors;
280 head = 0; 296 head = 0;
@@ -288,6 +304,29 @@ fail:
288 return res; 304 return res;
289} 305}
290 306
307static ssize_t ps3flash_user_read(struct file *file, char __user *buf,
308 size_t count, loff_t *pos)
309{
310 return ps3flash_read(buf, NULL, count, pos);
311}
312
313static ssize_t ps3flash_user_write(struct file *file, const char __user *buf,
314 size_t count, loff_t *pos)
315{
316 return ps3flash_write(buf, NULL, count, pos);
317}
318
319static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos)
320{
321 return ps3flash_read(NULL, buf, count, &pos);
322}
323
324static ssize_t ps3flash_kernel_write(const void *buf, size_t count,
325 loff_t pos)
326{
327 return ps3flash_write(NULL, buf, count, &pos);
328}
329
291 330
292static irqreturn_t ps3flash_interrupt(int irq, void *data) 331static irqreturn_t ps3flash_interrupt(int irq, void *data)
293{ 332{
@@ -312,12 +351,16 @@ static irqreturn_t ps3flash_interrupt(int irq, void *data)
312 return IRQ_HANDLED; 351 return IRQ_HANDLED;
313} 352}
314 353
315
316static const struct file_operations ps3flash_fops = { 354static const struct file_operations ps3flash_fops = {
317 .owner = THIS_MODULE, 355 .owner = THIS_MODULE,
318 .llseek = ps3flash_llseek, 356 .llseek = ps3flash_llseek,
319 .read = ps3flash_read, 357 .read = ps3flash_user_read,
320 .write = ps3flash_write, 358 .write = ps3flash_user_write,
359};
360
361static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = {
362 .read = ps3flash_kernel_read,
363 .write = ps3flash_kernel_write,
321}; 364};
322 365
323static struct miscdevice ps3flash_misc = { 366static struct miscdevice ps3flash_misc = {
@@ -386,6 +429,8 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
386 429
387 dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n", 430 dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
388 __func__, __LINE__, ps3flash_misc.minor); 431 __func__, __LINE__, ps3flash_misc.minor);
432
433 ps3_os_area_flash_register(&ps3flash_kernel_ops);
389 return 0; 434 return 0;
390 435
391fail_teardown: 436fail_teardown:
@@ -402,6 +447,7 @@ static int ps3flash_remove(struct ps3_system_bus_device *_dev)
402{ 447{
403 struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); 448 struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
404 449
450 ps3_os_area_flash_register(NULL);
405 misc_deregister(&ps3flash_misc); 451 misc_deregister(&ps3flash_misc);
406 ps3stor_teardown(dev); 452 ps3stor_teardown(dev);
407 kfree(ps3_system_bus_get_drvdata(&dev->sbd)); 453 kfree(ps3_system_bus_get_drvdata(&dev->sbd));