home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / useful / dist / disk / cdrom / amicdrom / cdrom.c < prev    next >
C/C++ Source or Header  |  1994-04-17  |  16KB  |  601 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.  * 17-Feb-94   fmu   Added support for Toshiba 4101.
  14.  * 06-Feb-94   dmb   - Fixed bug in Test_Unit_Ready() trackdisk support.
  15.  *                   - Fixed bug in Open_CDROM (size of request)
  16.  *                   - Added function Clear_Sector_Buffers().
  17.  * 01-Jan-94   fmu   Added function Data_Tracks() for multisession support.
  18.  * 11-Dec-93   fmu   - Memory type can now be chosen by the user.
  19.  *                   - Addional parameter p_direction for Do_SCSI_Command().
  20.  *                   - Start_Play_Audio() now plays all tracks.
  21.  *                   - Mode_Select() instead of Select_XA_Mode().
  22.  *                   - Support for CDROM drives with 512, 1024 or 2048 bytes
  23.  *                     per block.
  24.  * 06-Dec-93   fmu   New drive type DRIVE_SCSI_2.
  25.  * 09-Nov-93   fmu   Added Select_XA_Mode.
  26.  * 23-Oct-93   fmu   Open_CDROM now returns an error code that tell what
  27.  *                   went wrong.
  28.  * 09-Oct-93   fmu   SAS/C support added.
  29.  * 03-Oct-93   fmu   New buffering algorithm.
  30.  * 27-Sep-93   fmu   Added support for multi-LUN devices.
  31.  * 24-Sep-93   fmu   - SCSI buffers may now reside in fast or chip memory.
  32.  *                   - TD_CHANGESTATE instead of CMD_READ in Test_Unit_Ready
  33.  */
  34.  
  35. #include <string.h>
  36.  
  37. #include <clib/exec_protos.h>
  38. #include <clib/alib_protos.h>
  39.  
  40. #ifdef AZTEC_C
  41. #include <pragmas/exec_lib.h>
  42. #endif
  43. #ifdef LATTICE
  44. #include <pragmas/exec_pragmas.h>
  45. #endif
  46. #if defined (_DCC) && defined (REGISTERED)
  47. #include <pragmas/exec_pragmas.h>
  48. extern struct Library *SysBase;
  49. #endif
  50.  
  51. #include <devices/trackdisk.h>
  52.  
  53. #include <limits.h>
  54.  
  55. #include "cdrom.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->drive_type = DRIVE_ANY;
  66.  
  67.   if (!Inquire (p_cd, &data))
  68.     return;
  69.  
  70.   if ((data.version & 0x7) >= 2)
  71.     p_cd->drive_type = DRIVE_SCSI_2;
  72.  
  73.   if (strncmp (data.vendor, "TOSHIBA", 7) == 0) {
  74.     memcpy (buf, data.product, 32);
  75.     buf[32] = 0;
  76.     if (strstr (buf, "3401") || strstr (buf, "4101"))
  77.       p_cd->drive_type = DRIVE_TOSHIBA_3401;
  78.   }
  79. }
  80.  
  81. CDROM *Open_CDROM (char *p_device, int p_scsi_id, int p_use_trackdisk,
  82.            unsigned long p_memory_type,
  83.            int p_std_buffers, int p_file_buffers)
  84. {
  85.   CDROM *cd;
  86.   int i;
  87.   int bufs = p_std_buffers + p_file_buffers + 1;
  88.   
  89.   g_cdrom_errno = CDROMERR_NO_MEMORY;
  90.  
  91.   cd = AllocMem (sizeof (CDROM),
  92.                MEMF_PUBLIC | MEMF_CLEAR | p_memory_type);
  93.   if (!cd)
  94.     return NULL;
  95.  
  96.   cd->std_buffers = p_std_buffers;
  97.   cd->file_buffers = p_file_buffers;
  98.  
  99.   cd->buffer_data = AllocMem (SCSI_BUFSIZE * bufs + 15,
  100.                     MEMF_PUBLIC | p_memory_type);
  101.   if (!cd->buffer_data) {
  102.     Cleanup_CDROM (cd);
  103.     return NULL;
  104.   }
  105.  
  106.   cd->buffers = AllocMem (sizeof (unsigned char *) * bufs, MEMF_PUBLIC);
  107.   if (!cd->buffers) {
  108.     Cleanup_CDROM (cd);
  109.     return NULL;
  110.   }
  111.   
  112.   cd->current_sectors = AllocMem (sizeof (long) * bufs, MEMF_PUBLIC);
  113.   if (!cd->current_sectors) {
  114.     Cleanup_CDROM (cd);
  115.     return NULL;
  116.   }
  117.  
  118.   cd->last_used = AllocMem (sizeof (unsigned long) * p_std_buffers,
  119.                   MEMF_PUBLIC | MEMF_CLEAR);
  120.   if (!cd->last_used) {
  121.     Cleanup_CDROM (cd);
  122.     return NULL;
  123.   }
  124.   
  125.   /* make the buffer quad-word aligned. This greatly helps 
  126.    * performance on '040-powered systems with DMA SCSI
  127.    * controllers.
  128.    */
  129.  
  130.   cd->buffers[0] = (UBYTE *)(((ULONG)cd->buffer_data + 15) & ~15);
  131.  
  132.   for (i=1; i<bufs; i++)
  133.     cd->buffers[i] = cd->buffers[0] + i * SCSI_BUFSIZE;
  134.  
  135.   cd->port = CreateMsgPort ();
  136.   if (!cd->port) {
  137.     g_cdrom_errno = CDROMERR_MSGPORT;
  138.     Cleanup_CDROM (cd);
  139.     return NULL;
  140.   }
  141.  
  142.   cd->scsireq = CreateIORequest (cd->port, sizeof (struct IOExtTD));
  143.   if (!cd->scsireq) {
  144.     g_cdrom_errno = CDROMERR_IOREQ;
  145.     Cleanup_CDROM (cd);
  146.     return NULL;
  147.   }
  148.  
  149.   if (OpenDevice ((UBYTE *) p_device, p_scsi_id,
  150.                   (struct IORequest *) cd->scsireq, 0)) {
  151.     g_cdrom_errno = CDROMERR_DEVICE;
  152.     Cleanup_CDROM (cd);
  153.     return NULL;
  154.   }
  155.  
  156.   cd->device_open = TRUE;
  157.  
  158.   for (i=0; i<bufs; i++)
  159.     cd->current_sectors[i] = -1;
  160.  
  161.   cd->use_trackdisk = p_use_trackdisk;
  162.   cd->t_changeint = -1;
  163.   cd->t_changeint2 = -2;
  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.   g_cdrom_errno = 0;
  172.  
  173.   Determine_Drive_Type (cd);
  174.  
  175.   if (g_ignore_blocklength) {
  176.     cd->block_length = 0;
  177.     cd->blocking_factor = 0;
  178.   } else {
  179.     cd->block_length = Block_Length (cd);
  180.     switch (cd->block_length) {
  181.     case 2048:
  182.       cd->blocking_factor = 0;
  183.       break;
  184.     case 1024:
  185.       cd->blocking_factor = 1;
  186.       break;
  187.     case 512:
  188.       cd->blocking_factor = 2;
  189.       break;
  190.     case 0:
  191.       cd->blocking_factor = 0;
  192.       break;
  193.     default:
  194.       g_cdrom_errno = CDROMERR_BLOCKSIZE;
  195.       Cleanup_CDROM (cd);
  196.       return NULL;
  197.     }
  198.   }
  199.  
  200.   return cd;
  201. }
  202.  
  203. int Do_SCSI_Command (CDROM *p_cd, unsigned char *p_buf, long p_buf_length,
  204.              unsigned char *p_command, int p_length, int p_direction)
  205. {
  206.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  207.  
  208.   p_cd->scsireq->io_Length   = sizeof (struct SCSICmd);
  209.   p_cd->scsireq->io_Data     = (APTR) &p_cd->cmd;
  210.   p_cd->scsireq->io_Command  = HD_SCSICMD;
  211.  
  212.   p_cd->cmd.scsi_Data        = (UWORD *) p_buf;
  213.   p_cd->cmd.scsi_Length      = p_buf_length;
  214.   p_cd->cmd.scsi_Flags       = SCSIF_AUTOSENSE | p_direction;
  215.   p_cd->cmd.scsi_SenseData   = (UBYTE *) p_cd->sense;
  216.   p_cd->cmd.scsi_SenseLength = 18;
  217.   p_cd->cmd.scsi_SenseActual = 0;
  218.   p_cd->cmd.scsi_Command     = (UBYTE *) p_command;
  219.   p_cd->cmd.scsi_CmdLength   = p_length;
  220.  
  221.   p_command[1] |= p_cd->lun << 5;
  222.  
  223.   DoIO ((struct IORequest *) p_cd->scsireq);
  224.   if (p_cd->cmd.scsi_Status) {
  225.     int i;
  226.     for (i=0; i<bufs; i++)
  227.       p_cd->current_sectors[i] = -1;
  228.     return 0;
  229.   } else
  230.     return 1;
  231. }
  232.  
  233. int Read_From_Drive (CDROM *p_cd, unsigned char *p_buf, long p_buf_length,
  234.              long p_sector, int p_number_of_sectors)
  235. {
  236.   static unsigned char cmd[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  237.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  238.  
  239. #ifdef DEBUG_SECTORS
  240.   extern void *dbprintf (char *, ...);
  241.  
  242.   if (p_number_of_sectors == 1)
  243.     dbprintf ("[%ld]", p_sector);
  244.   else
  245.     dbprintf ("[%ld-%ld]", p_sector, p_sector + p_number_of_sectors - 1);
  246. #endif
  247.  
  248.   if (p_cd->use_trackdisk) {
  249.     p_cd->scsireq->io_Length   = 2048 * p_number_of_sectors;
  250.     p_cd->scsireq->io_Data     = (APTR) p_buf;
  251.     p_cd->scsireq->io_Offset   = (ULONG) p_sector * 2048;
  252.     p_cd->scsireq->io_Command  = CMD_READ;
  253.  
  254.     DoIO ((struct IORequest *) p_cd->scsireq);
  255.     if (p_cd->scsireq->io_Error) {
  256.       int i;
  257.       for (i=0; i<bufs; i++)
  258.         p_cd->current_sectors[i] = -1;
  259.       return 0;
  260.     } else
  261.       return 1;
  262.   } else {
  263.     long sector = p_sector << p_cd->blocking_factor;
  264.     cmd[5] = sector & 0xff;
  265.     cmd[4] = (sector >> 8) & 0xff;
  266.     cmd[3] = (sector >> 16) & 0x1f;
  267.  
  268.     cmd[8] = p_number_of_sectors << p_cd->blocking_factor;
  269.  
  270.     return Do_SCSI_Command (p_cd, p_buf, p_buf_length, cmd, sizeof (cmd),
  271.                     SCSIF_READ);
  272.   }
  273. }
  274.  
  275. /* Read one sector from the CDROM drive.
  276.  */
  277.  
  278. int Read_Sector (CDROM *p_cd, long p_sector)
  279. {
  280.   int status;
  281.   int i;
  282.   int maxbuf = p_cd->std_buffers;
  283.   int loc;
  284.  
  285.   p_cd->tick++;
  286.  
  287.   for (i=0; i<maxbuf; i++)
  288.     if (p_cd->current_sectors[i] == p_sector) {
  289.       p_cd->buffer = p_cd->buffers[i];
  290.       p_cd->last_used[i] = p_cd->tick;
  291.       return 1;
  292.     }
  293.  
  294.   /* find an empty buffer position: */
  295.   for (loc=0; loc<maxbuf; loc++)
  296.     if (p_cd->current_sectors[loc] == -1)
  297.       break;
  298.  
  299.   if (loc==maxbuf) {
  300.     /* no free buffer position; remove the buffer that is unused
  301.        for the longest time: */
  302.     unsigned long oldest_tick = ULONG_MAX;
  303.     unsigned long tick;
  304.  
  305.     for