/*
 * This file is part of the QPxTool project.
 * Copyright (C) 2005-2006 Gennady "ShultZ" Kozlov <qpxtool@mail.ru>
 *
 * 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 <unistd.h>
//#include <sys/time.h>

#include <qpx_transport.h>
#include <qpx_mmc.h>
#include <common_functions.h>

#include "media_check_benq.h"

//#define _BENQ_DEBUG 1
#define _BENQ_DEBUG2 1

// ************* Scan init commands *********
int benq_init_scan_cd(drive_info* drive) {
	int i;

	drive->cmd_clear();
	drive->cmd[0] = 0xFD;
	drive->cmd[1] = 0xF1;
	drive->cmd[2] = 0x42;
	drive->cmd[3] = 0x45;
	drive->cmd[4] = 0x4E;
	drive->cmd[5] = 0x51;
#ifdef _BENQ_DEBUG
	printf("benq_init_cx_scan_0\n");
#endif
	if ((drive->err=drive->cmd.transport(NONE,NULL,0))){
		sperror ("benq_init_cx_scan_0",drive->err);
		return drive->err;
	}
// ************
	drive->rd_buf[0] = 0xD2;
	drive->rd_buf[1] = 0x0A;
	drive->rd_buf[2] = 0x00;
	drive->rd_buf[3] = 0x00;

	drive->cmd_clear();
	drive->cmd[0] = 0xF9;
	drive->cmd[8] = 0x04;
#ifdef _BENQ_DEBUG
	printf("benq_init_cx_scan_1\n");
#endif
	if ((drive->err=drive->cmd.transport(WRITE,drive->rd_buf,4))){
		sperror ("benq_init_cx_scan_1",drive->err);
		return drive->err;
	}

	drive->cmd_clear();
	drive->cmd[0] = 0xF8;
	drive->cmd[8] = 0x02;
#ifdef _BENQ_DEBUG
	printf("benq_init_cx_scan_2\n");
#endif
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,2))){
		sperror ("benq_init_cx_scan_2",drive->err);
		return drive->err;
	}
// ************
	drive->rd_buf[0] = 0xC8;
	drive->rd_buf[1] = 0x99;
	drive->rd_buf[2] = 0x79;
	for (i=3; i<10; i++)
		drive->rd_buf[i] = 0x00;

	drive->cmd_clear();
	drive->cmd[0] = 0xF9;
	drive->cmd[8] = 0x0A;
#ifdef _BENQ_DEBUG
	printf("benq_init_cx_scan_3\n");
#endif
	if ((drive->err=drive->cmd.transport(WRITE,drive->rd_buf,10))){
		sperror ("benq_init_cx_scan_3",drive->err);
		return drive->err;
	}

	drive->cmd_clear();
	drive->cmd[0] = 0xF8;
	drive->cmd[8] = 0x02;
#ifdef _BENQ_DEBUG
	printf("benq_init_cx_scan_4\n");
#endif
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,2))){
		sperror ("benq_init_cx_scan_4",drive->err);
		return drive->err;
	}
// ************
	drive->rd_buf[0] = 0xD4;
	drive->rd_buf[1] = 0x91;
	drive->rd_buf[2] = 0x00;
	drive->rd_buf[3] = 0x00;
	drive->rd_buf[4] = 0x00;
	drive->rd_buf[5] = 0x00;

	drive->cmd_clear();
	drive->cmd[0] = 0xF9;
	drive->cmd[8] = 0x06;
#ifdef _BENQ_DEBUG
	printf("benq_init_cx_scan_5\n");
#endif
	if ((drive->err=drive->cmd.transport(WRITE,drive->rd_buf,6))){
		sperror ("benq_init_cx_scan_5",drive->err);
		return drive->err;
	}

	drive->cmd_clear();
	drive->cmd[0] = 0xF8;
	drive->cmd[8] = 0x02;
#ifdef _BENQ_DEBUG
	printf("benq_init_cx_scan_6\n");
#endif
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,2))){
		sperror ("benq_init_cx_scan_6",drive->err);
		return drive->err;
	}

//	cnt=0;
	return 0;
}


int benq_init_scan_dvd(drive_info* drive) {
	int i;

	drive->cmd_clear();
	drive->cmd[0] = 0xFD;
	drive->cmd[1] = 0xF1;
	drive->cmd[2] = 0x42;
	drive->cmd[3] = 0x45;
	drive->cmd[4] = 0x4E;
	drive->cmd[5] = 0x51;
#ifdef _BENQ_DEBUG
	printf("benq_init_pi_scan_0\n");
#endif
	if ((drive->err=drive->cmd.transport(NONE,NULL,0))){
		sperror ("benq_init_pi_scan_0",drive->err);
		return drive->err;
	}
// ************
	drive->rd_buf[0] = 0xD2;
	drive->rd_buf[1] = 0x0A;
	drive->rd_buf[2] = 0x05;
	drive->rd_buf[3] = 0x00;

	drive->cmd_clear();
	drive->cmd[0] = 0xF9;
	drive->cmd[8] = 0x04;
#ifdef _BENQ_DEBUG
	printf("benq_init_pi_scan_1\n");
#endif
	if ((drive->err=drive->cmd.transport(WRITE,drive->rd_buf,4))){
		sperror ("benq_init_pi_scan_1",drive->err);
		return drive->err;
	}

	drive->cmd_clear();
	drive->cmd[0] = 0xF8;
	drive->cmd[8] = 0x02;
#ifdef _BENQ_DEBUG
	printf("benq_init_pi_scan_2\n");
#endif
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,2))){
		sperror ("benq_init_pi_scan_2",drive->err);
		return drive->err;
	}
// ************
	drive->rd_buf[0] = 0xC8;
	drive->rd_buf[1] = 0x99;
	drive->rd_buf[2] = 0x79;
	for (i=3; i<10; i++)
		drive->rd_buf[i] = 0x00;

	drive->cmd_clear();
	drive->cmd[0] = 0xF9;
	drive->cmd[8] = 0x0A;
#ifdef _BENQ_DEBUG
	printf("benq_init_pi_scan_3\n");
#endif
	if ((drive->err=drive->cmd.transport(WRITE,drive->rd_buf,10))){
		sperror ("benq_init_pi_scan_3",drive->err);
		return drive->err;
	}

	drive->cmd_clear();
	drive->cmd[0] = 0xF8;
	drive->cmd[8] = 0x02;
#ifdef _BENQ_DEBUG
	printf("benq_init_pi_scan_4\n");
#endif
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,2))){
		sperror ("benq_init_pi_scan_4",drive->err);
		return drive->err;
	}
// ************
	drive->rd_buf[0] = 0xD4;
	drive->rd_buf[1] = 0x91;
	drive->rd_buf[2] = 0x03;
	drive->rd_buf[3] = 0x00;
	drive->rd_buf[4] = 0x00;
	drive->rd_buf[5] = 0x00;

	drive->cmd_clear();
	drive->cmd[0] = 0xF9;
	drive->cmd[8] = 0x06;
#ifdef _BENQ_DEBUG
	printf("benq_init_pi_scan_5\n");
#endif
	if ((drive->err=drive->cmd.transport(WRITE,drive->rd_buf,6))){
		sperror ("benq_init_pi_scan_5",drive->err);
		return drive->err;
	}

	drive->cmd_clear();
	drive->cmd[0] = 0xF8;
	drive->cmd[8] = 0x02;
#ifdef _BENQ_DEBUG
	printf("benq_init_pi_scan_6\n");
#endif
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,2))){
		sperror ("benq_init_pi_scan_6",drive->err);
		return drive->err;
	}

//	cnt=0;
	return 0;
}

// ************ Scan commands ***********
int benq_scan_block(drive_info* drive){
	drive->rd_buf[0] = 0xC1;
	drive->rd_buf[1] = 0x9A;
	drive->rd_buf[2] = 0x00;
	drive->rd_buf[3] = 0x00;

	drive->cmd_clear();
	drive->cmd[0] = 0xF9;
	drive->cmd[8] = 0x04;
#ifdef _BENQ_DEBUG
	printf("benq_scan_block\n");
#endif
	if ((drive->err=drive->cmd.transport(WRITE,drive->rd_buf,4))){
		sperror ("benq_scan_block",drive->err);
		return drive->err;
	}
	return 0;
}

int benq_read_err(drive_info* drive){
	drive->cmd_clear();
	drive->cmd[0] = 0xF8;
	drive->cmd[7] = 0x01;
	drive->cmd[8] = 0x02;
#ifdef _BENQ_DEBUG
	printf("benq_read_err\n");
#endif
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,258))){
		sperror ("benq_read_err",drive->err);
		return drive->err;
	}
	return 0;
}

// ***********
//  CD tests
// ***********

int benq_cx_do_one_interval(drive_info* drive, int* lba, int* BLER,
	int* E11, int* E21, int* E31, int* E12, int* E22, int* E32)
{
	int i,m,s,f;
#ifdef _BENQ_DEBUG
	printf("benq_cx_do_one_interval. LBA=%d\n",*lba);
#endif
	int found=0;
	int cnt=128;
	while ((!found) && (cnt)) {
		benq_scan_block(drive);
		benq_read_err(drive);
		if ((!drive->rd_buf[0]) && (drive->rd_buf[1] == 0x63) && (drive->rd_buf[2] == 0x64) && (drive->rd_buf[3] == 0x6E)) {
			printf("\nData block found...\n");
			found = 1;
		} else {
			printf(".");
//			return 0;
		}
		usleep(1000);
		cnt--;
	}
	if (!cnt) return 1;
#ifdef _BENQ_DEBUG2
	for (i=0; i<32; i++) {
		if (!(i%8)) printf("| ");
		printf("%02X ", drive->rd_buf[i] & 0xFF);
	}
	printf("|\n");
#endif

	*BLER = swap2(drive->rd_buf+12); // C1
	*E11 = 0;
	*E21 = 0;
	*E31 = 0;
	*E12 = 0;
	*E22 = swap2(drive->rd_buf+18); // C2
	*E32 = 0; // CU
//	*lba+=75;
//	cnt++;
	m = ((drive->rd_buf[7] >> 4) & 0x0F)*10 + (drive->rd_buf[7] & 0x0F);
	s = ((drive->rd_buf[8] >> 4) & 0x0F)*10 + (drive->rd_buf[8] & 0x0F);
	f = ((drive->rd_buf[9] >> 4) & 0x0F)*10 + (drive->rd_buf[9] & 0x0F);
	*lba = (m*60 + s)*75 + f;
	printf("MSF: %02d:%02d.00 ; LBA: %d; C1:%4d; C2:%4d\n",m,s,*lba,*BLER,*E22);
	return 0;
}


int benq_jitter_CD_do_one_interval(drive_info* drive, int* lba, int* jitter, short int* beta, int blklen)
{
	benq_scan_block(drive);
	benq_read_err(drive);

	*jitter = 0;
	*beta = 0;
//	*lba=((int)drive->rd_buf[0] * 4500 + (int)drive->rd_buf[3] * 75 + (int)drive->rd_buf[2]);
	*lba = (((drive->rd_buf[7] & 0xF0)*10 + (drive->rd_buf[7] & 0x0F))*60 +  (drive->rd_buf[7] & 0xF0))*10 + (drive->rd_buf[7] & 0x0F);
	return 0;
}

// ***********
// DVD tests
// ***********

int benq_pie_pif_do_one_interval(drive_info* drive, int* lba, int* pie, int* pif, int* pof)
{
	int i;
//	int pif;
#ifdef _BENQ_DEBUG
	printf("benq_pie_pif_do_one_interval. LBA=%d\n",*lba);
#endif
	int found=0;
	int cnt=256;
	while ((!found) && (cnt)) {
		benq_scan_block(drive);
		benq_read_err(drive);
		if ((!drive->rd_buf[0]) && (drive->rd_buf[1] == 0x64) && (drive->rd_buf[2] == 0x76) && (drive->rd_buf[3] == 0x64)) {
			printf("\nData block found...\n");
			found = 1;
		} else {
			printf(".");
//			return 0;
		}
		usleep(1000);
		cnt--;
	}
	if (!cnt) return 1;
#ifdef _BENQ_DEBUG2
	for (i=0; i<32; i++) {
		if (!(i%8)) printf("| ");
		printf("%02X ", drive->rd_buf[i] & 0xFF);
	}
	printf("|\n");
#endif
	*pie = max (swap2(drive->rd_buf+10),swap2(drive->rd_buf+12));
	*pif = swap2(drive->rd_buf+16) + swap2(drive->rd_buf+18);
	*pof = 0;
	*lba = (((drive->rd_buf[7]-3) << 16 )& 0xFF0000) + ((drive->rd_buf[8] << 8)&0xFF00 ) + (drive->rd_buf[9] & 0xFF);
	printf("LBA: %d; PIE:%4d; PIF:%4d\n",*lba,*pie, *pif);
	return 0;
}

int benq_jitter_DVD_do_16_ecc(drive_info* drive, int* lba, int* jitter, short int* beta)
{
	benq_scan_block(drive);
	benq_read_err(drive);

	*jitter = 0;
	*beta = 0;
//	*lba=((int)drive->rd_buf[0] * 4500 + (int)drive->rd_buf[3] * 75 + (int)drive->rd_buf[2]);
	*lba+= 0x400;
	return 0;
}

// ************* END SCAN COMMAND *********
int benq_end_scan_cd(drive_info* drive) {
	int i;

	drive->rd_buf[0] = 0xD4;
	drive->rd_buf[1] = 0x91;
	for (i=2; i<10; i++)
		drive->rd_buf[i] = 0x00;

	drive->cmd_clear();
	drive->cmd[0] = 0xF9;
	drive->cmd[8] = 0x0A;
	if ((drive->err=drive->cmd.transport(WRITE,drive->rd_buf,10))){
		sperror ("benq_end_scan_0",drive->err);
		return drive->err;
	}

	drive->cmd_clear();
	drive->cmd[0] = 0xF8;
	drive->cmd[8] = 0x02;
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,2))){
		sperror ("benq_end_scan_1",drive->err);
		return drive->err;
	}
// ************
	drive->rd_buf[0] = 0xD4;
	drive->rd_buf[1] = 0x91;
	drive->rd_buf[2] = 0x00;
	drive->rd_buf[3] = 0x02;
	drive->rd_buf[4] = 0x00;
	drive->rd_buf[5] = 0x00;

	drive->cmd_clear();
	drive->cmd[0] = 0xF9;
	drive->cmd[8] = 0x06;
	if ((drive->err=drive->cmd.transport(WRITE,drive->rd_buf,6))){
		sperror ("benq_end_scan_2",drive->err);
		return drive->err;
	}

	drive->cmd_clear();
	drive->cmd[0] = 0xF8;
	drive->cmd[8] = 0x02;
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,2))){
		sperror ("benq_end_scan_3",drive->err);
		return drive->err;
	}
// ************
	drive->cmd_clear();
	drive->cmd[0] = 0xFD;
	drive->cmd[1] = 0xF2;
	drive->cmd[2] = 0x42;
	drive->cmd[3] = 0x45;
	drive->cmd[4] = 0x4E;
	drive->cmd[5] = 0x51;
	if ((drive->err=drive->cmd.transport(NONE,NULL,0))){
		sperror ("benq_end_scan_4",drive->err);
		return drive->err;
	}
	return 0;
}


int benq_end_scan_dvd(drive_info* drive) {
	int i;

	drive->rd_buf[0] = 0xD4;
	drive->rd_buf[1] = 0x91;
	for (i=2; i<10; i++)
		drive->rd_buf[i] = 0x00;

	drive->cmd_clear();
	drive->cmd[0] = 0xF9;
	drive->cmd[8] = 0x0A;
	if ((drive->err=drive->cmd.transport(WRITE,drive->rd_buf,10))){
		sperror ("benq_end_scan_0",drive->err);
		return drive->err;
	}

	drive->cmd_clear();
	drive->cmd[0] = 0xF8;
	drive->cmd[8] = 0x02;
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,2))){
		sperror ("benq_end_scan_1",drive->err);
		return drive->err;
	}
// ************
	drive->rd_buf[0] = 0xD4;
	drive->rd_buf[1] = 0x91;
	drive->rd_buf[2] = 0x03;
	drive->rd_buf[3] = 0x00;
	drive->rd_buf[4] = 0x00;
	drive->rd_buf[5] = 0x00;

	drive->cmd_clear();
	drive->cmd[0] = 0xF9;
	drive->cmd[8] = 0x06;
	if ((drive->err=drive->cmd.transport(WRITE,drive->rd_buf,6))){
		sperror ("benq_end_scan_2",drive->err);
		return drive->err;
	}

	drive->cmd_clear();
	drive->cmd[0] = 0xF8;
	drive->cmd[8] = 0x02;
	if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,2))){
		sperror ("benq_end_scan_3",drive->err);
		return drive->err;
	}
// ************
	drive->cmd_clear();
	drive->cmd[0] = 0xFD;
	drive->cmd[1] = 0xF2;
	drive->cmd[2] = 0x42;
	drive->cmd[3] = 0x45;
	drive->cmd[4] = 0x4E;
	drive->cmd[5] = 0x51;
	if ((drive->err=drive->cmd.transport(NONE,NULL,0))){
		sperror ("benq_end_scan_4",drive->err);
		return drive->err;
	}
	return 0;
}

scan_commands commands_list_benq = {
	benq_init_scan_cd,	benq_cx_do_one_interval,	benq_end_scan_cd,
	NULL,			benq_jitter_CD_do_one_interval,	benq_end_scan_cd,

	NULL,			NULL,				NULL,
	NULL,			NULL,				NULL,
	NULL,			NULL,				NULL,
	benq_init_scan_dvd,	benq_pie_pif_do_one_interval,	benq_end_scan_dvd,
	NULL,			benq_jitter_DVD_do_16_ecc,	benq_end_scan_dvd,
};

scan_commands commands_benq()  { return commands_list_benq; }


syntax highlighted by Code2HTML, v. 0.9.1