/*
 * PhotoCD Player plugin for VDR
 * pcd_func.h: Functions for handling PhotsCDs
 *
 * See the README file for copyright information and how to reach the author.
 *
 * This code is distributed under the terms and conditions of the
 * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
 *
 * $Id$
 */

#ifndef __PCD_FUNC_H
#define __PCD_FUNC_H

#include <arpa/inet.h>
#include <linux/cdrom.h>

#define CD_XA21_DATASIZE  (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE-CD_SUBHEAD_SIZE-CD_EDC_SIZE-CD_ECC_SIZE)
#define CD_XA22_DATASIZE  (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE-CD_SUBHEAD_SIZE-CD_EDC_SIZE)

struct cdsector_xa21 {
  __u8 sync   [CD_SYNC_SIZE];
  __u8 head   [CD_HEAD_SIZE];
  union {
     __u8  b  [CD_SUBHEAD_SIZE];
     __u32 dw [CD_SUBHEAD_SIZE/4];
  } subhead;
  __u8 data   [CD_XA21_DATASIZE];
  __u8 edc    [CD_EDC_SIZE];
  __u8 ecc    [CD_ECC_SIZE];
};

struct cdsector_xa22 {
  __u8 sync   [CD_SYNC_SIZE];
  __u8 head   [CD_HEAD_SIZE];
  union {
     __u8  b  [CD_SUBHEAD_SIZE];
     __u32 dw [CD_SUBHEAD_SIZE/4];
  } subhead;
  __u8 data   [CD_XA22_DATASIZE];
  __u8 edc    [CD_EDC_SIZE];
};

#define SECTOR_SYNC_SIZE    8
#define SECTOR_HEAD_SIZE    8
#define SECTOR_DATA_SIZE    496
#define INFO_SECTORS        16
#define INFO_LBA            0
#define ENTRY0_LBA          1
#define ENTRY1_LBA          2
#define ENTRY2_LBA          3
#define ENTRY3_LBA          8
#define ENTRY4_LBA          9
#define ENTRY5_LBA          10
#define PCD_IMAGES          992
#define PCD_ID              "PHOTO_CD"

// sector offsets and counts for pcd images relativ to start sector

#define INFO_OFFSET         0
#define INFO_OFFSET_BASE16  3
#define DATA_OFFSET_BASE16  4
#define INFO_OFFSET_BASE4   22
#define DATA_OFFSET_BASE4   23
#define INFO_OFFSET_BASE    95
#define DATA_OFFSET_BASE    96
#define INFO_OFFSET_4BASE   384
#define INFO_SIZE           (INFO_OFFSET_BASE16-INFO_OFFSET)
#define INFO_SIZE_BASE16    (DATA_OFFSET_BASE16-INFO_OFFSET_BASE16)
#define DATA_SIZE_BASE16    (INFO_OFFSET_BASE4-DATA_OFFSET_BASE16)
#define INFO_SIZE_BASE4     (DATA_OFFSET_BASE4-INFO_OFFSET_BASE4)
#define DATA_SIZE_BASE4     (INFO_OFFSET_BASE-DATA_OFFSET_BASE4)
#define INFO_SIZE_BASE      (DATA_OFFSET_BASE-INFO_OFFSET_BASE)
#define DATA_SIZE_BASE      (INFO_OFFSET_4BASE-DATA_OFFSET_BASE)

#define WIDTH_BASE16        192
#define HEIGHT_BASE16       128
#define WIDTH_BASE4         384
#define HEIGHT_BASE4        256
#define WIDTH_BASE          768
#define HEIGHT_BASE         512

struct pcd_image {
  int  lba;
  bool orientation;
  };

__u8 bcd_to_bin(__u8 bcd);
int bcdmsf_to_lba(cdrom_msf0 msf0);
struct cdrom_msf0 lba_to_msf(int lba);

struct raw_sector {
  __u8  sync[SECTOR_SYNC_SIZE];
  __u8  head[SECTOR_HEAD_SIZE];
  __u8  data[SECTOR_DATA_SIZE];
  };

class cPCD {
private:
  cPCD *pcdInstance;
  const char *deviceName;
  int cdrom;
  struct raw_sector infoSector[INFO_SECTORS];
  int Command(int Cmd);
public:
  cPCD(void);
  cPCD(const char *DeviceName);
  ~cPCD();
  cPCD *getPCD(void);
  bool DriveExists(void);
  bool DiscOk(void);
  void Eject(void);
  void Open(void);
  void Close(void);
  void SetDriveSpeed(int DriveSpeed);
  bool VerifyPCD(void);
  int GetImageCount(void);
  bool readSectorRaw(int lba, void *sect);
  bool readSectorXA21(int lba, void *data);
  struct pcd_image Image[PCD_IMAGES+1];
  };

#endif //__PCD_FUNC_H
