/*
 * This file is part of the QPxTool project.
 * Copyright (C) 2005-2006 Gennady "ShultZ" Kozlov <qpxtool@mail.ru>
 *
 *
 * Some Plextor commands got from PxScan and CDVDlib (C) Alexander Noe`
 *
 *
 * 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.
 * See the file "COPYING" for the exact licensing terms.
 */

#include <stdio.h>
#include <stdlib.h>

#include <math.h>
#include <common_functions.h>

//#include <qthread.h>
#include <qpx_transport.h>
#include <qpx_mmc.h>

//#include "test_threads.h"
#include "plextor_qcheck.h"
//#include "qpx_const.h"

#define DEBUG 1
//#define _debug_cx
//#define _debug_pi
//#define _debug_jb

//*********************************//
//
//  commands to start tests
//
//*********************************//

const char PLEX_QCHECK_START	= 0x15;
const char PLEX_QCHECK_READOUT	= 0x16;
const char PLEX_QCHECK_END	= 0x17;

int plextor_start_cx(drive_info* drive) {
	drive->cmd_clear();
	drive->cmd[0] = CMP_PLEX_QCHECK; //0xEA;
	drive->cmd[1] = PLEX_QCHECK_START; //0x15;
	drive->cmd[2] = 0x00;
	drive->cmd[3] = 0x01;
	if ((drive->err=drive->cmd.transport(NONE, NULL, 0) ))
		{sperror ("PLEXTOR_START_CX",drive->err); return drive->err;}
#ifdef _debug_cx
	printf("00 18 01 01 00 4B |      LBA    |  BLER   E31   E21   E11   ???   E32   E22   E12 |     C1|     C2|     CU\n");
#endif
	return 0;
}

int plextor_start_pie(drive_info* drive) {
	drive->cmd_clear();
	drive->cmd[0] = CMP_PLEX_QCHECK; //0xEA;
	drive->cmd[1] = PLEX_QCHECK_START; //0x15;
	drive->cmd[2] = 0x00;
	drive->cmd[3] = 0x00;
	drive->cmd[8] = 0x08; // scan interval (ECC blocks)
	drive->cmd[9] = 0x10;
	if ((drive->err=drive->cmd.transport(NONE, NULL, 0)))
		{sperror ("PLEXTOR_START_PISUM8",drive->err);return drive->err;}
	return 0;
}

int plextor_start_pie_poe(drive_info* drive) {
	drive->cmd_clear();
	drive->cmd[0] = CMP_PLEX_QCHECK; //0xEA;
	drive->cmd[1] = PLEX_QCHECK_START; //0x15;
	drive->cmd[2] = 0x00;
	drive->cmd[3] = 0x00;
	drive->cmd[8] = 0x08; // scan interval (ECC blocks)
	drive->cmd[9] = 0x11;
	if ((drive->err=drive->cmd.transport(NONE, NULL, 0)))
		{sperror ("PLEXTOR_START_PISUM8_POE",drive->err);return drive->err;}
	return 0;
}

int plextor_start_pif(drive_info* drive) {
	drive->cmd_clear();
	drive->cmd[0] = CMP_PLEX_QCHECK; //0xEA;
	drive->cmd[1] = PLEX_QCHECK_START; //0x15;
	drive->cmd[2] = 0x00;
	drive->cmd[3] = 0x00;
	drive->cmd[8] = 0x01; // scan interval (ECC blocks)
	drive->cmd[9] = 0x12;
	if ((drive->err=drive->cmd.transport(NONE, NULL, 0)))
		{sperror ("PLEXTOR_START_PIF",drive->err); return drive->err;}
	return 0;
}

int plextor_start_jb_DVD(drive_info* drive) {
	drive->cmd_clear();
	drive->cmd[0] = CMP_PLEX_QCHECK; //0xEA;
	drive->cmd[1] = PLEX_QCHECK_START; //0x15;
	drive->cmd[2] = 0x10;
	drive->cmd[3] = 0x00; // DVD
	drive->cmd[8] = 0x10; // scan interval (ECC blocks)
	if ((drive->err=drive->cmd.transport(NONE, NULL, 0)))
		{sperror ("PLEXTOR_START_JB_DVD",drive->err);return drive->err;}
	return 0;
}

