diff options
Diffstat (limited to 'drivers/char')
| -rw-r--r-- | drivers/char/ps3flash.c | 296 |
1 files changed, 164 insertions, 132 deletions
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c index afbe45676d71..f424d394a286 100644 --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c | |||
| @@ -33,48 +33,64 @@ | |||
| 33 | 33 | ||
| 34 | struct ps3flash_private { | 34 | struct ps3flash_private { |
| 35 | struct mutex mutex; /* Bounce buffer mutex */ | 35 | struct mutex mutex; /* Bounce buffer mutex */ |
| 36 | u64 chunk_sectors; | ||
| 37 | int tag; /* Start sector of buffer, -1 if invalid */ | ||
| 38 | bool dirty; | ||
| 36 | }; | 39 | }; |
| 37 | 40 | ||
| 38 | static struct ps3_storage_device *ps3flash_dev; | 41 | static struct ps3_storage_device *ps3flash_dev; |
| 39 | 42 | ||
| 40 | static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev, | 43 | static int ps3flash_read_write_sectors(struct ps3_storage_device *dev, |
| 41 | u64 lpar, u64 start_sector, | 44 | u64 start_sector, int write) |
| 42 | u64 sectors, int write) | ||
| 43 | { | 45 | { |
| 44 | u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors, | 46 | struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
| 47 | u64 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar, | ||
| 48 | start_sector, priv->chunk_sectors, | ||
| 45 | write); | 49 | write); |
| 46 | if (res) { | 50 | if (res) { |
| 47 | dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__, | 51 | dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__, |
| 48 | __LINE__, write ? "write" : "read", res); | 52 | __LINE__, write ? "write" : "read", res); |
| 49 | return -EIO; | 53 | return -EIO; |
| 50 | } | 54 | } |
| 51 | return sectors; | 55 | return 0; |
| 52 | } | 56 | } |
| 53 | 57 | ||
| 54 | static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev, | 58 | static int ps3flash_writeback(struct ps3_storage_device *dev) |
| 55 | u64 start_sector, u64 sectors, | ||
| 56 | unsigned int sector_offset) | ||
| 57 | { | 59 | { |
| 58 | u64 max_sectors, lpar; | 60 | struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
| 61 | int res; | ||
| 59 | 62 | ||
| 60 | max_sectors = dev->bounce_size / dev->blk_size; | 63 | if (!priv->dirty || priv->tag < 0) |
| 61 | if (sectors > max_sectors) { | 64 | return 0; |
| 62 | dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %llu\n", | ||
| 63 | __func__, __LINE__, max_sectors); | ||
| 64 | sectors = max_sectors; | ||
| 65 | } | ||
| 66 | 65 | ||
| 67 | lpar = dev->bounce_lpar + sector_offset * dev->blk_size; | 66 | res = ps3flash_read_write_sectors(dev, priv->tag, 1); |
| 68 | return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors, | 67 | if (res) |
| 69 | 0); | 68 | return res; |
| 69 | |||
| 70 | priv->dirty = false; | ||
| 71 | return 0; | ||
| 70 | } | 72 | } |
| 71 | 73 | ||
| 72 | static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev, | 74 | static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector) |
| 73 | u64 start_sector) | ||
| 74 | { | 75 | { |
| 75 | u64 sectors = dev->bounce_size / dev->blk_size; | 76 | struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
| 76 | return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector, | 77 | int res; |
| 77 | sectors, 1); | 78 | |
| 79 | if (start_sector == priv->tag) | ||
| 80 | return 0; | ||
| 81 | |||
| 82 | res = ps3flash_writeback(dev); | ||
| 83 | if (res) | ||
| 84 | return res; | ||
| 85 | |||
| 86 | priv->tag = -1; | ||
| 87 | |||
| 88 | res = ps3flash_read_write_sectors(dev, start_sector, 0); | ||
| 89 | if (res) | ||
| 90 | return res; | ||
| 91 | |||
| 92 | priv->tag = start_sector; | ||
| 93 | return 0; | ||
| 78 | } | 94 | } |
| 79 | 95 | ||
| 80 | static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin) | 96 | static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin) |
| @@ -104,18 +120,19 @@ out: | |||
| 104 | return res; | 120 | return res; |
| 105 | } | 121 | } |
| 106 | 122 | ||
| 107 | static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, | 123 | static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, |
| 108 | loff_t *pos) | 124 | size_t count, loff_t *pos) |
| 109 | { | 125 | { |
| 110 | struct ps3_storage_device *dev = ps3flash_dev; | 126 | struct ps3_storage_device *dev = ps3flash_dev; |
| 111 | struct ps3flash_private *priv = dev->sbd.core.driver_data; | 127 | struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
| 112 | u64 size, start_sector, end_sector, offset; | 128 | u64 size, sector, offset; |
| 113 | ssize_t sectors_read; | 129 | int res; |
| 114 | size_t remaining, n; | 130 | size_t remaining, n; |
| 131 | const void *src; | ||
| 115 | 132 | ||
| 116 | dev_dbg(&dev->sbd.core, | 133 | dev_dbg(&dev->sbd.core, |
| 117 | "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n", | 134 | "%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n", |
| 118 | __func__, __LINE__, count, *pos, buf); | 135 | __func__, __LINE__, count, *pos, userbuf, kernelbuf); |
| 119 | 136 | ||
| 120 | size = dev->regions[dev->region_idx].size*dev->blk_size; | 137 | size = dev->regions[dev->region_idx].size*dev->blk_size; |
| 121 | if (*pos >= size || !count) | 138 | if (*pos >= size || !count) |
| @@ -128,61 +145,63 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, | |||
| 128 | count = size - *pos; | 145 | count = size - *pos; |
| 129 | } | 146 | } |
| 130 | 147 | ||
| 131 | start_sector = *pos / dev->blk_size; | 148 | sector = *pos / dev->bounce_size * priv->chunk_sectors; |
| 132 | offset = *pos % dev->blk_size; | 149 | offset = *pos % dev->bounce_size; |
| 133 | end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size); | ||
| 134 | 150 | ||
| 135 | remaining = count; | 151 | remaining = count; |
| 136 | do { | 152 | do { |
| 153 | n = min_t(u64, remaining, dev->bounce_size - offset); | ||
| 154 | src = dev->bounce_buf + offset; | ||
| 155 | |||
| 137 | mutex_lock(&priv->mutex); | 156 | mutex_lock(&priv->mutex); |
| 138 | 157 | ||
| 139 | sectors_read = ps3flash_read_sectors(dev, start_sector, | 158 | res = ps3flash_fetch(dev, sector); |
| 140 | end_sector-start_sector, | 159 | if (res) |
| 141 | 0); | ||
| 142 | if (sectors_read < 0) { | ||
| 143 | mutex_unlock(&priv->mutex); | ||
| 144 | goto fail; | 160 | goto fail; |
| 145 | } | ||
| 146 | 161 | ||
| 147 | n = min_t(u64, remaining, sectors_read*dev->blk_size-offset); | ||
| 148 | dev_dbg(&dev->sbd.core, | 162 | dev_dbg(&dev->sbd.core, |
| 149 | "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n", | 163 | "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n", |
| 150 | __func__, __LINE__, n, dev->bounce_buf+offset, buf); | 164 | __func__, __LINE__, n, src, userbuf, kernelbuf); |
| 151 | if (copy_to_user(buf, dev->bounce_buf+offset, n)) { | 165 | if (userbuf) { |
| 152 | mutex_unlock(&priv->mutex); | 166 | if (copy_to_user(userbuf, src, n)) { |
| 153 | sectors_read = -EFAULT; | 167 | res = -EFAULT; |
| 154 | goto fail; | 168 | goto fail; |
| 169 | } | ||
| 170 | userbuf += n; | ||
| 171 | } | ||
| 172 | if (kernelbuf) { | ||
| 173 | memcpy(kernelbuf, src, n); | ||
| 174 | kernelbuf += n; | ||
| 155 | } | 175 | } |
| 156 | 176 | ||
| 157 | mutex_unlock(&priv->mutex); | 177 | mutex_unlock(&priv->mutex); |
| 158 | 178 | ||
| 159 | *pos += n; | 179 | *pos += n; |
| 160 | buf += n; | ||
| 161 | remaining -= n; | 180 | remaining -= n; |
| 162 | start_sector += sectors_read; | 181 | sector += priv->chunk_sectors; |
| 163 | offset = 0; | 182 | offset = 0; |
| 164 | } while (remaining > 0); | 183 | } while (remaining > 0); |
| 165 | 184 | ||
| 166 | return count; | 185 | return count; |
| 167 | 186 | ||
| 168 | fail: | 187 | fail: |
| 169 | return sectors_read; | 188 | mutex_unlock(&priv->mutex); |
| 189 | return res; | ||
| 170 | } | 190 | } |
| 171 | 191 | ||
| 172 | static ssize_t ps3flash_write(struct file *file, const char __user *buf, | 192 | static ssize_t ps3flash_write(const char __user *userbuf, |
| 173 | size_t count, loff_t *pos) | 193 | const void *kernelbuf, size_t count, loff_t *pos) |
| 174 | { | 194 | { |
| 175 | struct ps3_storage_device *dev = ps3flash_dev; | 195 | struct ps3_storage_device *dev = ps3flash_dev; |
| 176 | struct ps3flash_private *priv = dev->sbd.core.driver_data; | 196 | struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
| 177 | u64 size, chunk_sectors, start_write_sector, end_write_sector, | 197 | u64 size, sector, offset; |
| 178 | end_read_sector, start_read_sector, head, tail, offset; | 198 | int res = 0; |
| 179 | ssize_t res; | ||
| 180 | size_t remaining, n; | 199 | size_t remaining, n; |
| 181 | unsigned int sec_off; | 200 | void *dst; |
| 182 | 201 | ||
| 183 | dev_dbg(&dev->sbd.core, | 202 | dev_dbg(&dev->sbd.core, |
| 184 | "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n", | 203 | "%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n", |
| 185 | __func__, __LINE__, count, *pos, buf); | 204 | __func__, __LINE__, count, *pos, userbuf, kernelbuf); |
| 186 | 205 | ||
| 187 | size = dev->regions[dev->region_idx].size*dev->blk_size; | 206 | size = dev->regions[dev->region_idx].size*dev->blk_size; |
| 188 | if (*pos >= size || !count) | 207 | if (*pos >= size || !count) |
| @@ -195,89 +214,46 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf, | |||
| 195 | count = size - *pos; | 214 | count = size - *pos; |
| 196 | } | 215 | } |
| 197 | 216 | ||
| 198 | chunk_sectors = dev->bounce_size / dev->blk_size; | 217 | sector = *pos / dev->bounce_size * priv->chunk_sectors; |
| 199 | |||
| 200 | start_write_sector = *pos / dev->bounce_size * chunk_sectors; | ||
| 201 | offset = *pos % dev->bounce_size; | 218 | offset = *pos % dev->bounce_size; |
| 202 | end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) * | ||
| 203 | chunk_sectors; | ||
| 204 | |||
| 205 | end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size); | ||
| 206 | start_read_sector = (*pos + count) / dev->blk_size; | ||
| 207 | |||
| 208 | /* | ||
| 209 | * As we have to write in 256 KiB chunks, while we can read in blk_size | ||
| 210 | * (usually 512 bytes) chunks, we perform the following steps: | ||
| 211 | * 1. Read from start_write_sector to end_read_sector ("head") | ||
| 212 | * 2. Read from start_read_sector to end_write_sector ("tail") | ||
| 213 | * 3. Copy data to buffer | ||
| 214 | * 4. Write from start_write_sector to end_write_sector | ||
| 215 | * All of this is complicated by using only one 256 KiB bounce buffer. | ||
| 216 | */ | ||
| 217 | |||
| 218 | head = end_read_sector - start_write_sector; | ||
| 219 | tail = end_write_sector - start_read_sector; | ||
| 220 | 219 | ||
| 221 | remaining = count; | 220 | remaining = count; |
| 222 | do { | 221 | do { |
| 222 | n = min_t(u64, remaining, dev->bounce_size - offset); | ||
| 223 | dst = dev->bounce_buf + offset; | ||
| 224 | |||
| 223 | mutex_lock(&priv->mutex); | 225 | mutex_lock(&priv->mutex); |
| 224 | 226 | ||
| 225 | if (end_read_sector >= start_read_sector) { | 227 | if (n != dev->bounce_size) |
| 226 | /* Merge head and tail */ | 228 | res = ps3flash_fetch(dev, sector); |
| 227 | dev_dbg(&dev->sbd.core, | 229 | else if (sector != priv->tag) |
| 228 | "Merged head and tail: %llu sectors at %llu\n", | 230 | res = ps3flash_writeback(dev); |
| 229 | chunk_sectors, start_write_sector); | 231 | if (res) |
| 230 | res = ps3flash_read_sectors(dev, start_write_sector, | 232 | goto fail; |
| 231 | chunk_sectors, 0); | 233 | |
| 232 | if (res < 0) | 234 | dev_dbg(&dev->sbd.core, |
| 235 | "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n", | ||
| 236 | __func__, __LINE__, n, userbuf, kernelbuf, dst); | ||
| 237 | if (userbuf) { | ||
| 238 | if (copy_from_user(dst, userbuf, n)) { | ||
| 239 | res = -EFAULT; | ||
| 233 | goto fail; | 240 | goto fail; |
| 234 | } else { | ||
| 235 | if (head) { | ||
| 236 | /* Read head */ | ||
| 237 | dev_dbg(&dev->sbd.core, | ||
| 238 | "head: %llu sectors at %llu\n", head, | ||
| 239 | start_write_sector); | ||
| 240 | res = ps3flash_read_sectors(dev, | ||
| 241 | start_write_sector, | ||
| 242 | head, 0); | ||
| 243 | if (res < 0) | ||
| 244 | goto fail; | ||
| 245 | } | ||
| 246 | if (start_read_sector < | ||
| 247 | start_write_sector+chunk_sectors) { | ||
| 248 | /* Read tail */ | ||
| 249 | dev_dbg(&dev->sbd.core, | ||
| 250 | "tail: %llu sectors at %llu\n", tail, | ||
| 251 | start_read_sector); | ||
| 252 | sec_off = start_read_sector-start_write_sector; | ||
| 253 | res = ps3flash_read_sectors(dev, | ||
| 254 | start_read_sector, | ||
| 255 | tail, sec_off); | ||
| 256 | if (res < 0) | ||
| 257 | goto fail; | ||
| 258 | } | 241 | } |
| 242 | userbuf += n; | ||
| 259 | } | 243 | } |
| 260 | 244 | if (kernelbuf) { | |
| 261 | n = min_t(u64, remaining, dev->bounce_size-offset); | 245 | memcpy(dst, kernelbuf, n); |
| 262 | dev_dbg(&dev->sbd.core, | 246 | kernelbuf += n; |
| 263 | "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n", | ||
| 264 | __func__, __LINE__, n, buf, dev->bounce_buf+offset); | ||
| 265 | if (copy_from_user(dev->bounce_buf+offset, buf, n)) { | ||
| 266 | res = -EFAULT; | ||
| 267 | goto fail; | ||
| 268 | } | 247 | } |
| 269 | 248 | ||
| 270 | res = ps3flash_write_chunk(dev, start_write_sector); | 249 | priv->tag = sector; |
| 271 | if (res < 0) | 250 | priv->dirty = true; |
| 272 | goto fail; | ||
| 273 | 251 | ||
| 274 | mutex_unlock(&priv->mutex); | 252 | mutex_unlock(&priv->mutex); |
| 275 | 253 | ||
| 276 | *pos += n; | 254 | *pos += n; |
| 277 | buf += n; | ||
| 278 | remaining -= n; | 255 | remaining -= n; |
| 279 | start_write_sector += chunk_sectors; | 256 | sector += priv->chunk_sectors; |
| 280 | head = 0; | ||
| 281 | offset = 0; | 257 | offset = 0; |
| 282 | } while (remaining > 0); | 258 | } while (remaining > 0); |
| 283 | 259 | ||
| @@ -288,6 +264,51 @@ fail: | |||
| 288 | return res; | 264 | return res; |
| 289 | } | 265 | } |
| 290 | 266 | ||
| 267 | static ssize_t ps3flash_user_read(struct file *file, char __user *buf, | ||
| 268 | size_t count, loff_t *pos) | ||
| 269 | { | ||
| 270 | return ps3flash_read(buf, NULL, count, pos); | ||
| 271 | } | ||
| 272 | |||
| 273 | static ssize_t ps3flash_user_write(struct file *file, const char __user *buf, | ||
| 274 | size_t count, loff_t *pos) | ||
| 275 | { | ||
| 276 | return ps3flash_write(buf, NULL, count, pos); | ||
| 277 | } | ||
| 278 | |||
| 279 | static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos) | ||
| 280 | { | ||
| 281 | return ps3flash_read(NULL, buf, count, &pos); | ||
| 282 | } | ||
| 283 | |||
| 284 | static ssize_t ps3flash_kernel_write(const void *buf, size_t count, | ||
| 285 | loff_t pos) | ||
| 286 | { | ||
| 287 | ssize_t res; | ||
| 288 | int wb; | ||
| 289 | |||
| 290 | res = ps3flash_write(NULL, buf, count, &pos); | ||
| 291 | if (res < 0) | ||
| 292 | return res; | ||
| 293 | |||
| 294 | /* Make kernel writes synchronous */ | ||
| 295 | wb = ps3flash_writeback(ps3flash_dev); | ||
| 296 | if (wb) | ||
| 297 | return wb; | ||
| 298 | |||
| 299 | return res; | ||
| 300 | } | ||
| 301 | |||
| 302 | static int ps3flash_flush(struct file *file, fl_owner_t id) | ||
| 303 | { | ||
| 304 | return ps3flash_writeback(ps3flash_dev); | ||
| 305 | } | ||
| 306 | |||
| 307 | static int ps3flash_fsync(struct file *file, struct dentry *dentry, | ||
| 308 | int datasync) | ||
| 309 | { | ||
| 310 | return ps3flash_writeback(ps3flash_dev); | ||
| 311 | } | ||
| 291 | 312 | ||
| 292 | static irqreturn_t ps3flash_interrupt(int irq, void *data) | 313 | static irqreturn_t ps3flash_interrupt(int irq, void *data) |
| 293 | { | 314 | { |
| @@ -312,12 +333,18 @@ static irqreturn_t ps3flash_interrupt(int irq, void *data) | |||
| 312 | return IRQ_HANDLED; | 333 | return IRQ_HANDLED; |
| 313 | } | 334 | } |
| 314 | 335 | ||
| 315 | |||
| 316 | static const struct file_operations ps3flash_fops = { | 336 | static const struct file_operations ps3flash_fops = { |
| 317 | .owner = THIS_MODULE, | 337 | .owner = THIS_MODULE, |
| 318 | .llseek = ps3flash_llseek, | 338 | .llseek = ps3flash_llseek, |
| 319 | .read = ps3flash_read, | 339 | .read = ps3flash_user_read, |
| 320 | .write = ps3flash_write, | 340 | .write = ps3flash_user_write, |
| 341 | .flush = ps3flash_flush, | ||
| 342 | .fsync = ps3flash_fsync, | ||
| 343 | }; | ||
| 344 | |||
| 345 | static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = { | ||
| 346 | .read = ps3flash_kernel_read, | ||
| 347 | .write = ps3flash_kernel_write, | ||
| 321 | }; | 348 | }; |
| 322 | 349 | ||
| 323 | static struct miscdevice ps3flash_misc = { | 350 | static struct miscdevice ps3flash_misc = { |
| @@ -366,11 +393,13 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) | |||
| 366 | goto fail; | 393 | goto fail; |
| 367 | } | 394 | } |
| 368 | 395 | ||
| 369 | dev->sbd.core.driver_data = priv; | 396 | ps3_system_bus_set_drvdata(&dev->sbd, priv); |
| 370 | mutex_init(&priv->mutex); | 397 | mutex_init(&priv->mutex); |
| 398 | priv->tag = -1; | ||
| 371 | 399 | ||
| 372 | dev->bounce_size = ps3flash_bounce_buffer.size; | 400 | dev->bounce_size = ps3flash_bounce_buffer.size; |
| 373 | dev->bounce_buf = ps3flash_bounce_buffer.address; | 401 | dev->bounce_buf = ps3flash_bounce_buffer.address; |
| 402 | priv->chunk_sectors = dev->bounce_size / dev->blk_size; | ||
| 374 | 403 | ||
| 375 | error = ps3stor_setup(dev, ps3flash_interrupt); | 404 | error = ps3stor_setup(dev, ps3flash_interrupt); |
| 376 | if (error) | 405 | if (error) |
| @@ -386,13 +415,15 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) | |||
| 386 | 415 | ||
| 387 | dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n", | 416 | dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n", |
| 388 | __func__, __LINE__, ps3flash_misc.minor); | 417 | __func__, __LINE__, ps3flash_misc.minor); |
| 418 | |||
| 419 | ps3_os_area_flash_register(&ps3flash_kernel_ops); | ||
| 389 | return 0; | 420 | return 0; |
| 390 | 421 | ||
| 391 | fail_teardown: | 422 | fail_teardown: |
| 392 | ps3stor_teardown(dev); | 423 | ps3stor_teardown(dev); |
| 393 | fail_free_priv: | 424 | fail_free_priv: |
| 394 | kfree(priv); | 425 | kfree(priv); |
| 395 | dev->sbd.core.driver_data = NULL; | 426 | ps3_system_bus_set_drvdata(&dev->sbd, NULL); |
| 396 | fail: | 427 | fail: |
| 397 | ps3flash_dev = NULL; | 428 | ps3flash_dev = NULL; |
| 398 | return error; | 429 | return error; |
| @@ -402,10 +433,11 @@ static int ps3flash_remove(struct ps3_system_bus_device *_dev) | |||
| 402 | { | 433 | { |
| 403 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); | 434 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); |
| 404 | 435 | ||
| 436 | ps3_os_area_flash_register(NULL); | ||
| 405 | misc_deregister(&ps3flash_misc); | 437 | misc_deregister(&ps3flash_misc); |
| 406 | ps3stor_teardown(dev); | 438 | ps3stor_teardown(dev); |
| 407 | kfree(dev->sbd.core.driver_data); | 439 | kfree(ps3_system_bus_get_drvdata(&dev->sbd)); |
| 408 | dev->sbd.core.driver_data = NULL; | 440 | ps3_system_bus_set_drvdata(&dev->sbd, NULL); |
| 409 | ps3flash_dev = NULL; | 441 | ps3flash_dev = NULL; |
| 410 | return 0; | 442 | return 0; |
| 411 | } | 443 | } |
