diff options
| author | ahoka <ahoka@NetBSD.org> | 2011-02-26 18:07:13 +0000 |
|---|---|---|
| committer | ahoka <ahoka@NetBSD.org> | 2011-02-26 18:07:13 +0000 |
| commit | b84aee73028fe564bfa78c0c2c568359ca7288a8 (patch) | |
| tree | fe512736abd91f2864d5b0021de9e4af277634cd /sys/dev/flash | |
| parent | 11ce3c28dd5240489a3d69366d65cc854b754c35 (diff) | |
Import the Flash and NAND subsytem code contributed by the University
of Szeged, Hungary.
The commit includes:
- Flash layer, which gives a common API to access flash devices
- NAND controller subsystem for the flash layer
- An example OMAP driver which is used on BeagleBoard or alike ARM boards
Diffstat (limited to 'sys/dev/flash')
| -rw-r--r-- | sys/dev/flash/files.flash | 9 | ||||
| -rw-r--r-- | sys/dev/flash/flash.c | 695 | ||||
| -rw-r--r-- | sys/dev/flash/flash.h | 168 |
3 files changed, 872 insertions, 0 deletions
diff --git a/sys/dev/flash/files.flash b/sys/dev/flash/files.flash new file mode 100644 index 00000000000..7871e2d9031 --- /dev/null +++ b/sys/dev/flash/files.flash @@ -0,0 +1,9 @@ +# $NetBSD: files.flash,v 1.1 2011/02/26 18:07:30 ahoka Exp $ + +define flashbus { [offset = 0], [size = 0], [readonly = 0] } + +device flash +attach flash at flashbus +file dev/flash/flash.c flash + +defflag opt_flash.h FLASH_STATIC_PARTITIONS diff --git a/sys/dev/flash/flash.c b/sys/dev/flash/flash.c new file mode 100644 index 00000000000..33007cfe339 --- /dev/null +++ b/sys/dev/flash/flash.c @@ -0,0 +1,695 @@ +/* $NetBSD: flash.c,v 1.1 2011/02/26 18:07:30 ahoka Exp $ */ + +/*- + * Copyright (c) 2011 Department of Software Engineering, + * University of Szeged, Hungary + * Copyright (c) 2011 Adam Hoka <ahoka@NetBSD.org> + * Copyright (c) 2010 David Tengeri <dtengeri@inf.u-szeged.hu> + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by the Department of Software Engineering, University of Szeged, Hungary + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*- + * Framework for storage devices based on Flash technology + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: flash.c,v 1.1 2011/02/26 18:07:30 ahoka Exp $"); + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/proc.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/device.h> +#include <sys/conf.h> +#include <sys/kmem.h> +#include <sys/uio.h> +#include <sys/kernel.h> + +#include <sys/atomic.h> +#include <sys/buf.h> +#include <sys/bufq.h> +#include <sys/disk.h> +#include <sys/disklabel.h> +#include <sys/malloc.h> +#include <sys/reboot.h> + +#include <sys/flashio.h> +#include "flash.h" + +#define FLASH_DEBUG 1 +#ifdef FLASH_DEBUG +#define DPRINTF(x) if (flashdebug) printf x +#define DPRINTFN(n,x) if (flashdebug>(n)) printf x +int flashdebug = FLASH_DEBUG; +#else +#define DPRINTF(x) +#define DPRINTFN(n,x) +#endif + +extern struct cfdriver flash_cd; + +dev_type_open(flashopen); +dev_type_close(flashclose); +dev_type_read(flashread); +dev_type_write(flashwrite); +dev_type_ioctl(flashioctl); +dev_type_strategy(flashstrategy); +dev_type_dump(flashdump); +dev_type_size(flashsize); + +int flash_print(void *aux, const char *pnp); + +bool flash_shutdown(device_t dev, int how); +int flash_nsectors(struct buf *bp); +int flash_sector(struct buf *bp); + +static inline off_t flash_get_part_offset(struct flash_softc *fl, + size_t poffset); + +int flash_match(device_t parent, cfdata_t match, void *aux); +void flash_attach(device_t parent, device_t self, void *aux); +int flash_detach(device_t device, int flags); + +CFATTACH_DECL_NEW(flash, sizeof(struct flash_softc), + flash_match, flash_attach, flash_detach, NULL); + +/** + * Block device's operation + */ +const struct bdevsw flash_bdevsw = { + .d_open = flashopen, + .d_close = flashclose, + .d_strategy = flashstrategy, + .d_ioctl = flashioctl, + .d_dump = flashdump, + .d_psize = flashsize, + .d_flag = D_DISK | D_MPSAFE +}; + +/** + * Character device's operations + */ +const struct cdevsw flash_cdevsw = { + .d_open = flashopen, + .d_close = flashclose, + .d_read = flashread, + .d_write = flashwrite, + .d_ioctl = flashioctl, + .d_stop = nostop, + .d_tty = notty, + .d_poll = nopoll, + .d_mmap = nommap, + .d_kqfilter = nokqfilter, + .d_flag = D_DISK | D_MPSAFE +}; + +/* ARGSUSED */ +int +flash_match(device_t parent, cfdata_t match, void *aux) +{ + /* pseudo device, always attaches */ + return 1; +} + +/* ARGSUSED */ +void +flash_attach(device_t parent, device_t self, void *aux) +{ + struct flash_softc *sc = device_private(self); + struct flash_attach_args *faa = aux; + char pbuf[2][sizeof("9999 KB")]; + + sc->sc_dev = self; + sc->sc_parent_dev = parent; + sc->flash_if = faa->flash_if; + sc->hw_softc = device_private(parent); + + format_bytes(pbuf[0], sizeof(pbuf[0]), sc->flash_if->size); + format_bytes(pbuf[1], sizeof(pbuf[1]), sc->flash_if->erasesize); + + aprint_naive("\n"); + + switch (sc->flash_if->type) { + case FLASH_TYPE_NOR: + aprint_normal(": %s NOR flash\n", pbuf[0]); + break; + + case FLASH_TYPE_NAND: + aprint_normal(": %s NAND flash\n", pbuf[0]); + break; + + default: + aprint_normal(": %s unknown flash\n", pbuf[0]); + } + + aprint_normal_dev(sc->sc_dev, + "size: 0x%jx, offset: 0x%jx", + (uintmax_t )sc->flash_if->partition.part_size, + (uintmax_t )sc->flash_if->partition.part_offset); + + if (sc->flash_if->partition.part_flags & FLASH_PART_READONLY) { + sc->sc_readonly = true; + aprint_normal(", read only"); + } else { + sc->sc_readonly = false; + } + + aprint_normal("\n"); + + if (sc->flash_if->partition.part_size == 0) { + aprint_error_dev(self, + "partition size must be larger than 0\n"); + return; + } + + switch (sc->flash_if->type) { + case FLASH_TYPE_NOR: + aprint_normal_dev(sc->sc_dev, + "erase size %s bytes, write size %d bytes\n", + pbuf[1], sc->flash_if->writesize); + break; + + case FLASH_TYPE_NAND: + default: + aprint_normal_dev(sc->sc_dev, + "erase size %s, page size %d bytes, write size %d bytes\n", + pbuf[1], sc->flash_if->page_size, + sc->flash_if->writesize); + break; + } + + if (!pmf_device_register1(sc->sc_dev, NULL, NULL, flash_shutdown)) + aprint_error_dev(sc->sc_dev, + "couldn't establish power handler\n"); +} + +int +flash_detach(device_t device, int flags) +{ + struct flash_softc *sc = device_private(device); + + pmf_device_deregister(sc->sc_dev); + + /* freeing flash_if is our responsibility */ + printf("freeing flash_if..."); + kmem_free(sc->flash_if, sizeof(*sc->flash_if)); + printf("done!\n"); + + return 0; +} + +int +flash_print(void *aux, const char *pnp) +{ + struct flash_attach_args *arg; + const char *type; + + if (pnp != NULL) { + arg = aux; + switch (arg->flash_if->type) { + case FLASH_TYPE_NOR: + type = "NOR"; + break; + case FLASH_TYPE_NAND: + type = "NAND"; + break; + default: + panic("flash_print: unknown type %d", + arg->flash_if->type); + } + aprint_normal("%s flash at %s", type, pnp); + } + return UNCONF; +} + +device_t +flash_attach_mi(struct flash_interface *flash_if, device_t device) +{ + struct flash_attach_args arg; + +#ifdef DIAGNOSTIC + if (flash_if == NULL) { + aprint_error("flash_attach_mi: NULL\n"); + return 0; + } +#endif + arg.flash_if = flash_if; + + return config_found_ia(device, "flashbus", &arg, flash_print); +} + +/** + * flash_open - open the character device + * Checks if there is a driver registered to the minor number of the open + * request. + */ +int +flashopen(dev_t dev, int flags, int fmt, struct lwp *l) +{ + int unit = minor(dev); + struct flash_softc *sc; + + DPRINTFN(1, ("flash: opening device unit %d\n", unit)); + + if ((sc = device_lookup_private(&flash_cd, unit)) == NULL) + return ENXIO; + + /* TODO return eperm if want to open for writing a read only dev */ + + /* reset buffer length */ +// sc->sc_cache->fc_len = 0; + + return 0; +} + +/** + * flash_close - close device + * We don't have to release any resources, so just return 0. + */ +int +flashclose(dev_t dev, int flags, int fmt, struct lwp *l) +{ + int unit = minor(dev); + struct flash_softc *sc; + int err; + + DPRINTFN(1, ("flash: closing flash device unit %d\n", unit)); + + if ((sc = device_lookup_private(&flash_cd, unit)) == NULL) + return ENXIO; + + if (!sc->sc_readonly) { + err = flash_sync(sc->sc_dev); + if (err) + return err; + } + + return 0; +} + +/** + * flash_read - read from character device + * This function uses the registered driver's read function to read the requested length to + * a buffer and then moves this buffer to userspace. + */ +int +flashread(dev_t dev, struct uio *uio, int flag) +{ + return physio(flashstrategy, NULL, dev, B_READ, minphys, uio); +} + +/** + * flash_write - write to character device + * This function moves the data into a buffer from userspace to kernel space, + * then uses the registered driver's write function to write out the data to + * the media. + */ +int +flashwrite(dev_t dev, struct uio *uio, int flag) +{ + return physio(flashstrategy, NULL, dev, B_WRITE, minphys, uio); +} + +void +flashstrategy(struct buf *bp) +{ + struct flash_softc *sc; + const struct flash_interface *flash_if; + const struct flash_partition *part; + int unit, device_blks; + + unit = minor(bp->b_dev); + sc = device_lookup_private(&flash_cd, unit); + if (sc == NULL) { + bp->b_error = ENXIO; + goto done; + } + + flash_if = sc->flash_if; + part = &flash_if->partition; + + /* divider */ + KASSERT(flash_if->writesize != 0); + + aprint_debug_dev(sc->sc_dev, "flash_strategy()\n"); + + if (!(bp->b_flags & B_READ) && sc->sc_readonly) { + bp->b_error = EACCES; + goto done; + } + + /* check if length is not negative */ + if (bp->b_blkno < 0) { + bp->b_error = EINVAL; + goto done; + } + + /* zero lenght i/o */ + if (bp->b_bcount == 0) { + goto done; + } + + device_blks = sc->flash_if->size / DEV_BSIZE; + KASSERT(part->part_offset % DEV_BSIZE == 0); + bp->b_rawblkno = bp->b_blkno + (part->part_offset / DEV_BSIZE); + + if (bounds_check_with_mediasize(bp, DEV_BSIZE, device_blks) <= 0) { + goto done; + } + + bp->b_resid = bp->b_bcount; + flash_if->submit(sc->sc_parent_dev, bp); + + return; +done: + bp->b_resid = bp->b_bcount; + biodone(bp); +} + +/* + * Handle the ioctl for the device + */ +int +flashioctl(dev_t dev, u_long command, void *data, int flags, struct lwp *l) +{ + struct flash_erase_params *ep; + struct flash_info_params *ip; + struct flash_dump_params *dp; + struct flash_badblock_params *bbp; + struct flash_erase_instruction ei; + struct flash_softc *sc; + int unit, err; + size_t retlen; + flash_addr_t offset; + + unit = minor(dev); + if ((sc = device_lookup_private(&flash_cd, unit)) == NULL) + return ENXIO; + + err = 0; + switch (command) { + case FLASH_ERASE_BLOCK: + /** + * Set up an erase instruction then call the registered + * driver's erase operation. + */ + ep = data; + + if (sc->sc_readonly) { + return EACCES; + } + + ei.ei_addr = ep->ep_addr; + ei.ei_len = ep->ep_len; + ei.ei_callback = NULL; + + err = flash_erase(sc->sc_dev, &ei); + if (err) { + return err; + } + + break; + case FLASH_BLOCK_ISBAD: + /** + * Set up an erase instruction then call the registered + * driver's erase operation. + */ + bbp = data; + + err = flash_block_isbad(sc->sc_dev, bbp->bbp_addr); + if (err == EIO) { + bbp->bbp_isbad = true; + err = 0; + } else if (err) { + return err; + } else { + bbp->bbp_isbad = false; + } + + break; + case FLASH_BLOCK_MARKBAD: + bbp = data; + + err = flash_block_markbad(sc->sc_dev, bbp->bbp_addr); + + break; + case FLASH_DUMP: + dp = data; + offset = dp->dp_block * sc->flash_if->erasesize; + DPRINTF(("Reading from block: %jd len: %jd\n", + (intmax_t )dp->dp_block, (intmax_t )dp->dp_len)); + err = flash_read(sc->sc_parent_dev, offset, dp->dp_len, + &retlen, dp->dp_buf); + if (err) + return err; + if (retlen != dp->dp_len) { + dp->dp_len = -1; + dp->dp_buf = NULL; + } + + break; + case FLASH_GET_INFO: + ip = data; + + ip->ip_page_size = sc->flash_if->page_size; + ip->ip_erase_size = sc->flash_if->erasesize; + ip->ip_flash_type = sc->flash_if->type; + ip->ip_flash_size = sc->flash_if->size; + break; + default: + err = ENODEV; + } + + return err; +} +int +flashsize(dev_t dev) +{ + return -1; +} + +int +flashdump(dev_t dev, daddr_t blkno, void *va, size_t size) +{ + return EACCES; +} + +bool +flash_shutdown(device_t self, int how) +{ + struct flash_softc *sc = device_private(self); + + if ((how & RB_NOSYNC) == 0 && !sc->sc_readonly) + flash_sync(self); + + return true; +} + +const struct flash_interface * +flash_get_interface(dev_t dev) +{ + struct flash_softc *sc; + int unit; + + unit = minor(dev); + if ((sc = device_lookup_private(&flash_cd, unit)) == NULL) + return NULL; + + return sc->flash_if; +} + +const struct flash_softc * +flash_get_softc(dev_t dev) +{ + struct flash_softc *sc; + int unit; + + unit = minor(dev); + sc = device_lookup_private(&flash_cd, unit); + + return sc; +} + +device_t +flash_get_device(dev_t dev) +{ + struct flash_softc *sc; + int unit; + + unit = minor(dev); + sc = device_lookup_private(&flash_cd, unit); + + return sc->sc_dev; +} + +static inline off_t +flash_get_part_offset(struct flash_softc *fl, size_t poffset) +{ + return fl->flash_if->partition.part_offset + poffset; +} + +int +flash_erase(device_t self, struct flash_erase_instruction *ei) +{ + struct flash_softc *sc = device_private(self); + KASSERT(ei != NULL); + struct flash_erase_instruction e = *ei; + + if (sc->sc_readonly) + return EACCES; + + /* adjust for flash partition */ + e.ei_addr += sc->flash_if->partition.part_offset; + + /* bounds check for flash partition */ + if (e.ei_addr + e.ei_len > sc->flash_if->partition.part_size + + sc->flash_if->partition.part_offset) + return EINVAL; + + return sc->flash_if->erase(device_parent(self), &e); +} + +int +flash_read(device_t self, + off_t offset, size_t len, size_t *retlen, uint8_t *buf) +{ + struct flash_softc *sc = device_private(self); + + offset += sc->flash_if->partition.part_offset; + + if (offset + len > sc->flash_if->partition.part_size + + sc->flash_if->partition.part_offset) + return EINVAL; + + return sc->flash_if->read(device_parent(self), + offset, len, retlen, buf); +} + +int +flash_write(device_t self, + off_t offset, size_t len, size_t *retlen, const uint8_t *buf) +{ + struct flash_softc *sc = device_private(self); + + if (sc->sc_readonly) + return EACCES; + + offset += sc->flash_if->partition.part_offset; + + if (offset + len > sc->flash_if->partition.part_size + + sc->flash_if->partition.part_offset) + return EINVAL; + + return sc->flash_if->write(device_parent(self), + offset, len, retlen, buf); +} + +int +flash_block_markbad(device_t self, uint64_t offset) +{ + struct flash_softc *sc = device_private(self); + + if (sc->sc_readonly) + return EACCES; + + offset += sc->flash_if->partition.part_offset; + + if (offset + sc->flash_if->erasesize >= + sc->flash_if->partition.part_size + + sc->flash_if->partition.part_offset) + return EINVAL; + + return sc->flash_if->block_markbad(device_parent(self), offset); +} + +int +flash_block_isbad(device_t self, uint64_t offset) +{ + struct flash_softc *sc = device_private(self); + + offset += sc->flash_if->partition.part_offset; + + if (offset + sc->flash_if->erasesize > + sc->flash_if->partition.part_size + + sc->flash_if->partition.part_offset) + return EINVAL; + + return sc->flash_if->block_isbad(device_parent(self), offset); +} + +int +flash_sync(device_t self) +{ + struct flash_softc *sc = device_private(self); + + if (sc->sc_readonly) + return EACCES; + + /* noop now TODO: implement */ + return 0; +} + +MODULE(MODULE_CLASS_DRIVER, flash, NULL); + +#ifdef _MODULE +#include "ioconf.c" +#endif + +static int +flash_modcmd(modcmd_t cmd, void *opaque) +{ + int error = 0; +#ifdef _MODULE + int bmaj = -1, cmaj = -1; +#endif + + switch (cmd) { + case MODULE_CMD_INIT: +#ifdef _MODULE + error = config_init_component(cfdriver_ioconf_flash, + cfattach_ioconf_flash, cfdata_ioconf_flash); + if (error) + return error; + error = devsw_attach("flash", &flash_bdevsw, &bmaj, + &flash_cdevsw, &cmaj); + if (error) + config_fini_component(cfdriver_ioconf_flash, + cfattach_ioconf_flash, cfdata_ioconf_flash); +#endif + return error; + case MODULE_CMD_FINI: +#ifdef _MODULE + devsw_detach(&flash_bdevsw, &flash_cdevsw); + error = config_fini_component(cfdriver_ioconf_flash, + cfattach_ioconf_flash, cfdata_ioconf_flash); +#endif + return error; + default: + return ENOTTY; + } +} diff --git a/sys/dev/flash/flash.h b/sys/dev/flash/flash.h new file mode 100644 index 00000000000..ead0b3cda27 --- /dev/null +++ b/sys/dev/flash/flash.h @@ -0,0 +1,168 @@ +/* $NetBSD: flash.h,v 1.1 2011/02/26 18:07:30 ahoka Exp $ */ + +/*- + * Copyright (c) 2011 Department of Software Engineering, + * University of Szeged, Hungary + * Copyright (c) 2011 Adam Hoka <ahoka@NetBSD.org> + * Copyright (c) 2010 David Tengeri <dtengeri@inf.u-szeged.hu> + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by the Department of Software Engineering, University of Szeged, Hungary + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _FLASH_H_ +#define _FLASH_H_ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/module.h> +#include <sys/buf.h> +#include <sys/flashio.h> + +/** + * flash_softc - private structure for flash layer driver + */ + +struct flash_softc { + device_t sc_dev; + device_t sc_parent_dev; /* Hardware (parent) device */ + void *hw_softc; /* Hardware device private softc */ + struct flash_interface *flash_if; /* Hardware interface */ + + bool sc_readonly; /* read only flash device */ +}; + +struct flash_attach_args { + struct flash_interface *flash_if; /* Hardware interface */ +}; + +device_t flash_attach_mi(struct flash_interface *, device_t); +const struct flash_interface *flash_get_interface(dev_t); +const struct flash_softc *flash_get_softc(dev_t); +device_t flash_get_device(dev_t); + +/** + * struct erase_instruction - instructions to erase a flash eraseblock + * @fd: flash descriptor + * @addr: start address of the erase operation + * @len: the erase length + * @callback: callback operation, called when erase finished + * @priv: private data + * @state: the erase operation's result + */ +struct flash_erase_instruction { + flash_addr_t ei_addr; + flash_addr_t ei_len; + void (*ei_callback) (struct flash_erase_instruction *); + u_long ei_priv; + u_char ei_state; +}; + +enum { + FLASH_PART_READONLY = (1<<0), + FLASH_PART_FILESYSTEM = (1<<2) +}; + +struct flash_partition { + flash_addr_t part_offset; + flash_addr_t part_size; + int part_flags; +}; + +/** + * struct flash_interface - interface for flash operations + * @type: type of flash device + * @size: size of flash + * @page_size: page size of flash + * @erasesize: erase size of flash + * @writesize: minimum write size of flash + * @minor: minor number of the character device attached to this driver + * @erase: erase operation of the flash + * @read: read operation of the flash + * @write: write operation of the flash + * @block_markbad: marks a block as bad on the flash + * @block_isbad: checks if a block is bad on flash + */ +struct flash_interface { + int (*erase) (device_t, struct flash_erase_instruction *); + int (*read) (device_t, off_t, size_t, size_t *, uint8_t *); + int (*write) (device_t, off_t, size_t, size_t *, const uint8_t *); + int (*block_markbad)(device_t, uint64_t); + int (*block_isbad)(device_t, uint64_t); + int (*sync) (device_t); + + int (*submit)(device_t, struct buf *); + + /* storage for partition info */ + struct flash_partition partition; + + /* total size of mtd */ + flash_addr_t size; + uint32_t page_size; + uint32_t erasesize; + uint32_t writesize; + uint32_t minor; + uint8_t type; +}; + +/** + * struct cache - for caching writes on block device + */ +struct flash_cache { + size_t fc_len; + flash_addr_t fc_block; + uint8_t *fc_data; +}; + +/* flash operations should be used through these */ +int flash_erase(device_t, struct flash_erase_instruction *); +int flash_read(device_t, off_t, size_t, size_t *, uint8_t *); +int flash_write(device_t, off_t, size_t, size_t *, const uint8_t *); +int flash_block_markbad(device_t, uint64_t); +int flash_block_isbad(device_t, uint64_t); +int flash_sync(device_t); + +/* + * check_pattern - checks the buffer only contains the byte pattern + * @buf: the buffer to check + * @patt: the pattern to match + * @offset: the starting byte number, the matching starts from here + * @size: the buffer size + * + * This functions checks if the buffer only contains a specified byte pattern. + * Returns %0 if found something else, %1 otherwise. + */ +static inline int +check_pattern(const void *buf, uint8_t patt, size_t offset, size_t size) +{ + size_t i; + for (i = offset; i < size; i++) { + if (((const uint8_t *) buf)[i] != patt) + return 0; + } + return 1; +} + +#endif /* _FLASH_H_ */ |