int plextor_start_jb_CD(drive_info* drive) {
	drive->cmd_clear();
	drive->cmd[0] = CMP_PLEX_QCHECK; //0xEA;
	drive->cmd[1] = PLEX_QCHECK_START; //0x15;
	drive->cmd[2] = 0x10;
	drive->cmd[3] = 0x01; // CD
	if ((drive->err=drive->cmd.transport(NONE, NULL, 0)))
		{sperror ("PLEXTOR_START_JB_CD",drive->err);return drive->err;}
	return 0;
}

int plextor_start_fete(drive_info* drive) {
	drive->cmd[0] = CMD_PLEX_SCAN_TA_FETE; // 0xF3;
	drive->cmd[1] = 0x1F;
	drive->cmd[2] = 0x03;
	drive->cmd[3] = 0x01;
	if (drive->media.disc_type & DISC_CD) {
		int sect;
		msf sect_msf;
//	start address
		drive->cmd[4] = 0x00;
		drive->cmd[5] = 0x00;
		drive->cmd[6] = 0x00;
//	end address
		sect = drive->media.capacity_total-1;
		lba2msf(&sect,&sect_msf);
		drive->cmd[7] = sect_msf.m;
		drive->cmd[8] = sect_msf.s;
		drive->cmd[9] = sect_msf.f;
	} else {
//	start address
		drive->cmd[4] = 0x00;
		drive->cmd[5] = 0x00;
		drive->cmd[6] = 0x00;
//	end address
		drive->cmd[7] = ((drive->media.capacity_total-1) >> 16) & 0xFF;
		drive->cmd[8] = ((drive->media.capacity_total-1) >> 8) & 0xFF;
		drive->cmd[9] = (drive->media.capacity_total-1) & 0xFF;
	}
	if ((drive->err=drive->cmd.transport(NONE, NULL, 0)))
		{sperror ("PLEXTOR_START_FETE",drive->err);return drive->err;}
	return 0;
}

//*********************************//
//
//  end scan commands
//
//*********************************//

int plextor_end_scan(drive_info* drive) {
	drive->cmd_clear();
	drive->cmd[0] = CMP_PLEX_QCHECK; //0xEA;
	drive->cmd[1] = PLEX_QCHECK_END; //0x17;
	if ((drive->err=drive->cmd.transport(NONE, NULL, 0)))
		{sperror ("PLEXTOR_END_SCAN",drive->err); return drive->err;}
	return 0;
}

int plextor_end_fete(drive_info* drive) {
	drive->cmd_clear();
	drive->cmd[0] = CMD_PLEX_SCAN_TA_FETE; // 0xF3;
	drive->cmd[1] = 0x1F;
	drive->cmd[2] = 0x04;
	if ((drive->err=drive->cmd.transport(NONE, NULL, 0)))
		{sperror ("PLEXTOR_END_FETE",drive->err); return drive->err;}
	return 0;
}

//*********************************//
//
//  test data readout commands 
//
//*********************************//

int plextor_read_cd_error_info(drive_info* drive, int* BLER,
	int* E11, int* E21, int* E31, int* E12, int* E22, int* E32)
{
	drive->cmd_clear();
	drive->cmd[0] = CMP_PLEX_QCHECK; //0xEA;
	drive->cmd[1] = PLEX_QCHECK_READOUT; // 0x16;
	drive->cmd[2] = 0x01;
	drive->cmd[10]= 0x1A;
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,0x1A)))
		{sperror ("PLEXTOR_READ_CD_ERROR_INFO", drive->err);return drive->err;}

//	int E11, E21, E31, E12, E22, E32, BLER;
	*BLER = swap2(drive->rd_buf+10);
	*E31 = swap2(drive->rd_buf+12);
	*E21 = swap2(drive->rd_buf+14);
	*E11 = swap2(drive->rd_buf+16);
	// ??? swap2(drive->rd_buf+18);
	*E32 = swap2(drive->rd_buf+20);
	*E22 = swap2(drive->rd_buf+22);
	*E12 = swap2(drive->rd_buf+24);

	int C1,C2,CU;
	C1 = *BLER;
	C2 = *E22;
	CU = *E32;

#ifdef _debug_cx
	int i;
	for (i=0x00; i<0x06; i++) printf("%02X ", drive->rd_buf[i] & 0xFF); printf("| ");
	for (i=0x06; i<0x0A; i++) printf("%02X ", drive->rd_buf[i] & 0xFF); printf("| ");
	for (i=0x0A; i<0x1A; i+=2) { if (swap2(drive->rd_buf+i)) printf("%5d ", swap2(drive->rd_buf+i)); else printf("_____ "); }
	printf("| ");
	printf("%3d C1| %3d C2| %3d CU\n", C1, C2, CU);
