/*
 * device.h
 *
 * Copyright (C) 2016 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 _DEVICE_H_
#define _DEVICE_H_

#include <common.h>
#include <lock.h>
#include <cache.h>
#include <filesystem.h>
#include <sdk/list.h>
#include <sdk/device.h>

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

typedef dword_t (*device_init_proc_t)(void);
typedef dword_t (*device_cleanup_proc_t)(void);
typedef dword_t (*device_ioctl_proc_t)(
    device_t *device,
    dword_t control_code,
    const void *in_buffer,
    size_t in_length,
    void *out_buffer,
    size_t out_length
);

typedef dword_t (*block_dev_read_proc_t)(device_t *device, void *buffer, qword_t offset, size_t length, size_t *bytes_read);
typedef dword_t (*block_dev_write_proc_t)(device_t *device, const void *buffer, qword_t offset, size_t length, size_t *bytes_written);

typedef dword_t (*char_dev_read_proc_t)(device_t *device, void *buffer, size_t length, size_t *bytes_read);
typedef dword_t (*char_dev_write_proc_t)(device_t *device, const void *buffer, size_t length, size_t *bytes_written);

typedef struct
{
    list_entry_t list;
    dword_t mounted_devices;
    device_init_proc_t init_proc;
    device_cleanup_proc_t cleanup_proc;
    block_dev_read_proc_t read_proc;
    block_dev_write_proc_t write_proc;
    device_ioctl_proc_t ioctl_proc;
} block_dev_driver_t;

typedef struct
{
    list_entry_t list;
    device_init_proc_t init_proc;
    device_cleanup_proc_t cleanup_proc;
    char_dev_read_proc_t read_proc;
    char_dev_write_proc_t write_proc;
    device_ioctl_proc_t ioctl_proc;
} char_dev_driver_t;

typedef struct device
{
    list_entry_t list;
    device_type_t type;
    char name[MAX_DEVICE_NAME];
    lock_t lock;
    dword_t flags;
    qword_t capacity;

    union
    {
        void *driver;
        block_dev_driver_t *block_driver;
        char_dev_driver_t *char_driver;
    };
} device_t;

typedef struct
{
    dword_t heads;
    dword_t tracks;
    dword_t sectors_per_track;
    dword_t bytes_per_sector;
} block_dev_media_info_t;

typedef struct
{
    file_t header;
    device_t *device;
} device_file_t;

typedef struct
{
    file_instance_t header;
    device_t *next_device;
} device_dir_inst_t;

device_t *get_block_device(const char *name);
dword_t register_block_dev_driver(block_dev_driver_t *driver);
dword_t unregister_block_dev_driver(block_dev_driver_t *driver);
dword_t register_block_device(device_t *device);
dword_t unregister_block_device(device_t *device);
device_t *get_char_device(const char *name);
dword_t register_char_dev_driver(char_dev_driver_t *driver);
dword_t unregister_char_dev_driver(char_dev_driver_t *driver);
dword_t register_char_device(device_t *device);
dword_t unregister_char_device(device_t *device);
dword_t device_read(device_t *device, void *buffer, qword_t offset, size_t length, size_t *bytes_read);
dword_t device_write(device_t *device, const void *buffer, qword_t offset, size_t length, size_t *bytes_written);
dword_t device_ioctl_internal(device_t *device, dword_t control_code, const void *in_buffer, size_t in_length, void *out_buffer, size_t out_length);
void device_init(void);

#endif
