/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = CDTOSH.C
 *
 * DESCRIPTIVE NAME = Vendor unique command processing Toshiba SCSI-2
 *                    CD-ROM Drives
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION
 *
 *
 * FUNCTIONS
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#include "cdh.h"
#include "tocdb.h"

USHORT Tosh_Read_2352_NoCDDA (NPUNITCB, ULONG, USHORT, ULONG);


/****************************************************************************
 *
 * FUNCTION NAME = Tosh_Read_2048
 *
 * DESCRIPTION   = Read 2048 byte sectors for Toshiba 3301 & 3401
 *
 *      USHORT Tosh_Read_2048      (NPUNITCB pUnitCB, ULONG LBA,
 *                                   USHORT transfer_count, ULONG ppDataBuff)
 *
 * INPUT         = pUnitCB          - Pointer to UnitCB
 *                 LBA              - LBA
 *                 transfer_count   - count of sectors to transfer
 *                 ppDataBuff       - phys addr of data buffer
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Tosh_Read_2048 (pUnitCB, LBA, transfer_count, ppDataBuff)

NPUNITCB pUnitCB;
ULONG    LBA;
USHORT   transfer_count;
ULONG    ppDataBuff;

{
   USHORT disk_density, rc;

   /*
   ** Make sure the density is set properly for Toshiba 3301 drives
   */
   disk_density = pUnitCB->DeviceInfo.disk_density;

   if (LBA == 0L && transfer_count == 1)
   {
      if ( (rc = Tosh_GetDensityCode (pUnitCB, (USHORT FAR *) &disk_density))
                                                                    & STERR)
         return (rc);

      pUnitCB->DeviceInfo.disk_density = disk_density;
   }

   if (disk_density == CD_DENSITY_CDDA)
      return (STDON + STERR + ERROR_I24_SECTOR_NOT_FOUND);

   /*
   ** Issue mode select if density code or block length is not right
   */
   if ( ((pUnitCB->DeviceInfo.current_density == CD_DENSITY_CDDA) ||
         (pUnitCB->DeviceInfo.current_density != disk_density)    ||
         (pUnitCB->DeviceInfo.current_block_size != 2048))        &&
         (pUnitCB->DeviceInfo.current_density != CD_DENSITY_CDXA_83) )
   {

      /* Set density code to 0x83 if stock Toshiba 3401 since it */
      /* has a firmware     with density code 0x81               */

      if ( (pUnitCB->DeviceInfo.vendor_id_code == TOSHIBA) &&
           (pUnitCB->DeviceInfo.product_id_code == TOSHIBA_3401) )
      {
         disk_density = CD_DENSITY_CDXA_83;
      }

      rc = ChainModeSelectRead (pUnitCB, LBA, transfer_count,
                                         ppDataBuff, 2048, disk_density);
   }
   else
   {
      rc = ReadSector (pUnitCB, LBA, transfer_count, ppDataBuff, 2048);
   }
   return (rc);
}


/****************************************************************************
 *
 * FUNCTION NAME = Tosh_Read_2352
 *
 * DESCRIPTION   = Read 2352 byte sectors for Toshiba 3301 & 3401
 *
 *     USHORT Tosh_Read_2352  (NPUNITCB pUnitCB, ULONG LBA,
 *                                 USHORT transfer_count, ULONG ppDataBuff)
 *
 * INPUT         = pUnitCB          - Pointer to UnitCB
 *                 ul_LBA           - LBA
 *                 transfer_count   - count of sectors to transfer
 *                 ppDataBuff       - phys addr of data buffer
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Tosh_Read_2352 (pUnitCB, LBA, transfer_count, ppDataBuff)

NPUNITCB pUnitCB;
ULONG    LBA;
USHORT   transfer_count;
ULONG    ppDataBuff;

{
   USHORT rc, density;

   /*
   ** If this is a Toshiba drive that doesnt support reading CD-DA
   ** audio sectors, then just try reading 2352 XA.
   */
   if ( (pUnitCB->DeviceInfo.vendor_id_code == TOSHIBA) &&
        ( !(pUnitCB->DeviceInfo.Audio.capabilities & DCAPS_CDDA) ) )
   {
       rc = Tosh_Read_2352_NoCDDA (pUnitCB, LBA, transfer_count, ppDataBuff);
       return(rc);
   }

   /*
   ** If current block size is not 2352, issue Mode Select prior to
   ** the read.
   */
   if (pUnitCB->DeviceInfo.current_block_size != 2352)
   {
      rc = ChainModeSelectRead (pUnitCB, LBA, transfer_count,
                                         ppDataBuff, 2352, CD_DENSITY_CDDA);
   }
   else
   {
      rc = ReadSector (pUnitCB, LBA, transfer_count, ppDataBuff, 2352);
   }

   /*
   ** If a read error occurred, try changing the density code and
   ** reissuing the the read command.
   */
   if ( (rc == STDON + STERR + ERROR_I24_BAD_COMMAND) ||
        (rc == STDON + STERR + ERROR_I24_SEEK) )
   {
      if (pUnitCB->DeviceInfo.current_density != CD_DENSITY_CDDA)
         density = CD_DENSITY_CDDA;
      else if (pUnitCB->DeviceInfo.disk_density != CD_DENSITY_CDDA)
         density = pUnitCB->DeviceInfo.disk_density;
      else
         goto Tosh_Exit;

      rc = ChainModeSelectRead (pUnitCB, LBA, transfer_count,
                                         ppDataBuff, 2352, density);
   }

Tosh_Exit:
   return(rc);
}


