/***************************************************************************
 *   Copyright (C) 2007 by Arep                                            *
 *   Support is provided through the forums at                             *
 *   http://wii.console-tribe.com                                          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 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 General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifndef DVD_DRIVE_H_INCLUDED
#define DVD_DRIVE_H_INCLUDED

#include "misc.h"
#include <sys/types.h>


typedef struct dvd_drive_s dvd_drive;


typedef enum {
	DVD_VOLUME_LOCK_OK = 0,
	DVD_VOLUME_LOCK_UNAVAILABLE = 1,
	DVD_VOLUME_LOCK_FAILED = -1
} dvd_volume_lock_result;

typedef struct {
	int sense_key;
	int asc;
	int ascq;
} req_sense;

/* Snapshot of the most recently executed MMC command.  This is retained even
 * when the caller requested quiet error handling so release builds can report
 * actionable seed/cache transport diagnostics without enabling DEBUG/VERBOSE. */
typedef struct {
	bool valid;
	int transport_result;
	int os_error;
	int scsi_status;
	int sense_key;
	int asc;
	int ascq;
	int cdb_length;
	u_int8_t cdb[12];
} dvd_command_diagnostic;

/* Read-only metadata for an exact HLDS/MN103 0xE7 profile match.
 * Static firmware addresses are diagnostic evidence only. FriiDump does not
 * execute these addresses or issue firmware-write commands through this API. */
typedef struct {
	u_int32_t type;
	u_int32_t cache_base;
	u_int32_t mem_blocks;
	int preferred_method;
	const char *label;
	const char *support_tier;
	const char *family;
	const char *tokens;
	const char *record_id;
	u_int32_t static_cdb_base;
	u_int32_t static_gate;
	const char *notes;
} dvd_hlds_e7_profile_info;


typedef enum {
	DVD_DATA_NONE = 0,
	DVD_DATA_IN = 1,
	DVD_DATA_OUT = 2
} dvd_data_direction;

typedef struct {
	u_int8_t cmd[12];
	int cmdlen;
	dvd_data_direction direction;
	req_sense *sense;
	u_int8_t *buffer;
	int buflen;
} mmc_command;