#endif
	return 0;
}

int plextor_read_pi_info(drive_info* drive) {
	drive->cmd_clear();
	drive->cmd[0] = CMP_PLEX_QCHECK; //0xEA;
	drive->cmd[1] = PLEX_QCHECK_READOUT; // 0x16;
	drive->cmd[2] = 0x00;
	drive->cmd[10]= 0x34;
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,0x34)))
		{sperror ("PLEXTOR_READ_PI",drive->err); return drive->err;}
/*
	printf("READ PI:");
	for (int i=0; i<0x34; i++) {
		if (!(i%0x10)) printf("\n");
		printf(" %02X",drive->rd_buf[i] & 0xFF);
	}
	printf("\n");

*/
#ifdef _debug_pi
	int i;
/*
//	printf("\n| ");
	for (i=0x00; i<0x34; i++) {
		if (!(i%0x20))printf("\n| ");
		printf("%02X ", drive->rd_buf[i] & 0xFF);
	}
*/
	for (i=0x00; i<0x06; i++) printf("%02X ", drive->rd_buf[i] & 0xFF); printf("|");
	printf(" %6X |", swap4(drive->rd_buf+0x06) - 0x030000);
	printf(" %4X |", swap2(drive->rd_buf+0x0A));
	printf(" %4X",   swap2(drive->rd_buf+0x0C));

	for (i=0x20; i<0x34; i+=4) {
		if (!(i%0x10))printf(" |");
		if (swap4(drive->rd_buf+i))
			printf(" %8d", swap4(drive->rd_buf+i));
		else
			printf(" ________");
	}
//	printf("\n");
#endif
	return 0;
}

int plextor_read_jb_info(drive_info* drive) {
	drive->cmd_clear();
	drive->cmd[0] = CMP_PLEX_QCHECK; //0xEA;
	drive->cmd[1] = PLEX_QCHECK_READOUT; // 0x16;
	drive->cmd[2] = 0x10;
	drive->cmd[10] = 0x10;
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,0x10)))
		{sperror ("PLEXTOR_READ_JB",drive->err); return drive->err;}
#ifdef _debug_jb
	int i;
	printf("\n| J/B data: | ");
	for (i=0x00; i<0x10; i++) printf("%02X ", drive->rd_buf[i] & 0xFF);
	printf("|\n");
#endif
	return 0;
}


int plextor_cx_do_one_interval(drive_info* drive, int* lba, int* BLER,
	int* E11, int* E21, int* E31, int* E12, int* E22, int* E32)
{
	for (int i=0; (i<5) && *lba<drive->media.capacity; i++) {
		if (*lba + 15 < drive->media.capacity)
			read_cd(drive, *lba, 15, 0xFA);
		else
			read_cd(drive, *lba, drive->media.capacity - *lba, 0xFA);
		*lba+=15;
	}
	plextor_read_cd_error_info(drive, BLER, E11, E21, E31, E12, E22, E32);
//	*lba = 
	return 0;
}

int plextor_pif_do_one_ecc_block(drive_info* drive, int* lba, int* pif) {
	read_one_ecc_block(drive, *lba);
	*lba+= 0x10;
	plextor_read_pi_info(drive);
//	*lba = swap4(drive->rd_buf+0x06) - 0x00030000;
	*pif = swap4(drive->rd_buf+0x24);
#ifdef _debug_pi
	printf(" * %4d\n", *pif);
#endif
	return 0;
}

int plextor_pisum8_do_eight_ecc_blocks(drive_info* drive, int* lba, int* pie, int* pof) {
	for (int i=0;i<8;i++) {
		if ((drive->err = read_one_ecc_block(drive, *lba)));// i = 8;
		*lba+= 0x10;
	}
	plextor_read_pi_info(drive);
//	*lba = swap4(drive->rd_buf+0x06) - 0x00030000;
	*pie = swap4(drive->rd_buf+0x24);
	*pof = swap4(drive->rd_buf+0x10);
//	*poe = swap4(drive->rd_buf+0x28);
//	*pif = 0;
#ifdef _debug_pi
	printf(" * %4d\n", *pie);
#endif
	return 0;
}

