/*
 * cache.h
 *
 * Copyright (C) 2013 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _CACHE_H_
#define _CACHE_H_

#include <common.h>
#include <lock.h>
#include <device.h>
#include <sdk/avltree.h>

#define CACHE_WRITE_THROUGH (1 << 0)

typedef dword_t (*read_write_buffer_proc_t)(void *context, void *buffer, qword_t offset, size_t length, size_t *bytes_read_or_written);

typedef struct
{
    avl_node_t node;
    qword_t address;
    bool_t dirty;
    byte_t data[VARIABLE_SIZE];
} cache_entry_t;

#ifndef DEVICE_TYPEDEF
#define DEVICE_TYPEDEF
typedef struct device device_t;
#endif

typedef struct
{
    bool_t enabled;
    lock_t lock;
    dword_t flags;
    dword_t block_size;
    read_write_buffer_proc_t read_proc, write_proc;
    avl_tree_t entries;
} cache_descriptor_t;

void init_cache(cache_descriptor_t *cache,
                dword_t flags,
                dword_t block_size,
                read_write_buffer_proc_t read_proc,
                read_write_buffer_proc_t write_proc);
void cleanup_cache(cache_descriptor_t *cache);
dword_t read_cache(cache_descriptor_t *cache, void *context, byte_t *buffer, qword_t offset, dword_t length, dword_t *bytes_read);
dword_t write_cache(cache_descriptor_t *cache, void *context, const byte_t *buffer, qword_t offset, dword_t length, dword_t *bytes_written);
dword_t flush_cache(cache_descriptor_t *cache, void *context);

#endif
