home *** CD-ROM | disk | FTP | other *** search
/ AMIGA PD 1 / AMIGA-PD-1.iso / Aminet / Tools / Useful / AmiCDROM / src / cdrom.c next >
C/C++ Source or Header  |  1994-10-03  |  17KB  |  684 lines

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