/* Functions */
dvd_drive *dvd_drive_new (char *device, u_int32_t command);
void *dvd_drive_destroy (dvd_drive *d);
int dvd_read_sector_dummy (dvd_drive *dvd, u_int32_t sector, u_int32_t sectors, req_sense *sense, u_int8_t *extbuf, size_t extbufsize);
int dvd_read_sector_streaming (dvd_drive *dvd, u_int32_t sector, req_sense *sense, u_int8_t *extbuf, size_t extbufsize);
int dvd_read_streaming (dvd_drive *dvd, u_int32_t sector, u_int32_t sectors, req_sense *sense, u_int8_t *extbuf, size_t extbufsize);
int dvd_flush_cache_READ12 (dvd_drive *dvd, u_int32_t sector, req_sense *sense);
int dvd_start_stop_unit (dvd_drive *dvd, bool start, bool load_eject, req_sense *sense);
int dvd_set_door_lock (dvd_drive *dvd, bool locked);
int dvd_stop_unit (dvd_drive *dvd, bool start, req_sense *sense);
int dvd_media_cycle (dvd_drive *dvd, req_sense *sense);
int dvd_wait_ready (dvd_drive *dvd, unsigned int timeout_ms);
int dvd_test_unit_ready (dvd_drive *dvd, req_sense *sense);
int dvd_read_capacity_10 (dvd_drive *dvd, u_int32_t *sectors, u_int32_t *sector_size, req_sense *sense);
int dvd_read_10 (dvd_drive *dvd, u_int32_t sector, u_int32_t sectors, req_sense *sense, u_int8_t *extbuf, size_t extbufsize);
int dvd_mode_sense_10 (dvd_drive *dvd, u_int8_t page, u_int8_t *extbuf, size_t extbufsize, req_sense *sense);
int dvd_mode_select_10 (dvd_drive *dvd, const u_int8_t *buf, size_t bufsize, req_sense *sense);
int dvd_mode_select_6 (dvd_drive *dvd, const u_int8_t *buf, size_t bufsize, req_sense *sense);
int dvd_read_dvd_structure (dvd_drive *dvd, u_int8_t format, u_int8_t layer, u_int8_t *extbuf, size_t extbufsize, req_sense *sense);
int dvd_xbox_gdr8050l_unlock (dvd_drive *dvd, u_int32_t *unlocked_sectors);
int dvd_xbox_vendor_lock (dvd_drive *dvd);
int dvd_xbox_vendor_unlock_wxripper (dvd_drive *dvd, u_int32_t *unlocked_sectors);
int dvd_xbox_vendor_set_error_skip (dvd_drive *dvd, bool enabled);
int dvd_xbox_prepare_game_view (dvd_drive *dvd, u_int32_t *sectors, u_int32_t *sector_size);
int dvd_refresh_volume (dvd_drive *dvd);
int dvd_lock_volume (dvd_drive *dvd);
int dvd_xbox_refresh_volume (dvd_drive *dvd);
int dvd_xbox_lock_volume (dvd_drive *dvd);
bool dvd_is_xbox_drive (dvd_drive *dvd);
bool dvd_is_xbox_unlock_drive (dvd_drive *dvd);
bool dvd_is_xbox_challenge_drive (dvd_drive *dvd);
bool dvd_is_xbox_vendor_unlock_drive (dvd_drive *dvd);
int dvd_set_speed (dvd_drive *dvd, u_int32_t speed, req_sense *sense);
int dvd_get_size (dvd_drive *dvd, u_int32_t *size, req_sense *sense);
int dvd_get_layerbreak (dvd_drive *dvd, u_int32_t *layerbreak, req_sense *sense);
int dvd_set_streaming (dvd_drive *dvd, u_int32_t speed, req_sense *sense);
int dvd_memdump (dvd_drive *dvd, u_int32_t block_off, u_int32_t block_len, u_int32_t block_size, u_int8_t *buf);
char *dvd_get_vendor (dvd_drive *dvd);
char *dvd_get_product_id (dvd_drive *dvd);
char *dvd_get_product_revision (dvd_drive *dvd);
char *dvd_get_model_string (dvd_drive *dvd);
char *dvd_get_device (dvd_drive *dvd);
void *dvd_get_native_handle (dvd_drive *dvd);
bool dvd_get_support_status (dvd_drive *dvd);
u_int32_t dvd_get_def_method (dvd_drive *dvd);
u_int32_t dvd_get_command (dvd_drive *dvd);
bool dvd_lookup_hlds_e7_profile (
	const char *vendor,
	const char *product_id,
	const char *revision,
	dvd_hlds_e7_profile_info *out
);
u_int32_t dvd_detect_hlds_e7_type_for_identity (
	const char *vendor,
	const char *product_id,
	const char *revision
);
const char *dvd_get_hlds_e7_profile_name (dvd_drive *dvd);
const char *dvd_get_hlds_e7_support_tier (dvd_drive *dvd);
const char *dvd_get_hlds_e7_family (dvd_drive *dvd);
const char *dvd_get_hlds_e7_tokens (dvd_drive *dvd);
const char *dvd_get_hlds_e7_record_id (dvd_drive *dvd);
const char *dvd_get_hlds_e7_notes (dvd_drive *dvd);
u_int32_t dvd_get_hlds_e7_type (dvd_drive *dvd);
u_int32_t dvd_get_hlds_e7_cache_base (dvd_drive *dvd);
u_int32_t dvd_get_hlds_e7_mem_blocks (dvd_drive *dvd);
u_int32_t dvd_get_hlds_e7_static_cdb_base (dvd_drive *dvd);
u_int32_t dvd_get_hlds_e7_static_gate (dvd_drive *dvd);
int dvd_get_hlds_e7_preferred_method (dvd_drive *dvd);
void dvd_set_hlds_e7_runtime_profile (dvd_drive *dvd, u_int32_t type, u_int32_t cache_base, u_int32_t mem_blocks);

/* The following are exported for use by drive-specific functions */
typedef int (*dvd_drive_memdump_func) (dvd_drive *dvd, u_int32_t block_off, u_int32_t block_len, u_int32_t block_size, u_int8_t *buf);
void dvd_init_command (mmc_command *mmc, u_int8_t *buf, int len, req_sense *sense);
int dvd_execute_cmd (dvd_drive *dvd, mmc_command *mmc, bool ignore_errors);
bool dvd_get_last_command_diagnostic (dvd_drive *dvd, dvd_command_diagnostic *out);

#endif
