nand.c revision 2779beecc7410f29102125e87e8174597acb2fe5
18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Copyright (C) 2007-2008 The Android Open Source Project
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project**
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This software is licensed under the terms of the GNU General Public
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** License version 2, as published by the Free Software Foundation, and
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** may be copied, distributed, and modified under those terms.
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project**
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This program is distributed in the hope that it will be useful,
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** but WITHOUT ANY WARRANTY; without even the implied warranty of
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** GNU General Public License for more details.
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project*/
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu_file.h"
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "goldfish_nand_reg.h"
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "goldfish_nand.h"
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "android/utils/tempfile.h"
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu_debug.h"
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "android/android.h"
188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  DEBUG  1
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if DEBUG
21acbee3546b9a380a4eb33daef3dccfac87c56b0bXavier Ducrohet#  define  D(...)    VERBOSE_PRINT(init,__VA_ARGS__)
22acbee3546b9a380a4eb33daef3dccfac87c56b0bXavier Ducrohet#  define  D_ACTIVE  VERBOSE_CHECK(init)
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#  define  T(...)    VERBOSE_PRINT(nand_limits,__VA_ARGS__)
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#  define  T_ACTIVE  VERBOSE_CHECK(nand_limits)
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#  define  D(...)    ((void)0)
278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#  define  D_ACTIVE  0
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#  define  T(...)    ((void)0)
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#  define  T_ACTIVE  0
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* lseek uses 64-bit offsets on Darwin. */
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* prefer lseek64 on Linux              */
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef __APPLE__
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#  define  llseek  lseek
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#elif defined(__linux__)
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#  define  llseek  lseek64
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  XLOG  xlog
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectxlog( const char*  format, ... )
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    va_list  args;
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    va_start(args, format);
478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    fprintf(stderr, "NAND: ");
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vfprintf(stderr, format, args);
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    va_end(args);
508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
52c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije/* Information on a single device/nand image used by the emulator
53c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */
548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct {
55c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    char*      devname;      /* name for this device (not null-terminated, use len below) */
568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    size_t     devname_len;
57c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    uint8_t*   data;         /* buffer for read/write actions to underlying image */
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int        fd;
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t   flags;
608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t   page_size;
618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t   extra_size;
62c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    uint32_t   erase_size;   /* size of the data buffer mentioned above */
63c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    uint64_t   max_size;     /* Capacity limit for the image. The actual underlying
64c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije                              * file may be smaller. */
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} nand_dev;
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnand_threshold    android_nand_write_threshold;
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnand_threshold    android_nand_read_threshold;
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef CONFIG_NAND_THRESHOLD
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* update a threshold, return 1 if limit is hit, 0 otherwise */
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectnand_threshold_update( nand_threshold*  t, uint32_t  len )
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (t->counter < t->limit) {
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint64_t  avail = t->limit - t->counter;
788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (avail > len)
798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            avail = len;
808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (t->counter == 0) {
82e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            T("%s: starting threshold counting to %lld",
838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project              __FUNCTION__, t->limit);
848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        t->counter += avail;
868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (t->counter >= t->limit) {
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* threshold reach, send a signal to an external process */
88e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            T( "%s: sending signal %d to pid %d !",
898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               __FUNCTION__, t->signal, t->pid );
908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            kill( t->pid, t->signal );
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return;
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  NAND_UPDATE_READ_THRESHOLD(len)  \
988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    nand_threshold_update( &android_nand_read_threshold, (uint32_t)(len) )
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  NAND_UPDATE_WRITE_THRESHOLD(len)  \
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    nand_threshold_update( &android_nand_write_threshold, (uint32_t)(len) )
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else /* !NAND_THRESHOLD */
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  NAND_UPDATE_READ_THRESHOLD(len)  \
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    do {} while (0)
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  NAND_UPDATE_WRITE_THRESHOLD(len)  \
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    do {} while (0)
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif /* !NAND_THRESHOLD */
1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic nand_dev *nand_devs = NULL;
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t nand_dev_count = 0;
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
116c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije/* The controller is the single access point for all NAND images currently
117c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * attached to the system.
118c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct {
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t base;
1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    // register state
123c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    uint32_t dev;            /* offset in nand_devs for the device that is
124c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije                              * currently being accessed */
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t addr_low;
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t addr_high;
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t transfer_size;
1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t data;
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t result;
130c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije} nand_dev_controller_state;
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
132c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije/* update this everytime you change the nand_dev_controller_state structure
133c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * 1: initial version, saving only nand_dev_controller_state fields
134c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * 2: saving actual disk contents as well
135c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */
136c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije#define  NAND_DEV_STATE_SAVE_VERSION  2
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
138c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije#define  QFIELD_STRUCT  nand_dev_controller_state
139c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten ThijeQFIELD_BEGIN(nand_dev_controller_state_fields)
1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(dev),
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(addr_low),
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(addr_high),
1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(transfer_size),
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(data),
1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(result),
1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectQFIELD_END
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int  do_read(int  fd, void*  buf, size_t  size)
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int  ret;
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    do {
1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ret = read(fd, buf, size);
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } while (ret < 0 && errno == EINTR);
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return ret;
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int  do_write(int  fd, const void*  buf, size_t  size)
1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int  ret;
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    do {
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ret = write(fd, buf, size);
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } while (ret < 0 && errno == EINTR);
1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return ret;
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
169c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije#define NAND_DEV_SAVE_DISK_BUF_SIZE 2048
170c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
171c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
172c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije/**
173c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * Copies the current contents of a disk image into the snapshot file.
174c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije *
175c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * TODO optimize this using some kind of copy-on-write mechanism for
176c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije *      unchanged disk sections.
177c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */
178c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thijestatic void  nand_dev_save_disk_state(QEMUFile *f, nand_dev *dev)
179c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije{
180c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    int buf_size = NAND_DEV_SAVE_DISK_BUF_SIZE;
181c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    uint8_t buffer[NAND_DEV_SAVE_DISK_BUF_SIZE] = {0};
182c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    int ret;
183c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    uint64_t total_copied = 0;
184c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
185c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    /* Put the size up front, since otherwise we don't know how much to read
186c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije     * when restoring.
187c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije     */
188c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    const uint64_t total_size = dev->max_size;
189c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    qemu_put_be64(f, total_size);
190c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
191c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    /* copy all data from the stream to the stored image */
192c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    ret = lseek(dev->fd, 0, SEEK_SET);
193c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    if (ret < 0) {
194c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        XLOG("%s seek failed: %s\n", __FUNCTION__, strerror(errno));
195c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        qemu_file_set_error(f);
196c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        return;
197c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    }
198c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    do {
199c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        ret = do_read(dev->fd, buffer, buf_size);
200c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        if (ret < 0) {
201c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije            XLOG("%s read failed: %s\n", __FUNCTION__, strerror(errno));
202c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije            qemu_file_set_error(f);
203c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije            return;
204c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        }
205c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        qemu_put_buffer(f, buffer, ret);
206c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
207c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        total_copied += ret;
208c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    }
209c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    while (ret == buf_size && total_copied < total_size);
210c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
211c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    /* The file may be smaller than the device size. Pad with 0xff (pattern for
212c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije     * erased data) until we have filled the snapshot buffer we declared earlier.
213c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije     * TODO avoid padding. Unfortunately, attempts to use the actual size of the
214c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije     *      underlying image instead result in broken restores. This also happens
215c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije     *      when limited padding is inserted so the image size is a multiple of
216c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije     *      page_size or erase_size.
217c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije     */
218c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    memset(buffer, 0xff, NAND_DEV_SAVE_DISK_BUF_SIZE);
219c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    while (total_copied < total_size) {
220c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        /* adjust buffer size for last part of the image */
221c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        if (total_size - total_copied < buf_size) {
222c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije            buf_size = total_size - total_copied;
223c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        }
224c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        qemu_put_buffer(f, buffer, buf_size);
225c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        total_copied += buf_size;
226c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    }
227c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije}
228c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
229c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
230c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije/**
231c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * Saves the state of all disks managed by this controller to a snapshot file.
232c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */
233c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thijestatic void nand_dev_save_disks(QEMUFile *f)
234c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije{
235c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    int i;
236c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    for (i = 0; i < nand_dev_count; i++) {
237c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        nand_dev_save_disk_state(f, nand_devs + i);
238c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    }
239c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije}
240c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
241c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije/**
242c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * Overwrites the contents of the disk image managed by this device with the
243c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * contents as they were at the point the snapshot was made.
244c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */
245c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thijestatic int  nand_dev_load_disk_state(QEMUFile *f, nand_dev *dev)
246c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije{
247c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    int buf_size = NAND_DEV_SAVE_DISK_BUF_SIZE;
248c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    uint8_t buffer[NAND_DEV_SAVE_DISK_BUF_SIZE] = {0};
249c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    int ret;
250c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
251c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    /* number of bytes to restore */
252c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    uint64_t total_size = qemu_get_be64(f);
253c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    if (total_size > dev->max_size) {
254c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        XLOG("%s, restore failed: size required (%lld) exceeds device limit (%lld)\n",
255c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije             __FUNCTION__, total_size, dev->max_size);
256c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        return -EIO;
257c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    }
258c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
259c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    /* overwrite disk contents with snapshot contents */
260c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    uint64_t next_offset = 0;
261c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    do {
262c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        ret = lseek(dev->fd, 0, SEEK_SET);
263c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    } while (ret < 0 && errno == EINTR);
264c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    if (ret < 0) {
265c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        XLOG("%s seek failed: %s\n", __FUNCTION__, strerror(errno));
266c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        return -EIO;
267c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    }
268c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    while (next_offset < total_size) {
269c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        /* snapshot buffer may not be an exact multiple of buf_size
270c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije         * if necessary, adjust buffer size for last copy operation */
271c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        if (total_size - next_offset < buf_size) {
272c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije            buf_size = total_size - next_offset;
273c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        }
274c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
275c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        ret = qemu_get_buffer(f, buffer, buf_size);
276c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        if (ret != buf_size) {
277c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije            XLOG("%s read failed: expected %d bytes but got %d\n",
278c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije                 __FUNCTION__, buf_size, ret);
279c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije            return -EIO;
280c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        }
281c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        ret = do_write(dev->fd, buffer, buf_size);
282c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        if (ret != buf_size) {
283c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije            XLOG("%s, write failed: %s\n", __FUNCTION__, strerror(errno));
284c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije            return -EIO;
285c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        }
286c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
287c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        next_offset += buf_size;
288c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    }
289c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
290c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    return 0;
291c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije}
292c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
293c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije/**
294c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije * Restores the state of all disks managed by this driver from a snapshot file.
295c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije */
296c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thijestatic int nand_dev_load_disks(QEMUFile *f)
297c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije{
298c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    int i, ret;
299c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    for (i = 0; i < nand_dev_count; i++) {
300c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        ret = nand_dev_load_disk_state(f, nand_devs + i);
301c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        if (ret)
302c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije            return ret; // abort on error
303c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    }
304c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
305c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    return 0;
306c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije}
307c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
308c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thijestatic void  nand_dev_controller_state_save(QEMUFile *f, void  *opaque)
309c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije{
310c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    nand_dev_controller_state* s = opaque;
311c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
312c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    qemu_put_struct(f, nand_dev_controller_state_fields, s);
313c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
314c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    /* The guest will continue writing to the disk image after the state has
315c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije     * been saved. To guarantee that the state is identical after resume, save
316c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije     * a copy of the current disk state in the snapshot.
317c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije     */
318c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    nand_dev_save_disks(f);
319c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije}
320c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
321c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thijestatic int   nand_dev_controller_state_load(QEMUFile *f, void  *opaque, int  version_id)
322c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije{
323c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    nand_dev_controller_state*  s = opaque;
324c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    int ret;
325c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
326c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    if (version_id != NAND_DEV_STATE_SAVE_VERSION)
327c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        return -1;
328c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
329c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    if ((ret = qemu_get_struct(f, nand_dev_controller_state_fields, s)))
330c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        return ret;
331c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    if ((ret = nand_dev_load_disks(f)))
332c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        return ret;
333c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
334c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    return 0;
335c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije}
336c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije
3378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t nand_dev_read_file(nand_dev *dev, uint32_t data, uint64_t addr, uint32_t total_len)
3388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t len = total_len;
3408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    size_t read_len = dev->erase_size;
3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int eof = 0;
3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    NAND_UPDATE_READ_THRESHOLD(total_len);
3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    lseek(dev->fd, addr, SEEK_SET);
3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while(len > 0) {
3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(read_len < dev->erase_size) {
3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            memset(dev->data, 0xff, dev->erase_size);
3498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            read_len = dev->erase_size;
3508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            eof = 1;
3518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(len < read_len)
3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            read_len = len;
3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(!eof) {
3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            read_len = do_read(dev->fd, dev->data, read_len);
3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        cpu_memory_rw_debug(cpu_single_env, data, dev->data, read_len, 1);
3588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        data += read_len;
3598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        len -= read_len;
3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return total_len;
3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t nand_dev_write_file(nand_dev *dev, uint32_t data, uint64_t addr, uint32_t total_len)
3658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t len = total_len;
3678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    size_t write_len = dev->erase_size;
3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ret;
3698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    NAND_UPDATE_WRITE_THRESHOLD(total_len);
3718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    lseek(dev->fd, addr, SEEK_SET);
3738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while(len > 0) {
3748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(len < write_len)
3758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            write_len = len;
3765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        cpu_memory_rw_debug(cpu_single_env, data, dev->data, write_len, 0);
3778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ret = do_write(dev->fd, dev->data, write_len);
3788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(ret < write_len) {
3798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            XLOG("nand_dev_write_file, write failed: %s\n", strerror(errno));
3808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
3818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        data += write_len;
3838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        len -= write_len;
3848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return total_len - len;
3868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t nand_dev_erase_file(nand_dev *dev, uint64_t addr, uint32_t total_len)
3898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t len = total_len;
3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    size_t write_len = dev->erase_size;
3928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ret;
3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    lseek(dev->fd, addr, SEEK_SET);
3958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memset(dev->data, 0xff, dev->erase_size);
3968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while(len > 0) {
3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(len < write_len)
3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            write_len = len;
3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ret = do_write(dev->fd, dev->data, write_len);
4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(ret < write_len) {
4018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            XLOG( "nand_dev_write_file, write failed: %s\n", strerror(errno));
4028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
4038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        len -= write_len;
4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return total_len - len;
4078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* this is a huge hack required to make the PowerPC emulator binary usable
4108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * on Mac OS X. If you define this function as 'static', the emulated kernel
4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * will panic when attempting to mount the /data partition.
4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * worse, if you do *not* define the function as static on Linux-x86, the
4148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * emulated kernel will also panic !?
4158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
4168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * I still wonder if this is a compiler bug, or due to some nasty thing the
4178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * emulator does with CPU registers during execution of the translated code.
4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if !(defined __APPLE__ && defined __powerpc__)
4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic
4218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
422c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thijeuint32_t nand_dev_do_cmd(nand_dev_controller_state *s, uint32_t cmd)
4238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t size;
4258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint64_t addr;
4268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    nand_dev *dev;
4278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    addr = s->addr_low | ((uint64_t)s->addr_high << 32);
4298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    size = s->transfer_size;
4308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(s->dev >= nand_dev_count)
4318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
4328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dev = nand_devs + s->dev;
4338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch(cmd) {
4358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_CMD_GET_DEV_NAME:
4368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(size > dev->devname_len)
4378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            size = dev->devname_len;
4384e024bb4f5c8aa8b07459f7fbd65c35122127fd1David 'Digit' Turner        cpu_memory_rw_debug(cpu_single_env, s->data, (uint8_t*)dev->devname, size, 1);
4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return size;
4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_CMD_READ:
441c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        if(addr >= dev->max_size)
4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return 0;
443c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        if(size > dev->max_size - addr)
444c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije            size = dev->max_size - addr;
4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(dev->fd >= 0)
4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return nand_dev_read_file(dev, s->data, addr, size);
4475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        cpu_memory_rw_debug(cpu_single_env,s->data, &dev->data[addr], size, 1);
4488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return size;
4498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_CMD_WRITE:
4508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(dev->flags & NAND_DEV_FLAG_READ_ONLY)
4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return 0;
452c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        if(addr >= dev->max_size)
4538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return 0;
454c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        if(size > dev->max_size - addr)
455c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije            size = dev->max_size - addr;
4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(dev->fd >= 0)
4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return nand_dev_write_file(dev, s->data, addr, size);
4585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        cpu_memory_rw_debug(cpu_single_env,s->data, &dev->data[addr], size, 0);
4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return size;
4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_CMD_ERASE:
4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(dev->flags & NAND_DEV_FLAG_READ_ONLY)
4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return 0;
463c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        if(addr >= dev->max_size)
4648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return 0;
465c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        if(size > dev->max_size - addr)
466c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije            size = dev->max_size - addr;
4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(dev->fd >= 0)
4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return nand_dev_erase_file(dev, addr, size);
4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        memset(&dev->data[addr], 0xff, size);
4708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return size;
4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_CMD_BLOCK_BAD_GET: // no bad block support
4728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_CMD_BLOCK_BAD_SET:
4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(dev->flags & NAND_DEV_FLAG_READ_ONLY)
4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return 0;
4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
4778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
4788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_abort(cpu_single_env, "nand_dev_do_cmd: Bad command %x\n", cmd);
4798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
4808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* I/O write */
4848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void nand_dev_write(void *opaque, target_phys_addr_t offset, uint32_t value)
4858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
486c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    nand_dev_controller_state *s = (nand_dev_controller_state *)opaque;
4878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (offset) {
4898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_DEV:
4908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->dev = value;
4918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(s->dev >= nand_dev_count) {
4928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            cpu_abort(cpu_single_env, "nand_dev_write: Bad dev %x\n", value);
4938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
4958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_ADDR_HIGH:
4968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->addr_high = value;
4978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
4988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_ADDR_LOW:
4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->addr_low = value;
5008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_TRANSFER_SIZE:
5028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->transfer_size = value;
5038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
5048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_DATA:
5058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->data = value;
5068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
5078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_COMMAND:
5088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->result = nand_dev_do_cmd(s, value);
5098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
5108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
5118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_abort(cpu_single_env, "nand_dev_write: Bad offset %x\n", offset);
5128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
5138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* I/O read */
5178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t nand_dev_read(void *opaque, target_phys_addr_t offset)
5188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
519c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    nand_dev_controller_state *s = (nand_dev_controller_state *)opaque;
5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    nand_dev *dev;
5218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (offset) {
5238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_VERSION:
5248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return NAND_VERSION_CURRENT;
5258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_NUM_DEV:
5268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return nand_dev_count;
5278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_RESULT:
5288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return s->result;
5298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(s->dev >= nand_dev_count)
5328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
5338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dev = nand_devs + s->dev;
5358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (offset) {
5378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_DEV_FLAGS:
5388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return dev->flags;
5398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_DEV_NAME_LEN:
5418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return dev->devname_len;
5428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_DEV_PAGE_SIZE:
5448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return dev->page_size;
5458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_DEV_EXTRA_SIZE:
5478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return dev->extra_size;
5488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_DEV_ERASE_SIZE:
5508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return dev->erase_size;
5518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_DEV_SIZE_LOW:
553c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        return (uint32_t)dev->max_size;
5548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case NAND_DEV_SIZE_HIGH:
556c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije        return (uint32_t)(dev->max_size >> 32);
5578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
5598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_abort(cpu_single_env, "nand_dev_read: Bad offset %x\n", offset);
5608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
5618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic CPUReadMemoryFunc *nand_dev_readfn[] = {
5658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   nand_dev_read,
5668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   nand_dev_read,
5678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   nand_dev_read
5688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
5698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic CPUWriteMemoryFunc *nand_dev_writefn[] = {
5718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   nand_dev_write,
5728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   nand_dev_write,
5738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   nand_dev_write
5748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
5758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* initialize the QFB device */
5778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid nand_dev_init(uint32_t base)
5788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int iomemtype;
5808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    static int  instance_id = 0;
581c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    nand_dev_controller_state *s;
5828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
583c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    s = (nand_dev_controller_state *)qemu_mallocz(sizeof(nand_dev_controller_state));
5845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    iomemtype = cpu_register_io_memory(nand_dev_readfn, nand_dev_writefn, s);
5858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
5868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->base = base;
5878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    register_savevm( "nand_dev", instance_id++, NAND_DEV_STATE_SAVE_VERSION,
589c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije                      nand_dev_controller_state_save, nand_dev_controller_state_load, s);
5908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int arg_match(const char *a, const char *b, size_t b_len)
5938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while(*a && b_len--) {
5958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(*a++ != *b++)
5968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return 0;
5978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return b_len == 0;
5998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
6008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid nand_add_dev(const char *arg)
6028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
6038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint64_t dev_size = 0;
6048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const char *next_arg;
6058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const char *value;
6068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    size_t arg_len, value_len;
6078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    nand_dev *new_devs, *dev;
6088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char *devname = NULL;
6098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    size_t devname_len = 0;
6108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char *initfilename = NULL;
6118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char *rwfilename = NULL;
6128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int initfd = -1;
6138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int rwfd = -1;
6148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int read_only = 0;
6158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int pad;
6168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ssize_t read_size;
6178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t page_size = 2048;
6188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t extra_size = 64;
6198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t erase_pages = 64;
6208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while(arg) {
6228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        next_arg = strchr(arg, ',');
6238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        value = strchr(arg, '=');
6248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(next_arg != NULL) {
6258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            arg_len = next_arg - arg;
6268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            next_arg++;
6278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if(value >= next_arg)
6288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                value = NULL;
6298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
6308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else
6318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            arg_len = strlen(arg);
6328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(value != NULL) {
6338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            size_t new_arg_len = value - arg;
6348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            value_len = arg_len - new_arg_len - 1;
6358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            arg_len = new_arg_len;
6368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            value++;
6378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
6388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else
6398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            value_len = 0;
6408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(devname == NULL) {
6428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if(value != NULL)
6438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                goto bad_arg_and_value;
6448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            devname_len = arg_len;
6458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            devname = malloc(arg_len);
6468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if(devname == NULL)
6478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                goto out_of_memory;
6488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            memcpy(devname, arg, arg_len);
6498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
6508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else if(value == NULL) {
6518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if(arg_match("readonly", arg, arg_len)) {
6528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                read_only = 1;
6538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
6548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            else {
6558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                XLOG("bad arg: %.*s\n", arg_len, arg);
6568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                exit(1);
6578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
6588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
6598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else {
6608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if(arg_match("size", arg, arg_len)) {
6618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                char *ep;
6628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                dev_size = strtoull(value, &ep, 0);
6638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if(ep != value + value_len)
6648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    goto bad_arg_and_value;
6658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
6668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            else if(arg_match("pagesize", arg, arg_len)) {
6678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                char *ep;
6688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                page_size = strtoul(value, &ep, 0);
6698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if(ep != value + value_len)
6708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    goto bad_arg_and_value;
6718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
6728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            else if(arg_match("extrasize", arg, arg_len)) {
6738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                char *ep;
6748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                extra_size = strtoul(value, &ep, 0);
6758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if(ep != value + value_len)
6768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    goto bad_arg_and_value;
6778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
6788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            else if(arg_match("erasepages", arg, arg_len)) {
6798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                char *ep;
6808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                erase_pages = strtoul(value, &ep, 0);
6818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if(ep != value + value_len)
6828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    goto bad_arg_and_value;
6838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
6848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            else if(arg_match("initfile", arg, arg_len)) {
6858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                initfilename = malloc(value_len + 1);
6868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if(initfilename == NULL)
6878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    goto out_of_memory;
6888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                memcpy(initfilename, value, value_len);
6898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                initfilename[value_len] = '\0';
6908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
6918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            else if(arg_match("file", arg, arg_len)) {
6928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                rwfilename = malloc(value_len + 1);
6938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if(rwfilename == NULL)
6948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    goto out_of_memory;
6958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                memcpy(rwfilename, value, value_len);
6968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                rwfilename[value_len] = '\0';
6978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
6988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            else {
6998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                goto bad_arg_and_value;
7008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
7018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
7028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        arg = next_arg;
7048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (rwfilename == NULL) {
7078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* we create a temporary file to store everything */
7088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        TempFile*    tmp = tempfile_create();
7098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (tmp == NULL) {
7112779beecc7410f29102125e87e8174597acb2fe5Raphael            XLOG("could not create temp file for %.*s NAND disk image: %s\n",
7128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                  devname_len, devname, strerror(errno));
7138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            exit(1);
7148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
7158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        rwfilename = (char*) tempfile_path(tmp);
7168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (VERBOSE_CHECK(init))
7178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            dprint( "mapping '%.*s' NAND image to %s", devname_len, devname, rwfilename);
7188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(rwfilename) {
7218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        rwfd = open(rwfilename, O_BINARY | (read_only ? O_RDONLY : O_RDWR));
7228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(rwfd < 0 && read_only) {
7238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            XLOG("could not open file %s, %s\n", rwfilename, strerror(errno));
7248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            exit(1);
7258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
7268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* this could be a writable temporary file. use atexit_close_fd to ensure
7278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project         * that it is properly cleaned up at exit on Win32
7288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project         */
7298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (!read_only)
7308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            atexit_close_fd(rwfd);
7318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(initfilename) {
7348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        initfd = open(initfilename, O_BINARY | O_RDONLY);
7358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(initfd < 0) {
7368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            XLOG("could not open file %s, %s\n", initfilename, strerror(errno));
7378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            exit(1);
7388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
7398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if(dev_size == 0) {
7408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            dev_size = lseek(initfd, 0, SEEK_END);
7418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            lseek(initfd, 0, SEEK_SET);
7428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
7438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    new_devs = realloc(nand_devs, sizeof(nand_devs[0]) * (nand_dev_count + 1));
7468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(new_devs == NULL)
7478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto out_of_memory;
7488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    nand_devs = new_devs;
7498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dev = &new_devs[nand_dev_count];
7508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dev->page_size = page_size;
7528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dev->extra_size = extra_size;
7538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dev->erase_size = erase_pages * (page_size + extra_size);
7548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pad = dev_size % dev->erase_size;
7558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (pad != 0) {
7568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dev_size += (dev->erase_size - pad);
757acbee3546b9a380a4eb33daef3dccfac87c56b0bXavier Ducrohet        D("rounding devsize up to a full eraseunit, now %llx\n", dev_size);
7588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dev->devname = devname;
7608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dev->devname_len = devname_len;
761c51182e909275b7d89c1ed847eae40fdd8b6a33fOt ten Thije    dev->max_size = dev_size;
7628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dev->data = malloc(dev->erase_size);
7638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(dev->data == NULL)
7648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto out_of_memory;
7658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dev->flags = read_only ? NAND_DEV_FLAG_READ_ONLY : 0;
7668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (initfd >= 0) {
7688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        do {
7698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            read_size = do_read(initfd, dev->data, dev->erase_size);
7708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if(read_size < 0) {
7718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                XLOG("could not read file %s, %s\n", initfilename, strerror(errno));
7728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                exit(1);
7738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
7748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if(do_write(rwfd, dev->data, read_size) != read_size) {
7758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                XLOG("could not write file %s, %s\n", initfilename, strerror(errno));
7768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                exit(1);
7778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
7788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } while(read_size == dev->erase_size);
7798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        close(initfd);
7808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dev->fd = rwfd;
7828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    nand_dev_count++;
7848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return;
7868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectout_of_memory:
7888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    XLOG("out of memory\n");
7898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    exit(1);
7908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectbad_arg_and_value:
7928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    XLOG("bad arg: %.*s=%.*s\n", arg_len, arg, value_len, value);
7938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    exit(1);
7948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
7958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
796e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine#ifdef CONFIG_NAND_LIMITS
797e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine
798e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkinestatic uint64_t
799e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkineparse_nand_rw_limit( const char*  value )
800e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine{
801e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    char*     end;
802e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    uint64_t  val = strtoul( value, &end, 0 );
803e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine
804e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    if (end == value) {
805e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        derror( "bad parameter value '%s': expecting unsigned integer", value );
806e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        exit(1);
807e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    }
808e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine
809e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    switch (end[0]) {
810e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        case 'K':  val <<= 10; break;
811e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        case 'M':  val <<= 20; break;
812e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        case 'G':  val <<= 30; break;
813e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        case 0: break;
814e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        default:
815e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            derror( "bad read/write limit suffix: use K, M or G" );
816e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            exit(1);
817e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    }
818e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    return val;
819e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine}
820e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine
821e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkinevoid
822e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkineparse_nand_limits(char*  limits)
823e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine{
824e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    int      pid = -1, signal = -1;
825e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    int64_t  reads = 0, writes = 0;
826e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    char*    item = limits;
827e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine
828e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    /* parse over comma-separated items */
829e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    while (item && *item) {
830e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        char*  next = strchr(item, ',');
831e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        char*  end;
832e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine
833e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        if (next == NULL) {
834e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            next = item + strlen(item);
835e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        } else {
836e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            *next++ = 0;
837e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        }
838e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine
839e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        if ( !memcmp(item, "pid=", 4) ) {
840e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            pid = strtol(item+4, &end, 10);
841e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            if (end == NULL || *end) {
842e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine                derror( "bad parameter, expecting pid=<number>, got '%s'",
843e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine                        item );
844e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine                exit(1);
845e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            }
846e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            if (pid <= 0) {
847e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine                derror( "bad parameter: process identifier must be > 0" );
848e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine                exit(1);
849e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            }
850e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        }
851e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        else if ( !memcmp(item, "signal=", 7) ) {
852e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            signal = strtol(item+7,&end, 10);
853e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            if (end == NULL || *end) {
854e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine                derror( "bad parameter: expecting signal=<number>, got '%s'",
855e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine                        item );
856e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine                exit(1);
857e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            }
858e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            if (signal <= 0) {
859e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine                derror( "bad parameter: signal number must be > 0" );
860e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine                exit(1);
861e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            }
862e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        }
863e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        else if ( !memcmp(item, "reads=", 6) ) {
864e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            reads = parse_nand_rw_limit(item+6);
865e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        }
866e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        else if ( !memcmp(item, "writes=", 7) ) {
867e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            writes = parse_nand_rw_limit(item+7);
868e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        }
869e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        else {
870e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            derror( "bad parameter '%s' (see -help-nand-limits)", item );
871e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine            exit(1);
872e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        }
873e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        item = next;
874e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    }
875e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    if (pid < 0) {
876e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        derror( "bad paramater: missing pid=<number>" );
877e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        exit(1);
878e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    }
879e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    else if (signal < 0) {
880e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        derror( "bad parameter: missing signal=<number>" );
881e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        exit(1);
882e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    }
883e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    else if (reads == 0 && writes == 0) {
884e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        dwarning( "no read or write limit specified. ignoring -nand-limits" );
885e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    } else {
886e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        nand_threshold*  t;
887e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine
888e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        t  = &android_nand_read_threshold;
889e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        t->pid     = pid;
890e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        t->signal  = signal;
891e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        t->counter = 0;
892e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        t->limit   = reads;
893e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine
894e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        t  = &android_nand_write_threshold;
895e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        t->pid     = pid;
896e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        t->signal  = signal;
897e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        t->counter = 0;
898e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine        t->limit   = writes;
899e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine    }
900e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine}
901e13168648d5947955e0fd4fbf396f891ae53921fVladimir Chtchetkine#endif /* CONFIG_NAND_LIMITS */
902