linux/drivers/char/ps3flash.c
<<
>>
Prefs
   1/*
   2 * PS3 FLASH ROM Storage Driver
   3 *
   4 * Copyright (C) 2007 Sony Computer Entertainment Inc.
   5 * Copyright 2007 Sony Corp.
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of the GNU General Public License as published
   9 * by the Free Software Foundation; version 2 of the License.
  10 *
  11 * This program is distributed in the hope that it will be useful, but
  12 * WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License along
  17 * with this program; if not, write to the Free Software Foundation, Inc.,
  18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19 */
  20
  21#include <linux/fs.h>
  22#include <linux/miscdevice.h>
  23#include <linux/slab.h>
  24#include <linux/uaccess.h>
  25#include <linux/module.h>
  26
  27#include <asm/lv1call.h>
  28#include <asm/ps3stor.h>
  29
  30
  31#define DEVICE_NAME             "ps3flash"
  32
  33#define FLASH_BLOCK_SIZE        (256*1024)
  34
  35
  36struct ps3flash_private {
  37        struct mutex mutex;     /* Bounce buffer mutex */
  38        u64 chunk_sectors;
  39        int tag;                /* Start sector of buffer, -1 if invalid */
  40        bool dirty;
  41};
  42
  43static struct ps3_storage_device *ps3flash_dev;
  44
  45static int ps3flash_read_write_sectors(struct ps3_storage_device *dev,
  46                                       u64 start_sector, int write)
  47{
  48        struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
  49        u64 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar,
  50                                             start_sector, priv->chunk_sectors,
  51                                             write);
  52        if (res) {
  53                dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
  54                        __LINE__, write ? "write" : "read", res);
  55                return -EIO;
  56        }
  57        return 0;
  58}
  59
  60static int ps3flash_writeback(struct ps3_storage_device *dev)
  61{
  62        struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
  63        int res;
  64
  65        if (!priv->dirty || priv->tag < 0)
  66                return 0;
  67
  68        res = ps3flash_read_write_sectors(dev, priv->tag, 1);
  69        if (res)
  70                return res;
  71
  72        priv->dirty = false;
  73        return 0;
  74}
  75
  76static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector)
  77{
  78        struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
  79        int res;
  80
  81        if (start_sector == priv->tag)
  82                return 0;
  83
  84        res = ps3flash_writeback(dev);
  85        if (res)
  86                return res;
  87
  88        priv->tag = -1;
  89
  90        res = ps3flash_read_write_sectors(dev, start_sector, 0);
  91        if (res)
  92                return res;
  93
  94        priv->tag = start_sector;
  95        return 0;
  96}
  97
  98static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
  99{
 100        struct ps3_storage_device *dev = ps3flash_dev;
 101        loff_t res;
 102
 103        mutex_lock(&file->f_mapping->host->i_mutex);
 104        switch (origin) {
 105        case 0:
 106                break;
 107        case 1:
 108                offset += file->f_pos;
 109                break;
 110        case 2:
 111                offset += dev->regions[dev->region_idx].size*dev->blk_size;
 112                break;
 113        default:
 114                offset = -1;
 115        }
 116        if (offset < 0) {
 117                res = -EINVAL;
 118                goto out;
 119        }
 120
 121        file->f_pos = offset;
 122        res = file->f_pos;
 123
 124out:
 125        mutex_unlock(&file->f_mapping->host->i_mutex);
 126        return res;
 127}
 128
 129static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
 130                             size_t count, loff_t *pos)
 131{
 132        struct ps3_storage_device *dev = ps3flash_dev;
 133        struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
 134        u64 size, sector, offset;
 135        int res;
 136        size_t remaining, n;
 137        const void *src;
 138
 139        dev_dbg(&dev->sbd.core,
 140                "%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n",
 141                __func__, __LINE__, count, *pos, userbuf, kernelbuf);
 142
 143        size = dev->regions[dev->region_idx].size*dev->blk_size;
 144        if (*pos >= size || !count)
 145                return 0;
 146
 147        if (*pos + count > size) {
 148                dev_dbg(&dev->sbd.core,
 149                        "%s:%u Truncating count from %zu to %llu\n", __func__,
 150                        __LINE__, count, size - *pos);
 151                count = size - *pos;
 152        }
 153
 154        sector = *pos / dev->bounce_size * priv->chunk_sectors;
 155        offset = *pos % dev->bounce_size;
 156
 157        remaining = count;
 158        do {
 159                n = min_t(u64, remaining, dev->bounce_size - offset);
 160                src = dev->bounce_buf + offset;
 161
 162                mutex_lock(&priv->mutex);
 163
 164                res = ps3flash_fetch(dev, sector);
 165                if (res)
 166                        goto fail;
 167
 168                dev_dbg(&dev->sbd.core,
 169                        "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n",
 170                        __func__, __LINE__, n, src, userbuf, kernelbuf);
 171                if (userbuf) {
 172                        if (copy_to_user(userbuf, src, n)) {
 173                                res = -EFAULT;
 174                                goto fail;
 175                        }
 176                        userbuf += n;
 177                }
 178                if (kernelbuf) {
 179                        memcpy(kernelbuf, src, n);
 180                        kernelbuf += n;
 181                }
 182
 183                mutex_unlock(&priv->mutex);
 184
 185                *pos += n;
 186                remaining -= n;
 187                sector += priv->chunk_sectors;
 188                offset = 0;
 189        } while (remaining > 0);
 190
 191        return count;
 192
 193fail:
 194        mutex_unlock(&priv->mutex);
 195        return res;
 196}
 197
 198static ssize_t ps3flash_write(const char __user *userbuf,
 199                              const void *kernelbuf, size_t count, loff_t *pos)
 200{
 201        struct ps3_storage_device *dev = ps3flash_dev;
 202        struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
 203        u64 size, sector, offset;
 204        int res = 0;
 205        size_t remaining, n;
 206        void *dst;
 207
 208        dev_dbg(&dev->sbd.core,
 209                "%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n",
 210                __func__, __LINE__, count, *pos, userbuf, kernelbuf);
 211
 212        size = dev->regions[dev->region_idx].size*dev->blk_size;
 213        if (*pos >= size || !count)
 214                return 0;
 215
 216        if (*pos + count > size) {
 217                dev_dbg(&dev->sbd.core,
 218                        "%s:%u Truncating count from %zu to %llu\n", __func__,
 219                        __LINE__, count, size - *pos);
 220                count = size - *pos;
 221        }
 222
 223        sector = *pos / dev->bounce_size * priv->chunk_sectors;
 224        offset = *pos % dev->bounce_size;
 225
 226        remaining = count;
 227        do {
 228                n = min_t(u64, remaining, dev->bounce_size - offset);
 229                dst = dev->bounce_buf + offset;
 230
 231                mutex_lock(&priv->mutex);
 232
 233                if (n != dev->bounce_size)
 234                        res = ps3flash_fetch(dev, sector);
 235                else if (sector != priv->tag)
 236                        res = ps3flash_writeback(dev);
 237                if (res)
 238                        goto fail;
 239
 240                dev_dbg(&dev->sbd.core,
 241                        "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n",
 24ass="sref">copy_to_user(<__func__, __LINE__, userbuf, kernelbuf, dst);
2433                if (userbuf) {
2434                        if (copy froo_usek(dstuserbuf, n)) {
2145               opy_to_user(<res = -EFAULT;
2436                                goto fail;
2437                        }
2148               ser(<userbuf += n;
2149                }
2150                if (kernelbuf) {
2151               ser(<memcpy(dstkernelbuf, n);
254ass="sref">copy_to_user(<kernelbuf += n;
2533                }
2584
2545                priv->tag = sector;
2586                priv-> = ;
2507
2528                mutex_unlock(&priv->mutex);
2539
2160                *pos += n;
2631                remaining -= n;
2162                sector += priv->chunk_sectors;
2683                offset = 0;
2164        } while (remaining > 0);
2625
2166        return count;
2167
2168fail:
2639        mutex_unlock(&priv->mutex);
2170        return res;
21712732
2173static ssize_t ps3flash>useh_reak struct filefile__user *buf,
2174                                  size_t count, loff_t *pos)
21752766        return ps3flash_read*bufn n count, pos);
2727}
2738
2729static ssize_t ps3flash>useh_writk struct filefile__user *buf,
2180                                   size_t count, loff_t *pos)
2831{
2826        return ps3flash_write*bufn n count, pos);
2183}
2184
2185static ssize_t ps3flash>kerneh_reae void *bufn size_t count, loff_t*pos)
2186{
2187        return ps3flash_read*n bufn count,(&pos);
2188}
2839
2190static ssize_t ps3flash>kerneh_writd const void *bufn size_t count>
2951               ser(              loff_t*pos)
2192{
2923        ssize_t res;
2194        int ;
2925
2926        res = ps3flash_write*n bufn count,(&pos);
2947        if  res&lgt; 0;
2928                return res;
2939
3080        /* Make >kerne _writs synchronous */;
3201         = ps3flash_writeback(ps3flash_dev);
3202        if  3083                return ;
3084
3205        return res;
3096}
3207
3098static int ps3flash_lusck struct filefile 3209{
3170        return ps3flash_writeback(ps3flash_dev);
31713132
3138static int ps3flash_synck struct filefileloff_t*str_eloff_t*3214{
3105        struct file->.->;
3216        int ;
3157        mutex_lock(&->);
3108         = ps3flash_writeback(ps3flash_dev);
3139        mutex_unlock(&->);
3270        return ;
32713222
3273static   int 3214{
3205        struct ps3_storage_device *dev = ;
3216        int res;
3257        u64 tagn ;
3238
3239        res = (dev->sbd.deviat,(&tagn(&);
3230
3231        if  tag != dev->tag)
3362                deverek(&dev->sbd.core,
3233                        "%s:%u:>ta mismatch,  goo %lx, expectedo %lxp\n",
3234                        __func__, __LINE__, tagn dev->tag);
3325
3236        if (res) {
3237                deverek(&dev->sbd.core  "%s:%u:>re=:%d =staue= 0x%lxp\n",
3238                        __func__, __LINE__, resn );
3389        } else {
3240                dev-> = ;
3241               .(&dev->);
324ass="sref">c }
3433        return ;
34343425
3436static const struct  ps3flashfopos = {
3437       >.  = ,
3148       >. = ,
3149       >.  = ps3flash>useh_reak,
3150       >.  = ps3flash>useh_writk,
3151       >.  = ps3flash_lusck,
354ass="sref">c>.  = ps3flash_synck,
3533;
3584
3556static const struct ps3os_a_re_3flashopot ps3flash>kernehopos = {
3586       >.  = ps3flash>kerneh_reae,
3537       >.  = ps3flash>kerneh_writd,
3528;
3539
3690static struct  ps3flashmiscs = {
3651       >.  = ,
364ass="sref">c>.  = ,
3683       >.>  =(&ps3flashfopos,
3u64;
3625
3636static int  ps3flashprobtk struct ps3_system_bus_device *>
31673648        struct ps3_storage_device *dev = (&->core);
3639        struct ps3flash_private *priv3170        int 3751       unsigned long= 3732
3723         = dev->regions[dev->region_idx].str_edev->blk_size;
3174        if   % ) {
3745                deverek(&dev->sbd.core{
3766       >                "%s:%u>regio >str_y %luis not alignedu\n", __func__,
3737                        __LINE__, );
3728                return -;
3789        ;
3180         = dev->regions[dev->region_idx].size*dev->blk_size;
3831        if   % ) {
3862                deverek(&dev->sbd.core,
3833                        "%s:%u>regio >sizy %luis not alignedu\n", __func__,
3834                        __LINE__, );
3845                return -;
3869        ;
3807
3808        /* use >staticbuffer, kmalloc cannot allocvat>258 KiB */;
3891        if ! bounce_buferd.>
3940                return -;
39513902        if  ps3flash_dev) {
3933                deverek(&dev->sbd.core,
3934                        "Only one FLASH _devicuis supportedu\n");
3945                return -;
3969        ;
3907
3908        ps3flash_dev = dev;
3939
4080        priv =  sizof( *priv, );
4031        if ! priv4062                 = -;
4083                goto fail;
4049        ;
4025
4026        ps3_system_busset_drv=datk(&dev->sbd, priv;
4057        (&priv->mutex);
4008        priv->tag =-1);
4039
4180        dev->bounce_sizv = bounce_buferd.size4101        dev->bounce_buv = bounce_buferd.4128        priv->chunk_sectors = dev->bounce_sizv/= dev->blk_size;
41384148         =  dev, );
4105        if  >
4166       >        goto ;
4107
4108        ps3flashmiscs. =(&dev->sbd.core;
4139         = regystok(&ps3flashmiscs);
4270        if  ) {
4241               .deverek(&dev->sbd.core  "%s:%u:misc_>regysto =faiedo %du\n"{
424ass="sref">copy_to_user(<__func__, __LINE__, );
4283                goto ;
4249        ;
4225
4226        devinfok(&dev->sbd.core  "%s:%u:>regystoedomisc _devicu %du\n"{
4237                <__func__, __LINE__, ps3flashmiscs.);
4238
4239        ps3os_a_re_3flash>regystok(&ps3flash>kernehopos);
4370        return 0;
43514362:
4323         dev);
4234:
4353         priv;
4326        ps3_system_busset_drv=datk(&dev->sbd, ;
4237fail:
4308        ps3flash_dev = ;
4389        return 42404451424ass=>static int ps3flashremovtk struct ps3_system_bus_device *>
44334449        struct ps3_storage_device *dev = (&->core;
4425
4426        ps3os_a_re_3flash>regystok ;
4457        regystok(&ps3flashmiscs);
4408         dev);
4439         ps3_system_busget_drv=datk(&dev->sbd);
4580        ps3_system_busset_drv=datk(&dev->sbd, ;
4501        ps3flash_dev = ;
454ass="sref">c return 0;
4583}
4584
4525
4536static struct ps3_system_bus_driveass=" ps3flasv = {
4537       >.       = {
4548       >.core.     = ,
4549       >.core.     = ,
4650       >.robtkps3flashprobtk,
4651       >.ps3flashremovtk,
464ass="sref">c>.       = ps3flashremovtk,
4633;
4684
4625
4636static int   voi>>
41674648        return ps3_system_bus_driveh>regystok(&ps3flasv;
4639}
4730
4751static void   voi>>
47324723        ps3_system_bus_drivehun>regystok(&ps3flasv;
47344725
4766 ;
4737 ;
4738
4789 "GPLn");
4180 "PS3 FLASH ROM Sstorag Ddriven");
4831 "Sony Corporatgion");
4862 ;
4833


The original LXR software by the LXR communi_yd,this experimeunal ivergio by lxo@"liux.noe
lxo."liux.no kindly hostedoby Redpill Llipro ASk