home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga Shareware Floppies / ma28.dms / ma28.adf / AmiCDROM / source / Csourcefiles.lha / cdrom.c < prev    next >
C/C++ Source or Header  |  1994-09-11  |  17KB  |  650 lines

  1. /* cdrom.c:
  2.  *
  3.  * Basic interaction with the CDROM drive.
  4.  *
  5.  * ----------------------------------------------------------------------
  6.  * This code is (C) Copyright 1993,1994 by Frank Munkert.
  7.  * All rights reserved.
  8.  * This software may be freely distributed and redistributed for
  9.  * non-commercial purposes, provided this notice is included.
  10.  * ----------------------------------------------------------------------
  11.  * History:
  12.  * 
  13.  * 02-Sep-94   fmu   Display READ TOC for Apple CD 150 drives.
  14.  * 01-Sep-94   fmu   Workaround for bad NEC 3X READ TOC command in 
  15.  *             Has_Audio_Tracks() and Data_Tracks().
  16.  * 20-Aug-94   fmu   New function Find_Last_Session ().
  17.  * 23-Jul-94   fmu   Last index modified from 99 to 1 in Start_Play_Audio().
  18.  * 18-May-94   fmu   New drive model: MODEL_CDU_8002 (= Apple CD 150).
  19.  * 17-May-94   fmu   Sense length 20 instead of 18 (needed by ALF controller).
  20.  * 17-Feb-94   fmu   Added support for Toshiba 4101.
  21.  * 06-Feb-94   dmb   - Fixed bug in Test_Unit_Ready() trackdisk support.
  22.  *                   - Fixed bug in Open_CDROM (size of request)
  23.  *                   - Added function Clear_Sector_Buffers().
  24.  * 01-Jan-94   fmu   Added function Data_Tracks() for multisession support.
  25.  * 11-Dec-93   fmu   - Memory type can now be chosen by the user.
  26.  *                   - Addional parameter p_direction for Do_SCSI_Command().
  27.  *                   - Start_Play_Audio() now plays all tracks.
  28.  *                   - Mode_Select() instead of Select_XA_Mode().
  29.  *                   - Support for CDROM drives with 512, 1024 or 2048 bytes
  30.  *                     per block.
  31.  * 06-Dec-93   fmu   New drive type DRIVE_SCSI_2.
  32.  * 09-Nov-93   fmu   Added Select_XA_Mode.
  33.  * 23-Oct-93   fmu   Open_CDROM now returns an error code that tell what
  34.  *                   went wrong.
  35.  * 09-Oct-93   fmu   SAS/C support added.
  36.  * 03-Oct-93   fmu   New buffering algorithm.
  37.  * 27-Sep-93   fmu   Added support for multi-LUN devices.
  38.  * 24-Sep-93   fmu   - SCSI buffers may now reside in fast or chip memory.
  39.  *                   - TD_CHANGESTATE instead of CMD_READ in Test_Unit_Ready
  40.  */
  41.  
  42. #include <string.h>
  43.  
  44. #include <clib/exec_protos.h>
  45. #include <clib/alib_protos.h>
  46.  
  47. #ifdef LATTICE
  48. #include <pragmas/exec_pragmas.h>
  49. #endif
  50.  
  51. #include <devices/trackdisk.h>
  52.  
  53. #include "cdrom.h"
  54.  
  55. #include <limits.h>
  56.  
  57. int g_cdrom_errno;
  58. int g_ignore_blocklength = FALSE;
  59.  
  60. void Determine_Drive_Type (CDROM *p_cd)
  61. {
  62.   t_inquiry_data data;
  63.   char buf[33];
  64.   
  65.   p_cd->scsi_compliance = 1;
  66.   p_cd->model = MODEL_ANY;
  67.  
  68.   if (!Inquire (p_cd, &data))
  69.     return;
  70.  
  71.   if ((data.version & 0x7) >= 2)
  72.     p_cd->scsi_compliance = 2;
  73.  
  74.   if (strncmp (data.vendor, "TOSHIBA", 7) == 0) {
  75.     memcpy (buf, data.product, 32);
  76.     buf[32] = 0;
  77.     if (strstr (buf, "3401") || strstr (buf, "4101"))
  78.       p_cd->model = MODEL_TOSHIBA_3401;
  79.   } else if (strncmp (data.vendor, "SONY", 4) == 0) {
  80.     memcpy (buf, data.product, 32);
  81.     buf[32] = 0;
  82.     if (strstr (buf, "CDU-8002"))
  83.       p_cd->model = MODEL_CDU_8002;
  84.   }
  85. }
  86.  
  87. CDROM *Open_CDROM (char *p_device, int p_scsi_id, int p_use_trackdisk,
  88.            unsigned long p_memory_type,
  89.            int p_std_buffers, int p_file_buffers)
  90. {
  91.   CDROM *cd;
  92.   int i;
  93.   int bufs = p_std_buffers + p_file_buffers + 1;
  94.   
  95.   g_cdrom_errno = CDROMERR_NO_MEMORY;
  96.  
  97.   cd = AllocMem (sizeof (CDROM),
  98.                MEMF_PUBLIC | MEMF_CLEAR | p_memory_type);
  99.   if (!cd)
  100.     return NULL;
  101.  
  102.   cd->std_buffers = p_std_buffers;
  103.   cd->file_buffers = p_file_buffers;
  104.  
  105.   cd->buffer_data = AllocMem (SCSI_BUFSIZE * bufs + 15,
  106.                     MEMF_PUBLIC | p_memory_type);
  107.   if (!cd->buffer_data) {
  108.     Cleanup_CDROM (cd);
  109.     return NULL;
  110.   }
  111.  
  112.   cd->buffers = AllocMem (sizeof (unsigned char *) * bufs, MEMF_PUBLIC);
  113.   if (!cd->buffers) {
  114.     Cleanup_CDROM (cd);
  115.     return NULL;
  116.   }
  117.   
  118.   cd->current_sectors = AllocMem (sizeof (long) * bufs, MEMF_PUBLIC);
  119.   if (!cd->current_sectors) {
  120.     Cleanup_CDROM (cd);
  121.     return NULL;
  122.   }
  123.  
  124.   cd->last_used = AllocMem (sizeof (unsigned long) * p_std_buffers,
  125.                   MEMF_PUBLIC | MEMF_CLEAR);
  126.   if (!cd->last_used) {
  127.     Cleanup_CDROM (cd);
  128.     return NULL;
  129.   }
  130.   
  131.   /* make the buffer quad-word aligned. This greatly helps 
  132.    * performance on '040-powered systems with DMA SCSI
  133.    * controllers.
  134.    */
  135.  
  136.   cd->buffers[0] = (UBYTE *)(((ULONG)cd->buffer_data + 15) & ~15);
  137.  
  138.   for (i=1; i<bufs; i++)
  139.     cd->buffers[i] = cd->buffers[0] + i * SCSI_BUFSIZE;
  140.  
  141.   cd->port = CreateMsgPort ();
  142.   if (!cd->port) {
  143.     g_cdrom_errno = CDROMERR_MSGPORT;
  144.     Cleanup_CDROM (cd);
  145.     return NULL;
  146.   }
  147.  
  148.   cd->scsireq = CreateIORequest (cd->port, sizeof (struct IOExtTD));
  149.   if (!cd->scsireq) {
  150.     g_cdrom_errno = CDROMERR_IOREQ;
  151.     Cleanup_CDROM (cd);
  152.     return NULL;
  153.   }
  154.  
  155.   if (OpenDevice ((UBYTE *) p_device, p_scsi_id,
  156.                   (struct IORequest *) cd->scsireq, 0)) {
  157.     g_cdrom_errno = CDROMERR_DEVICE;
  158.     Cleanup_CDROM (cd);
  159.     return NULL;
  160.   }
  161.  
  162.   cd->device_open = TRUE;
  163.  
  164.   for (i=0; i<bufs; i++)
  165.     cd->current_sectors[i] = -1;
  166.  
  167.   if (p_use_trackdisk) {
  168.     cd->scsireq->io_Command = CMD_CLEAR;
  169.     DoIO ((struct IORequest *) cd->scsireq);
  170.   }
  171.  
  172.   cd->use_trackdisk = p_use_trackdisk;
  173.   cd->t_changeint = -1;
  174.   cd->t_changeint2 = -2;
  175.  
  176.   /* The LUN is the 2nd digit of the SCSI id number: */
  177.   cd->lun = (p_scsi_id / 10) % 10;
  178.  
  179.   /* 'tick' is incremented every time a sector is accessed. */
  180.   cd->tick = 0;
  181.  
  182.   g_cdrom_errno = 0;
  183.  
  184.   Determine_Drive_Type (cd);
  185.  
  186.   if (g_ignore_blocklength) {
  187.     cd->block_length = 0;
  188.     cd->blocking_factor = 0;
  189.   } else {
  190.     cd->block_length = Block_Length (cd);
  191.     switch (cd->block_length) {
  192.     case 2048:
  193.       cd->blocking_factor = 0;
  194.       break;
  195.     case 1024:
  196.       cd->blocking_factor = 1;
  197.       break;
  198.     case 512:
  199.       cd->blocking_factor = 2;
  200.       break;
  201.     case 0:
  202.       cd->blocking_factor = 0;
  203.       break;
  204.     default:
  205.       g_cdrom_errno = CDROMERR_BLOCKSIZE;
  206.       Cleanup_CDROM (cd);
  207.       return NULL;
  208.     }
  209.   }
  210.  
  211.   return cd;
  212. }
  213.  
  214. int Do_SCSI_Command (CDROM *p_cd, unsigned char *p_buf, long p_buf_length,
  215.              unsigned char *p_command, int p_length, int p_direction)
  216. {
  217.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  218.  
  219.   p_cd->scsireq->io_Length   = sizeof (struct SCSICmd);
  220.   p_cd->scsireq->io_Data     = (APTR) &p_cd->cmd;
  221.   p_cd->scsireq->io_Command  = HD_SCSICMD;
  222.  
  223.   p_cd->cmd.scsi_Data        = (UWORD *) p_buf;
  224.   p_cd->cmd.scsi_Length      = p_buf_length;
  225.   p_cd->cmd.scsi_Flags       = SCSIF_AUTOSENSE | p_direction;
  226.   p_cd->cmd.scsi_SenseData   = (UBYTE *) p_cd->sense;
  227.   p_cd->cmd.scsi_SenseLength = 20;
  228.   p_cd->cmd.scsi_SenseActual = 0;
  229.   p_cd->cmd.scsi_Command     = (UBYTE *) p_command;
  230.   p_cd->cmd.scsi_CmdLength   = p_length;
  231.  
  232.   p_command[1] |= p_cd->lun << 5;
  233.  
  234.   DoIO ((struct IORequest *) p_cd->scsireq);
  235.   if (p_cd->cmd.scsi_Status) {
  236.     int i;
  237.     for (i=0; i<bufs; i++)
  238.       p_cd->current_sectors[i] = -1;
  239.     return 0;
  240.   } else
  241.     return 1;
  242. }
  243.  
  244. int Read_From_Drive (CDROM *p_cd, unsigned char *p_buf, long p_buf_length,
  245.              long p_sector, int p_number_of_sectors)
  246. {
  247.   static unsigned char cmd[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  248.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  249.  
  250. #ifdef DEBUG_SECTORS
  251.   extern void *dbprintf (char *, ...);
  252.  
  253.   if (p_number_of_sectors == 1)
  254.     dbprintf ("[%ld]", p_sector);
  255.   else
  256.     dbprintf ("[%ld-%ld]", p_sector, p_sector + p_number_of_sectors - 1);
  257. #endif
  258.  
  259.   if (p_cd->use_trackdisk) {
  260.     p_cd->scsireq->io_Length   = 2048 * p_number_of_sectors;
  261.     p_cd->scsireq->io_Data     = (APTR) p_buf;
  262.     p_cd->scsireq->io_Offset   = (ULONG) p_sector * 2048;
  263.     p_cd->scsireq->io_Command  = CMD_READ;
  264.  
  265.     DoIO ((struct IORequest *) p_cd->scsireq);
  266.     if (p_cd->scsireq->io_Error) {
  267.       int i;
  268.       for (i=0; i<bufs; i++)
  269.         p_cd->current_sectors[i] = -1;
  270.       return 0;
  271.     } else
  272.       return 1;
  273.   } else {
  274.     long sector = p_sector << p_cd->blocking_factor;
  275.     cmd[5] = sector & 0xff;
  276.     cmd[4] = (sector >> 8) & 0xff;
  277.     cmd[3] = (sector >> 16) & 0x1f;
  278.  
  279.     cmd[8] = p_number_of_sectors << p_cd->blocking_factor;
  280.  
  281.     return Do_SCSI_Command (p_cd, p_buf, p_buf_length, cmd, sizeof (cmd),
  282.                     SCSIF_READ);
  283.   }
  284. }
  285.  
  286. /* Read one sector from the CDROM drive.
  287.  */
  288.  
  289. int Read_Sector (CDROM *p_cd, long p_sector)
  290. {
  291.   int status;
  292.   int i;
  293.   int maxbuf = p_cd->std_buffers;
  294.   int loc;
  295.  
  296.   p_cd->tick++;
  297.  
  298.   for (i=0; i<maxbuf; i++)
  299.     if (p_cd->current_sectors[i] == p_sector) {
  300.       p_cd->buffer = p_cd->buffers[i];
  301.       p_cd->last_used[i] = p_cd->tick;
  302.       return 1;
  303.     }
  304.  
  305.   /* find an empty buffer position: */
  306.   for (loc=0; loc<maxbuf; loc++)
  307.     if (p_cd->current_sectors[loc] == -1)
  308.       break;
  309.  
  310.   if (loc==maxbuf) {
  311.     /* no free buffer position; remove the buffer that is unused
  312.        for the longest time: */
  313.     unsigned long oldest_tick = ULONG_MAX;
  314.     unsigned long tick;
  315.  
  316.     for (loc=0, i=0; i<maxbuf; i++) {
  317.       tick = p_cd->last_used[i];
  318.       if (tick < oldest_tick)
  319.         loc = i, oldest_tick = tick;
  320.     }
  321.   }
  322.  
  323.   status = Read_From_Drive (p_cd, p_cd->buffers[loc], SCSI_BUFSIZE,
  324.                   p_sector, 1);
  325.   if (status) {
  326.     p_cd->current_sectors[loc] = p_sector;
  327.     p_cd->buffer = p_cd->buffers[loc];
  328.     p_cd->last_used[loc] = p_cd->tick;
  329.   }
  330.  
  331.   return status;
  332. }
  333.  
  334. /* Read_Contiguous_Sectors uses the 'file buffers' instead of the
  335.  * 'standard buffers'. Additionaly, more than one sector may be read
  336.  * with a single SCSI command. This may cause a substantial increase
  337.  * in speed when reading large files.
  338.  */
  339.  
  340. int Read_Contiguous_Sectors (CDROM *p_cd, long p_sector, long p_last_sector)
  341. {
  342.   int status;
  343.   int i;
  344.   int maxbuf = p_cd->std_buffers + p_cd->file_buffers;
  345.   int len;
  346.  
  347.   for (i=p_cd->std_buffers; i<maxbuf; i++)
  348.     if (p_cd->current_sectors[i] == p_sector) {
  349.       p_cd->buffer = p_cd->buffers[i];
  350.       return 1;
  351.     }
  352.  
  353.   if (p_last_sector <= p_sector)
  354.     len = 1;
  355.   else {
  356.     len = p_last_sector - p_sector + 1;
  357.     if (len > p_cd->file_buffers)
  358.       len = p_cd->file_buffers;
  359.     if (len > 255)
  360.       len = 255;
  361.   }
  362.  
  363.   status = Read_From_Drive (p_cd, p_cd->buffers[p_cd->std_buffers],
  364.                   SCSI_BUFSIZE * len, p_sector, len);
  365.   if (status) {
  366.     long sector = p_sector;
  367.     for (i=p_cd->std_buffers; len; i++, len--)
  368.       p_cd->current_sectors[i] = sector++;
  369.     p_cd->buffer = p_cd->buffers[p_cd->std_buffers];
  370.   }
  371.  
  372.   return status;
  373. }
  374.  
  375. int Test_Unit_Ready (CDROM *p_cd)
  376. {
  377.   if (p_cd->use_trackdisk) {
  378.     p_cd->scsireq->io_Command = TD_CHANGENUM;
  379.     if (!DoIO ((struct IORequest *) p_cd->scsireq)) {
  380.       if (p_cd->scsireq->io_Error==0)
  381.         p_cd->t_changeint = p_cd->scsireq->io_Actual;
  382.     }
  383.     p_cd->scsireq->io_Command = TD_CHANGESTATE;
  384.     if (!DoIO ((struct IORequest *) p_cd->scsireq)) {
  385.       if (p_cd->scsireq->io_Error==0 &&
  386.           p_cd->scsireq->io_Actual==0)
  387.         return TRUE;
  388.     }
  389.     return FALSE;
  390.   } else {
  391.     int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  392.     static unsigned char cmd[6] = { 0, 0, 0, 0, 0, 0 };
  393.  
  394.     return Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], SCSI_BUFSIZE,
  395.                     cmd, 6, SCSIF_READ);
  396.   }
  397. }
  398.  
  399. int Is_XA_Mode_Disk (CDROM *p_cd)
  400. {
  401.   static unsigned char cmd[10] = { 0xC7, 3, 0, 0, 0, 0, 0, 0, 0, 0 };
  402.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  403.  
  404.   if (!Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], 4,
  405.               cmd, 10, SCSIF_READ))
  406.     return FALSE;
  407.  
  408.   return *(p_cd->buffers[dummy_buf]) == 0x20;
  409. }
  410.  
  411. int Mode_Select (CDROM *p_cd, int p_mode, int p_block_length)
  412. {
  413.   static unsigned char cmd[6] = { 0x15, 0x10, 0, 0, 12, 0 };
  414.   static unsigned char mode[12] = { 0, 0, 0, 8,
  415.                     0, 0, 0, 0, 0, 0, 0, 0 };
  416.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  417.  
  418.   if (p_cd->use_trackdisk)
  419.     return FALSE;
  420.  
  421.   p_cd->block_length = p_block_length;
  422.   switch (p_cd->block_length) {
  423.   case 2048:
  424.     p_cd->blocking_factor = 0;
  425.     break;
  426.   case 1024:
  427.     p_cd->blocking_factor = 1;
  428.     break;
  429.   case 512:
  430.     p_cd->blocking_factor = 2;
  431.     break;
  432.   }
  433.  
  434.   mode[4] = p_mode;
  435.   mode[9] = p_block_length >> 16;
  436.   mode[10] = (p_block_length >> 8) & 0xff;
  437.   mode[11] = p_block_length & 0xff;
  438.  
  439.   memcpy (p_cd->buffers[dummy_buf], mode, sizeof (mode));
  440.   return Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], sizeof (mode),
  441.                 cmd, 6, SCSIF_WRITE);
  442. }
  443.  
  444. int Inquire (CDROM *p_cd, t_inquiry_data *p_data)
  445. {
  446.   static unsigned char cmd[6] = { 0x12, 0, 0, 0, 96, 0 };
  447.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  448.   
  449.   if (p_cd->use_trackdisk)
  450.     return FALSE;
  451.  
  452.   if (!Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], 96,
  453.               cmd, 6, SCSIF_READ))
  454.     return FALSE;
  455.   
  456.   memcpy (p_data, p_cd->buffers[dummy_buf], sizeof (*p_data));
  457.   return 1;
  458. }
  459.  
  460. #define TOC_SIZE 804
  461.  
  462. t_toc_data *Read_TOC (CDROM *p_cd, t_toc_header *p_toc_header)
  463. {
  464.   static unsigned char cmd[10] = { 0x43, 0, 0, 0, 0, 0, 0,
  465.                      TOC_SIZE >> 8, TOC_SIZE & 0xff, 0 };
  466.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  467.  
  468.   if (p_cd->use_trackdisk)
  469.     return NULL;
  470.  
  471.   if (p_cd->model == MODEL_CDU_8002) /* READ TOC not supported by this drive */
  472.     return NULL;
  473.  
  474.   if (!Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], TOC_SIZE,
  475.               cmd, 10, SCSIF_READ))
  476.     return NULL;
  477.  
  478.   memcpy (p_toc_header, p_cd->buffers[dummy_buf], sizeof (*p_toc_header));
  479.   return (t_toc_data *) (p_cd->buffers[dummy_buf] + 4);
  480. }
  481.  
  482. int Has_Audio_Tracks (CDROM *p_cd)
  483. {
  484.   t_toc_header hdr;
  485.   t_toc_data *toc;
  486.   int i, len;
  487.   
  488.   if (!(toc = Read_TOC (p_cd, &hdr)))
  489.     return FALSE;
  490.  
  491.   len = hdr.length / 8;
  492.   for (i=0; i<len; i++) {
  493.     if (toc[i].track_number <= 99 &&
  494.         !(toc[i].flags & 4))
  495.       return toc[i].track_number;
  496.   }
  497.   return FALSE;
  498. }
  499.  
  500. /*
  501.  * Create a buffer containing the start addresses of all data tracks
  502.  * on the disk.
  503.  *
  504.  * Returns:
  505.  *  number of tracks or -1 on error.
  506.  */
  507.  
  508. int Data_Tracks (CDROM *p_cd, unsigned long** p_buf)
  509. {
  510.   int cnt=0;
  511.   t_toc_header hdr;
  512.   t_toc_data *toc;
  513.   int i, j, len;
  514.   
  515.   if (!(toc = Read_TOC (p_cd, &hdr)))
  516.     return -1;
  517.  
  518.   len = hdr.length / 8;
  519.  
  520.   /* count number of data tracks: */
  521.   for (i=0; i<len; i++)
  522.     if (toc[i].track_number <= 99 && (toc[i].flags & 4))
  523.       cnt++;
  524.  
  525.   if (cnt == 0)
  526.     return 0;
  527.  
  528.   /* allocate memory for output buffer: */
  529.   *p_buf = (unsigned long*) AllocVec (cnt * sizeof (unsigned long*),
  530.                         MEMF_PUBLIC);
  531.   if (!*p_buf)
  532.     return -1;
  533.  
  534.   /* fill output buffer: */
  535.   for (i=0, j=0; i<len; i++)
  536.     if (toc[i].track_number <= 99 && (toc[i].flags & 4))
  537.       (*p_buf)[j++] = toc[i].address;
  538.  
  539.   return cnt;
  540. }
  541.  
  542. int Start_Play_Audio (CDROM *p_cd)
  543. {
  544.   static unsigned char cmd[10] = { 0x48, 0, 0, 0, 0, 1, 0, 99, 1, 0 };
  545.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  546.  
  547.   if (p_cd->use_trackdisk ||
  548.       (p_cd->scsi_compliance == 1 && p_cd->model == MODEL_ANY))
  549.     return FALSE;
  550.  
  551.   if (p_cd->model == MODEL_CDU_8002)
  552.     cmd[0] = 0xC9;
  553.  
  554.   cmd[4] = Has_Audio_Tracks (p_cd);
  555.  
  556.   return Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], 0,
  557.                     cmd, 10, SCSIF_WRITE);
  558. }
  559.  
  560. int Stop_Play_Audio (CDROM *p_cd)
  561. {
  562.   static unsigned char cmd[6] = { 0x1B, 0, 0, 0, 0, 0 };
  563.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  564.  
  565.   if (p_cd->use_trackdisk)
  566.     return FALSE;
  567.  
  568.   return Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], 0,
  569.                     cmd, 6, SCSIF_WRITE);
  570. }
  571.  
  572. int Block_Length (CDROM *p_cd)
  573. {
  574.   static unsigned char cmd[6] = { 0x1A, 0, 1, 0, 100, 0 };
  575.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  576.   unsigned char *buf = p_cd->buffers[dummy_buf];
  577.  
  578.   if (p_cd->use_trackdisk)
  579.     return 0;
  580.   
  581.   if (!Do_SCSI_Command (p_cd, buf, 100,    cmd, 6, SCSIF_READ))
  582.     return 0;
  583.  
  584.   if (buf[3] == 0)
  585.     return 0;
  586.   
  587.   return (buf[9]<<16) + (buf[10]<<8) + buf[11];
  588. }
  589.  
  590. void Cleanup_CDROM (CDROM *p_cd)
  591. {
  592.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  593.  
  594.   if (p_cd->device_open)
  595.     CloseDevice ((struct IORequest *) p_cd->scsireq);
  596.   if (p_cd->scsireq)
  597.     DeleteIORequest (p_cd->scsireq);
  598.   if (p_cd->port)
  599.     DeleteMsgPort (p_cd->port);
  600.   if (p_cd->last_used)
  601.     FreeMem (p_cd->last_used, sizeof (unsigned long) * p_cd->std_buffers);
  602.   if (p_cd->current_sectors)
  603.     FreeMem (p_cd->current_sectors, sizeof (long) * bufs);
  604.   if (p_cd->buffers)
  605.     FreeMem (p_cd->buffers, sizeof (unsigned char *) * bufs);
  606.   if (p_cd->buffer_data)
  607.     FreeMem (p_cd->buffer_data, SCSI_BUFSIZE * bufs + 15);
  608.   FreeMem (p_cd, sizeof (CDROM));
  609. }
  610.  
  611. void Clear_Sector_Buffers (CDROM *p_cd)
  612. {
  613.   int i;
  614.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  615.  
  616.   for (i=0; i<bufs; i++)
  617.     p_cd->current_sectors[i] = -1;
  618. }
  619.  
  620. /* Finds offset of last session. (Not supported by all CDROM drives)
  621.  *
  622.  * Returns: - FALSE if there is no special SCSI command to determine the
  623.  *            offset of the last session.
  624.  *          - TRUE if the offset of the last session has been determined.
  625.  */
  626.  
  627. int Find_Last_Session (CDROM *p_cd, unsigned long *p_result)
  628. {
  629.   static unsigned char cmd[10] = { 0xC7, 3, 0, 0, 0, 0, 0, 0, 0, 0 };
  630.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  631.   unsigned char *buf = p_cd->buffers[dummy_buf];
  632.   int min, sec, frame;
  633.  
  634.   if (p_cd->use_trackdisk)
  635.     return FALSE;
  636.  
  637.   if (p_cd->model != MODEL_TOSHIBA_3401)
  638.     return FALSE;
  639.  
  640.   if (!Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], SCSI_BUFSIZE,
  641.               cmd, sizeof (cmd), SCSIF_READ)) 
  642.     return FALSE;
  643.  
  644.   min = (buf[1] & 0xF) + ((buf[1] & 0xF0) >> 4) * 10;
  645.   sec = (buf[2] & 0xF) + ((buf[2] & 0xF0) >> 4) * 10;
  646.   frame = (buf[3] & 0xF) + ((buf[3] & 0xF0) >> 4) * 10;
  647.   *p_result = frame + sec * 75 + min * (75 * 60) - 150;
  648.   return TRUE;
  649. }
  650.