/****************************************************************************
 *
 * FUNCTION NAME = Tosh_Read_2352_NoCDDA
 *
 * DESCRIPTION   = Read 2352 byte sectors for Toshiba 3301
 *
 *   USHORT Tosh_Read_2352_NoCDDA  (NPUNITCB pUnitCB, ULONG LBA,
 *                                    USHORT transfer_count, ULONG ppDataBuff)
 *
 * INPUT         = pUnitCB          - Pointer to UnitCB
 *                 ul_LBA           - LBA
 *                 transfer_count   - count of sectors to transfer
 *                 ppDataBuff       - phys addr of data buffer
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Tosh_Read_2352_NoCDDA (pUnitCB, LBA, transfer_count, ppDataBuff)

NPUNITCB pUnitCB;
ULONG    LBA;
USHORT   transfer_count;
ULONG    ppDataBuff;

{
   USHORT rc, disk_density;

   /*
   ** If current block size is not 2352, issue Mode Select prior to
   ** the read.
   */
   disk_density = pUnitCB->DeviceInfo.disk_density;

   if ( (pUnitCB->DeviceInfo.current_density != disk_density) ||
        (pUnitCB->DeviceInfo.current_block_size != 2352) )
   {
      rc = ChainModeSelectRead (pUnitCB, LBA, transfer_count,
                                         ppDataBuff, 2352, disk_density);
   }
   else
   {
      rc = ReadSector (pUnitCB, LBA, transfer_count, ppDataBuff, 2352);
   }


   return(rc);
}


/****************************************************************************
 *
 * FUNCTION NAME = Tosh_GetDensityCode
 *
 * DESCRIPTION   = Get density code for sector zero.
 *
 *    This routine returns the density code for sector zero.  This routine
 *    should only be called if the drive is a Toshiba 3301.
 *
 *    USHORT Tosh_GetDensityCode  (NPUNITCB pUnitCB, USHORT FAR * density_code)
 *
 * INPUT         = pUnitCB          - Pointer to UnitCB
 *                 density_code     - Density Code
 *                                    00 = CD-ROM
 *                                    81 = CD-ROM XA
 *                                    82 = CD-DA
 *
 * OUTPUT        = USHORT           - Packet status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Tosh_GetDensityCode (pUnitCB, density_code)

NPUNITCB pUnitCB;
USHORT   FAR *density_code;

{
   USHORT rc;
   NPIORB_CDB pIORB;
   struct ReadHeader_Data NEAR *pCDBData;


   BuildCDB_ReadHeader(pUnitCB, 0, (NPIORB_CDB FAR *) &pIORB);

   pCDBData = (struct ReadHeader_Data NEAR *) pIORB->CDB_data;

   rc = SubmitIORB_Wait(pUnitCB, pIORB);

   if (rc == STDON)
   {
      switch(pCDBData->cdrom_data_mode)
      {
         case 0x02:
            *density_code = CD_DENSITY_CDXA;
            break;

         case 0x00:
         case 0x01:
         default:
            *density_code = CD_DENSITY_DEFAULT;
            break;
      }
   }
   else
   {
      if (rc == STDON + STERR + ERROR_I24_BAD_COMMAND)
      {
         *density_code = CD_DENSITY_CDDA;
         rc = STDON;
      }
   }
   FreeIORB (pUnitCB, pIORB);
   return (rc);
}


/****************************************************************************
 *
 * FUNCTION NAME = Tosh_GetLastSessionAddr
 *
 * DESCRIPTION   = Get address of last session on multisession disk
 *
 *   This routine returns the address of the last session of a multisession
 *   photo CD disk.  This routine should only be called is the drive is
 *   a Toshiba 3401 or the drive is a non-SCSI CD-ROM which supports
 *   multi-session.
 *
 *   USHORT Tosh_GetLastSessionAddr (NPUNITCB pUnitCB, ULONG FAR * session_addr)
 *
 * INPUT         =  pUnitCB          - Pointer to UnitCB
 *                  session_addr     - Pointer to returned session addr
 *
 * OUTPUT        =  USHORT           - Packet status word
 *
 *                                     if the STERR bit is on, then the disk
 *                                       is not a multisession disk and the
 *                                       session_addr field is not valid
 *
 *                                     if the STERR bit is NOT set, then the
 *                                       disk is a multi-session disk and the
 *                                       session addr field is valid
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Tosh_GetLastSessionAddr (pUnitCB, session_addr)

NPUNITCB pUnitCB;
ULONG    FAR *session_addr;

{
   USHORT rc;
   NPIORB_CDB pIORB;
   union TOSH_ReadDiskInfo_Data NEAR *pCDBData;
   union  AddressType last_session;


   Tosh_BuildCDB_ReadDiskInfo (pUnitCB, TOSH_LASTSESSION_INFO,
                                        (NPIORB_CDB FAR *) &pIORB);

   pCDBData = (union TOSH_ReadDiskInfo_Data NEAR *) pIORB->CDB_data;

   rc = SubmitIORB_Wait(pUnitCB, pIORB);

   if (rc == STDON)
   {
      /*
      ** If zero returned in data fields, then not multisession
      */
      if ( (pCDBData->last_session.amin == 0) &&
           (pCDBData->last_session.asec == 0) &&
           (pCDBData->last_session.aframe == 0) )
      {
         rc = STDON + STERR;
      }
      else
      {
         last_session.ul_redbook.min = BCDtoBinary(pCDBData->last_session.amin);
         last_session.ul_redbook.sec = BCDtoBinary(pCDBData->last_session.asec);
         last_session.ul_redbook.frame =
                                 BCDtoBinary(pCDBData->last_session.aframe);
         last_session.ul_redbook.zero = 0;

         last_session.dword = RedBookToHSG (last_session.dword);

         *session_addr = last_session.dword;
      }

   }
   FreeIORB (pUnitCB, pIORB);
   return (rc);
}

