home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / cdrom / compactplayer / source / scsi.c < prev    next >
C/C++ Source or Header  |  1995-12-28  |  9KB  |  430 lines

  1. #include "sysheaders.h"
  2. #include "cdpanel.h"
  3. #include "CompactPlayer.h"
  4.  
  5. /********************************************************
  6.  * SCSI
  7.  */
  8.  
  9. struct MsgPort *SCSIPort;
  10. struct IOStdReq *SCSIIO;
  11. STRPTR Device = "scsi.device";
  12. ULONG Unit = 6;
  13. UBYTE *DataBuf;
  14. UBYTE *TOCBuf;
  15. UBYTE *SenseData;
  16. BOOL Ejected = FALSE;
  17. BOOL JustStarted = FALSE;
  18.  
  19. //#define SINGLE_TRACK_PLAY 1
  20.  
  21. #define BLOCKSPERSECOND 75    /* CD blocks per second of audio */
  22.  
  23. int __stdargs
  24. Open_SCSI(void)
  25. {
  26.     if ((DataBuf     = AllocVec(DATA_LEN, MEMF_CHIP | MEMF_CLEAR)) &&
  27.         (TOCBuf     = AllocVec(TOC_LEN, MEMF_CHIP)) &&
  28.         (SenseData     = AllocVec(SENSE_LEN, MEMF_CHIP | MEMF_CLEAR)) &&
  29.         (SCSIPort     = CreateMsgPort()) &&
  30.         (SCSIIO     = CreateIORequest(SCSIPort, sizeof(struct IOStdReq))) &&
  31.         !OpenDevice(Device, Unit, (struct IORequest *) SCSIIO, NULL))
  32.     {
  33.         SCSIIO->io_Command = HD_SCSICMD;
  34.         
  35.         CD_Eject = Eject_SCSI;
  36.         CD_Stop = Stop_SCSI;
  37.         CD_Play = Play_SCSI;
  38.         CD_PauseResume = PauseResume_SCSI;
  39.         CD_Seek = Seek_SCSI;
  40.         CD_Snoop = Snoop_SCSI;
  41.         CD_ReadTOC = ReadTOC_SCSI;
  42.         CD_IsCD = IsCD_SCSI;
  43.         CD_Close = (void (*)(void))Close_SCSI;
  44.         
  45.         if (CD_IsCD())
  46.             return 0;
  47.         else
  48.             ErrorMsg(GS(DEVICE_FAIL), Device, Unit);
  49.     }
  50.     else
  51.         ErrorMsg(GS(SCSI_FAIL), Device, Unit);
  52.     Close_SCSI();
  53.     return -1;
  54. }
  55.  
  56. void __stdargs
  57. Close_SCSI(void)
  58. {
  59.     if (SCSIIO)
  60.     {
  61.         if (SCSIIO->io_Command == HD_SCSICMD)
  62.             CloseDevice((struct IORequest *) SCSIIO);
  63.         DeleteIORequest(SCSIIO);
  64.         SCSIIO = NULL;
  65.     }
  66.     if (SCSIPort)
  67.     {
  68.         DeleteMsgPort(SCSIPort);
  69.         SCSIPort = NULL;
  70.     }
  71.     if (SenseData)
  72.     {
  73.         FreeVec(SenseData);
  74.         SenseData = NULL;
  75.     }
  76.     if (TOCBuf)
  77.     {
  78.         FreeVec(TOCBuf);
  79.         TOCBuf = NULL;
  80.     }
  81.     if (DataBuf)
  82.     {
  83.         FreeVec(DataBuf);
  84.         DataBuf = NULL;
  85.     }
  86.  
  87.     CD_Eject = (void (*)(UBYTE))Dummy;
  88.     CD_Stop = (void (*)(void))Dummy;
  89.     CD_Play = (void (*)(ULONG))Dummy;
  90.     CD_PauseResume = (void (*)(UBYTE))Dummy;
  91.     CD_Seek = (void (*)(LONG))Dummy;
  92.     CD_Snoop = (ULONG (*)(ULONG *, ULONG *, ULONG *, ULONG))Dummy;
  93.     CD_ReadTOC = (ULONG (*)(void))Dummy;
  94.     CD_IsCD = (BOOL (*)(void))Dummy;
  95.     CD_Close = (void (*)(void))Dummy;
  96. }
  97.  
  98. static int
  99. DoSCSI( APTR data, int dsize, APTR cmd, int csize, UBYTE flags )
  100. {
  101.     if (SCSIIO)
  102.     {
  103.         static struct SCSICmd ScsiCmd;
  104.  
  105.         /* send a SCSI Direct command */
  106.  
  107.         ScsiCmd.scsi_Command = cmd;
  108.         ScsiCmd.scsi_CmdLength = csize;
  109.         ScsiCmd.scsi_Data = data;
  110.         ScsiCmd.scsi_Length = dsize;
  111.         ScsiCmd.scsi_SenseData = SenseData;
  112.         ScsiCmd.scsi_SenseLength = SENSE_LEN;
  113.         ScsiCmd.scsi_SenseActual = 0;
  114.         ScsiCmd.scsi_Flags = flags;
  115.     
  116.         SCSIIO->io_Command = HD_SCSICMD;
  117.         SCSIIO->io_Data = &ScsiCmd;
  118.         SCSIIO->io_Length = sizeof(ScsiCmd);
  119.     
  120.         DoIO((struct IORequest *)SCSIIO);
  121.     
  122.         return SCSIIO->io_Error;
  123.     }
  124.     return -1;
  125. }
  126.  
  127. void
  128. Eject_SCSI( UBYTE out )
  129. {
  130.     static SCSICMD6 command = { SCSI_DA_START_STOP_UNIT };
  131.     
  132.     /* Eject/Reload a CD */
  133.  
  134.     command.b4 = out ? 0x02 : 0x03;
  135.     
  136.     Ejected = out;
  137.     
  138.     DoSCSI( NULL, 0, &command, sizeof(command), (SCSIF_READ|SCSIF_AUTOSENSE) );
  139. }
  140.  
  141. void
  142. Stop_SCSI(void)
  143. {
  144.     static SCSICMD6 command = { SCSI_DA_START_STOP_UNIT };
  145.     
  146.     /* Stop motor */
  147.  
  148.     DoSCSI( NULL, 0, &command, sizeof(command), (SCSIF_READ|SCSIF_AUTOSENSE) );
  149. }
  150.  
  151. #ifndef SINGLE_TRACK_PLAY
  152. ULONG EndAddress = ~0;
  153. #endif
  154.  
  155. void
  156. Play_SCSI(ULONG track)
  157. {
  158.     static SCSICMD12 command = { SCSI_CD_PLAY_AUDIO_12 };
  159.     ULONG address, length;
  160.     
  161.     /* Play a track. Basic program (random order) support in here, even
  162.      * though there is no program editor yet. */
  163.     
  164.     if (TOCP[0] != ~0)
  165.     {
  166.         if (TOCP[track] == ~0)
  167.             return;
  168.         address = TOCL[TOCP[track-1]]+1;
  169.     }
  170.     else
  171.     {
  172.         if (track > Tracks)
  173.             return;
  174.         address = TOCL[track-1]+1;
  175.     }
  176.     Track = track;
  177.     
  178.     command.b2 = (address & 0xff000000) >> 24;
  179.     command.b3 = (address & 0x00ff0000) >> 16;
  180.     command.b4 = (address & 0x0000ff00) >> 8;
  181.     command.b5 = (address & 0x000000ff);
  182.     
  183. #ifdef SINGLE_TRACK_PLAY
  184.     if (TOCP[0] != ~0)
  185.         length = TOCL[TOCP[track]] - address - 1;
  186.     else
  187.         length = TOCL[Tracks-1] - address - 1;
  188.     
  189.     command.b6 = (length & 0xff000000) >> 24;
  190.     command.b7 = (length & 0x00ff0000) >> 16;
  191.     command.b8 = (length & 0x0000ff00) >> 8;
  192.     command.b9 = (length & 0x000000ff);
  193. #else
  194.     /* continuous play */
  195.     if (TOCP[0] != ~0)
  196.         EndAddress = TOCL[TOCP[track]] - 1;
  197.     else
  198.         EndAddress = ~0;
  199.  
  200.     command.b6 = 0xff;
  201.     command.b7 = 0xff;
  202.     command.b8 = 0xff;
  203.     command.b9 = 0xff;
  204. #endif
  205.     
  206.     /* because a Toshiba XM3601B can abort a PLAY_AUDIO sent immediately
  207.      * after media change without any error code, we have a kludge that makes
  208.      * it restart. */
  209.     JustStarted = TRUE;
  210.     
  211.     DoSCSI( DataBuf, DATA_LEN, &command, sizeof(command), (SCSIF_READ|SCSIF_AUTOSENSE) );
  212. }
  213.  
  214. void
  215. PauseResume_SCSI( UBYTE pause )
  216. {
  217.     static SCSICMD10 command = { SCSI_CD_PAUSE_RESUME };
  218.     
  219.     /* Pause/Restart playing */
  220.     
  221.     command.b8 = pause;
  222.     
  223.     DoSCSI( NULL, 0, &command, sizeof(command), (SCSIF_READ|SCSIF_AUTOSENSE) );
  224. }
  225.  
  226. void
  227. Seek_SCSI( LONG seconds )
  228. {
  229.     static SCSICMD10 command = { SCSI_CD_READ_SUB_CHANNEL };
  230.     
  231.     command.b2 = 0x40;
  232.     command.b3 = 1;
  233.     command.b6 = 0;
  234.     
  235.     command.b7 = 255;
  236.     command.b8 = 255;
  237.     
  238.     /* Seek forward/backward (rewind/fast forward) */
  239.     
  240.     if (!DoSCSI( DataBuf, DATA_LEN, &command, sizeof(command), (SCSIF_READ|SCSIF_AUTOSENSE) ))
  241.     {
  242.         static SCSICMD12 command = { SCSI_CD_PLAY_AUDIO_12 };
  243.         
  244.         ULONG address = (DataBuf[8] << 24 | DataBuf[9] << 16 | DataBuf[10] << 8 | DataBuf[11]);
  245.         ULONG length, start, end;
  246.         
  247.         address += seconds * BLOCKSPERSECOND;
  248.         
  249.         if (TOCP[0] != ~0)
  250.         {
  251.             start = TOCL[TOCP[Track-1]];
  252.             end = TOCL[TOCP[Track]];
  253.         }
  254.         else
  255.         {
  256.             start = TOCL[Track-1];
  257.             end = TOCL[Track];
  258.         }
  259.         
  260.         if (address >= start && address < end)
  261.         {
  262.             command.b2 = (address & 0xff000000) >> 24;
  263.             command.b3 = (address & 0x00ff0000) >> 16;
  264.             command.b4 = (address & 0x0000ff00) >> 8;
  265.             command.b5 = (address & 0x000000ff);
  266.             
  267. #ifdef SINGLE_TRACK_PLAY
  268.             length = end - address - 1;
  269.         
  270.             command.b6 = (length & 0xff000000) >> 24;
  271.             command.b7 = (length & 0x00ff0000) >> 16;
  272.             command.b8 = (length & 0x0000ff00) >> 8;
  273.             command.b9 = (length & 0x000000ff);
  274. #else
  275.             command.b6 = 0xff;
  276.             command.b7 = 0xff;
  277.             command.b8 = 0xff;
  278.             command.b9 = 0xff;
  279. #endif
  280.         
  281.             DoSCSI( DataBuf, DATA_LEN, &command, sizeof(command), (SCSIF_READ|SCSIF_AUTOSENSE) );
  282.         }
  283.     }
  284. }
  285.  
  286. ULONG
  287. Snoop_SCSI(ULONG *track, ULONG *tracktime, ULONG *time, ULONG ostat)
  288. {
  289.     static SCSICMD10 command = { SCSI_CD_READ_SUB_CHANNEL };
  290.     
  291.     command.b2 = 0x40;
  292.     command.b3 = 1;
  293.     command.b6 = 0;
  294.     
  295.     command.b7 = 255;
  296.     command.b8 = 255;
  297.     
  298.     /* snoop and update current status */
  299.     
  300.     if (!DoSCSI( DataBuf, DATA_LEN, &command, sizeof(command), (SCSIF_READ|SCSIF_AUTOSENSE) ))
  301.     {
  302.         ULONG status;
  303.         ULONG address;
  304.         
  305.         address = (DataBuf[8] << 24 | DataBuf[9] << 16 | DataBuf[10] << 8 | DataBuf[11]);
  306.         
  307.         if (DataBuf[1] == 0x11)
  308.         {
  309. #ifndef SINGLE_TRACK_PLAY
  310.             if (address >= EndAddress)
  311.             {
  312.                 CD_Play(Track + 1); /* end of track, continue program */
  313.                 return CD_Snoop(track, tracktime, time, CDP_STOPPED);
  314.             }
  315. #endif
  316.             status = CDP_PLAYING;
  317.         }
  318.         else
  319.         if (DataBuf[1] == 0x12)
  320.             status = CDP_PAUSED;
  321.         else
  322.         {
  323.             if (JustStarted && !(DataBuf[5] & 0x04 /* signifies a data track */))
  324.             {
  325.                 /* kludge for aborted PLAY_AUDIO (needed with Toshiba XM3601B) */
  326.                 CD_Play(Track); /* restart track */
  327.                 return CD_Snoop(track, tracktime, time, CDP_STOPPED);
  328.             }
  329.             else
  330.             if (ostat == CDP_PLAYING)
  331.             {
  332.                 CD_Play(Track + 1); /* end of track, continue */
  333.                 return CD_Snoop(track, tracktime, time, CDP_STOPPED);
  334.             }
  335.             JustStarted = FALSE;
  336.             *track = Track = 0;
  337.             return CDP_STOPPED;
  338.         }
  339.         
  340.         Track = *track = DataBuf[6];
  341.         
  342.         *time = address / BLOCKSPERSECOND;
  343.         
  344.         address = (DataBuf[12] << 24 | DataBuf[13] << 16 | DataBuf[14] << 8 | DataBuf[15]);
  345.         
  346.         *tracktime = address / BLOCKSPERSECOND;
  347.         
  348.         if (*tracktime > 1)            /* if the player managed to stay on for longer than */
  349.             JustStarted = FALSE;    /* one second, we can assume it will do so. */
  350.         
  351.         return status;
  352.     }
  353.     return (ULONG)(Ejected ? CDP_EJECTED : CDP_EMPTY);
  354. }
  355.  
  356. ULONG
  357. ReadTOC_SCSI(void)
  358. {
  359.     static SCSICMD10 command = { SCSI_CD_READ_TOC };
  360.  
  361.     command.b7 = 0x03;
  362.     command.b8 = 0x24;
  363.     
  364.     /* Read track lengths from the CD Table Of Contents */
  365.     
  366.     if (!DoSCSI( TOCBuf, TOC_LEN, &command, sizeof(command),  (SCSIF_READ|SCSIF_AUTOSENSE) ))
  367.     {
  368.         ULONG tocsize = (TOCBuf[0] << 8) | TOCBuf[1];
  369.         ULONG tracks = 0;
  370.         UBYTE *toc;
  371.         
  372.         if (tocsize > 2) tocsize -= 2;
  373.  
  374.         for (toc = &TOCBuf[4] ; toc < (&TOCBuf[4] + tocsize) ; toc += 8 )
  375.         {
  376.             TOCL[tracks] = (toc[4] << 24) | (toc[5] << 16) | (toc[6] << 8) | (toc[7]);
  377.             TOCT[tracks] = TOCL[tracks] / BLOCKSPERSECOND;
  378.             TOCF[tracks] = (toc[1] & 0x04) ? 1 : 0;
  379.             TOCS[tracks] = &TitleBuffer[(tracks+2)*40];
  380.             Sprintf(TOCS[tracks], GS(TRACK_NUM), tracks+1);
  381.             tracks++;
  382.         }
  383.         TOCS[--tracks] = NULL;
  384.  
  385.         if (!GetIndex( tracks, TOCL[2], TOCL[tracks]))
  386.         {
  387.             TITLE[0] = NULL;
  388.             TITLE[1] = NULL;
  389.         }
  390.         
  391.         if (!TITLE[0])
  392.         {
  393.             TITLE[0] = &TitleBuffer[0];
  394.             strcpy(TITLE[0], GS(UNKNOWN_ARTIST));
  395.         }
  396.  
  397.         if (!TITLE[1])
  398.         {
  399.             TITLE[1] = &TitleBuffer[40];
  400.             strcpy(TITLE[1], GS(UNKNOWN_TITLE));
  401.         }
  402.  
  403.         return tracks;
  404.     }
  405.     if (SenseData[2] == 0x06 && /* media changed */
  406.         SenseData[7] >= 3 &&     /* enough sense data */
  407.         SenseData[12] == 0x28)    /* media changed */
  408.     {
  409.         Delay(10);
  410.         return CD_ReadTOC();
  411.     }
  412.     return 0;
  413. }
  414.  
  415. BOOL
  416. IsCD_SCSI(void)
  417. {
  418.     static SCSICMD6 command = { SCSI_INQUIRY };
  419.     
  420.     /* Test if a SCSI target is a CD-ROM device */
  421.     
  422.     command.b4 = 40;
  423.     
  424.     if (!DoSCSI( DataBuf, DATA_LEN, &command, sizeof(command), (SCSIF_READ|SCSIF_AUTOSENSE) ))
  425.     {
  426.         return (BOOL)(((DataBuf[0] & 0x1f) == 0x05) ? TRUE : FALSE); /* is a CD-ROM */
  427.     }
  428.     return FALSE;
  429. }
  430.