int plextor_burst_do_eight_ecc_blocks(drive_info* drive, int* lba, int* pie, int* poe, int* pof) {
	for (int i=0;i<8;i++) {
		if ((drive->err = read_one_ecc_block(drive, *lba)));// i = 8;
		*lba+= 0x10;
	}
	plextor_read_pi_info(drive);
//	*lba = swap4(drive->rd_buf+0x06) - 0x00030000;
	*pie = swap4(drive->rd_buf+0x24);
//*
	if (swap2(drive->rd_buf+0x0C) > swap2(drive->rd_buf+0x0A))
		*poe = swap4(drive->rd_buf+0x28) >> 1;
	else
		*poe = 0;
	*pof = swap4(drive->rd_buf+0x10);

#ifdef _debug_pi
	printf(" * %4d * %4d\n", *pie, *poe);
#endif
	return 0;
}

int plextor_jitterbeta_DVD_do_16_ecc_blocks(drive_info* drive, int* lba, int* jitter, short int* beta) {
	short int*  i16_beta;
	char c;
	for (int i=0;i<16;i++) {
		int j = read_one_ecc_block(drive, *lba);
		if (j == COMMAND_FAILED) i=16;
		*lba+= 0x10;
	}
	plextor_read_jb_info(drive);
	c = drive->rd_buf[10]; drive->rd_buf[10] = drive->rd_buf[11]; drive->rd_buf[11] = c;
	i16_beta = (short int*)(drive->rd_buf+10);
	if (drive->dev_ID > PLEXTOR_716) {
		*beta = *i16_beta;
		*jitter = 3200 - 2*swap2(drive->rd_buf+12);
	} else {
		*beta = *i16_beta;
//		*jitter = 3000 - 2*swap2(drive->rd_buf+12);
		*jitter = 3200 - (int)(2.4*swap2(drive->rd_buf+12));
	}
	return (!(drive->rd_buf[2]));
}

int plextor_jitterbeta_do_one_cd_interval(drive_info* drive, int* lba, int* jitter, short int* beta, int int_len) {
	short int*  i16_beta;
	char c;
	int blocks = int_len / 15;
	int rest = int_len % 15;
	for (int i=0;i<blocks;i++) {
		int j = read_cd(drive, *lba, 15, 0xFA);
		*lba+= 0x0F;
		if (j == COMMAND_FAILED) i++;
	}
	if (rest) {
		read_cd(drive, *lba, rest, 0xFA);
	}
	plextor_read_jb_info(drive);
	c = drive->rd_buf[10]; drive->rd_buf[10] = drive->rd_buf[11]; drive->rd_buf[11] = c;
	i16_beta = (short int*)(drive->rd_buf+10);
	if (drive->dev_ID > PLEXTOR_716) {
		*beta = *i16_beta;
		*jitter = 4800 - 2*swap2(drive->rd_buf+12);
	} else {
		*beta = *i16_beta;
//		*jitter = 3200 - 2*swap2(drive->rd_buf+12);
		*jitter = 3600 - (int)(2.4*swap2(drive->rd_buf+12));
	}
	return (!(drive->rd_buf[2]));
}

int plextor_read_fete(drive_info* drive) {
	drive->cmd_clear();
	drive->cmd[0] = CMD_PLEX_FETE_READOUT; // 0xF5;
	drive->cmd[3] = 0x0C;
	drive->cmd[9] = 0xCE;
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,0xCE)))
		{sperror ("PLEXTOR_FETE_READOUT",drive->err); return drive->err;}
/*
	for (int i=0; i<0xCE; i++) {
		if (!(i % 0x20)) printf("\n");
		printf("%02X ",drive->rd_buf[i] & 0xFF);
	}
	printf("\n");
*/
	return 0;
}

scan_commands commands_plextor_list = {
	plextor_start_cx,	plextor_cx_do_one_interval,			plextor_end_scan,
	plextor_start_jb_CD,	plextor_jitterbeta_do_one_cd_interval,		plextor_end_scan,

	plextor_start_pie,	plextor_pisum8_do_eight_ecc_blocks,		plextor_end_scan,
	plextor_start_pif,	plextor_pif_do_one_ecc_block,			plextor_end_scan,
	plextor_start_pie_poe,	plextor_burst_do_eight_ecc_blocks,		plextor_end_scan,
	NULL,			NULL,						NULL,
	plextor_start_jb_DVD,	plextor_jitterbeta_DVD_do_16_ecc_blocks,	plextor_end_scan,
};

scan_commands commands_plextor() { return commands_plextor_list; }


syntax highlighted by Code2HTML, v. 0.9.1