summaryrefslogtreecommitdiff
path: root/macosx/plugins/CDDeviceInterface/src
diff options
context:
space:
mode:
authorSND\weimingzhi_cp <SND\weimingzhi_cp@e17a0e51-4ae3-4d35-97c3-1a29b211df97>2009-10-24 03:15:42 +0000
committerSND\weimingzhi_cp <SND\weimingzhi_cp@e17a0e51-4ae3-4d35-97c3-1a29b211df97>2009-10-24 03:15:42 +0000
commit5408345d8b1cde19a19ddf324d3439ead6e80709 (patch)
treefd7934308384396b4ad92b547e8804a696c480e8 /macosx/plugins/CDDeviceInterface/src
parentf2f1033882e0643f05f3027f2c812f425f67a879 (diff)
downloadpcsxr-5408345d8b1cde19a19ddf324d3439ead6e80709.tar.gz
git-svn-id: https://pcsxr.svn.codeplex.com/svn/pcsxr@32699 e17a0e51-4ae3-4d35-97c3-1a29b211df97
Diffstat (limited to 'macosx/plugins/CDDeviceInterface/src')
-rw-r--r--macosx/plugins/CDDeviceInterface/src/PSEmu_Plugin_Defs.h313
-rw-r--r--macosx/plugins/CDDeviceInterface/src/PlugCD.c889
-rw-r--r--macosx/plugins/CDDeviceInterface/src/PlugCD.h120
3 files changed, 1322 insertions, 0 deletions
diff --git a/macosx/plugins/CDDeviceInterface/src/PSEmu_Plugin_Defs.h b/macosx/plugins/CDDeviceInterface/src/PSEmu_Plugin_Defs.h
new file mode 100644
index 00000000..151f30a1
--- /dev/null
+++ b/macosx/plugins/CDDeviceInterface/src/PSEmu_Plugin_Defs.h
@@ -0,0 +1,313 @@
+/*
+ PSEmu Plugin Developer Kit Header definition
+
+ (C)1998 Vision Thing
+
+ This file can be used only to develop PSEmu Plugins
+ Other usage is highly prohibited.
+*/
+
+
+// IMPORTANT!!!
+
+// if you want to add return codes (any errors or warnings) just drop mail to
+// plugin@psemu.com
+
+#ifndef _PSEMU_PLUGIN_DEFS_H
+#define _PSEMU_PLUGIN_DEFS_H
+
+
+// header version
+#define _PPDK_HEADER_VERSION 3
+
+#define PLUGIN_VERSION 1
+
+// plugin type returned by PSEgetLibType (types can be merged if plugin is multi type!)
+#define PSE_LT_CDR 1
+#define PSE_LT_GPU 2
+#define PSE_LT_SPU 4
+#define PSE_LT_PAD 8
+#define PSE_LT_NET 16
+
+
+// every function in DLL if completed sucessfully should return this value
+#define PSE_ERR_SUCCESS 0
+
+// undefined error but fatal one, that kills all functionality
+#define PSE_ERR_FATAL -1
+
+
+
+// XXX_Init return values
+// Those return values apply to all libraries
+// currently obsolete - preserved for compatibilty
+
+
+// initialization went OK
+#define PSE_INIT_ERR_SUCCESS 0
+
+// this driver is not configured
+#define PSE_INIT_ERR_NOTCONFIGURED -2
+
+// this driver can not operate properly on this hardware or hardware is not detected
+#define PSE_INIT_ERR_NOHARDWARE -3
+
+
+
+/* GPU PlugIn */
+
+
+// GPU_Test return values
+
+// sucess, everything configured, and went OK.
+#define PSE_GPU_ERR_SUCCESS 0
+
+// ERRORS
+// this error might be returned as critical error but none of below
+#define PSE_GPU_ERR -20
+
+
+// this driver is not configured
+#define PSE_GPU_ERR_NOTCONFIGURED PSE_GPU_ERR - 1
+// this driver failed Init
+#define PSE_GPU_ERR_INIT PSE_GPU_ERR - 2
+
+// WARNINGS
+// this warning might be returned as undefined warning but allowing driver to continue
+#define PSE_GPU_WARN 20
+
+
+
+
+// GPU_Query - will be implemented soon
+
+typedef struct
+{
+ unsigned long flags;
+ unsigned long status;
+ HWND window;
+ unsigned char reserved[100];
+} gpuQueryS;
+
+// gpuQueryS.flags
+// if driver can operate in both modes it must support GPU_changeMode();
+// this driver can operate in fullscreen mode
+#define PSE_GPU_FLAGS_FULLSCREEN 1
+// this driver can operate in windowed mode
+#define PSE_GPU_FLAGS_WINDOWED 2
+
+
+// gpuQueryS.status
+// this driver cannot operate in this windowed mode
+#define PSE_GPU_STATUS_WINDOWWRONG 1
+
+// GPU_Query End - will be implemented in v2
+
+
+
+
+/* CDR PlugIn */
+
+// CDR_Test return values
+
+// sucess, everything configured, and went OK.
+#define PSE_CDR_ERR_SUCCESS 0
+
+// general failure (error undefined)
+#define PSE_CDR_ERR_FAILURE -1
+
+// ERRORS
+#define PSE_CDR_ERR -40
+// this driver is not configured
+#define PSE_CDR_ERR_NOTCONFIGURED PSE_CDR_ERR - 0
+// if this driver is unable to read data from medium
+#define PSE_CDR_ERR_NOREAD PSE_CDR_ERR - 1
+
+// WARNINGS
+#define PSE_CDR_WARN 40
+// if this driver emulates lame mode ie. can read only 2048 tracks and sector header is emulated
+// this might happen to CDROMS that do not support RAW mode reading - surelly it will kill many games
+#define PSE_CDR_WARN_LAMECD PSE_CDR_WARN + 0
+
+
+
+
+/* SPU PlugIn */
+
+// some info retricted (now!)
+
+// sucess, everything configured, and went OK.
+#define PSE_SPU_ERR_SUCCESS 0
+
+// ERRORS
+// this error might be returned as critical error but none of below
+#define PSE_SPU_ERR -60
+
+// this driver is not configured
+#define PSE_SPU_ERR_NOTCONFIGURED PSE_SPU_ERR - 1
+// this driver failed Init
+#define PSE_SPU_ERR_INIT PSE_SPU_ERR - 2
+
+
+// WARNINGS
+// this warning might be returned as undefined warning but allowing driver to continue
+#define PSE_SPU_WARN 60
+
+
+
+
+/* PAD PlugIn */
+
+/*
+
+ functions that must be exported from PAD Plugin
+
+ long PADinit(long flags); // called only once when PSEmu Starts
+ void PADshutdown(void); // called when PSEmu exits
+ long PADopen(PadInitS *); // called when PSEmu is running program
+ long PADclose(void);
+ long PADconfigure(void);
+ void PADabout(void);
+ long PADtest(void); // called from Configure Dialog and after PADopen();
+ long PADquery(void);
+
+ long PADreadPort1(PadDataS *);
+ long PADreadPort2(PadDataS *);
+
+*/
+
+// PADquery responses (notice - values ORed)
+// PSEmu will use them also in PADinit to tell Plugin which Ports will use
+// notice that PSEmu will call PADinit and PADopen only once when they are from
+// same plugin
+
+// might be used in port 1 (must support PADreadPort1() function)
+#define PSE_PAD_USE_PORT1 1
+// might be used in port 2 (must support PADreadPort2() function)
+#define PSE_PAD_USE_PORT2 2
+
+
+
+// MOUSE SCPH-1030
+#define PSE_PAD_TYPE_MOUSE 1
+// NEGCON - 16 button analog controller SLPH-00001
+#define PSE_PAD_TYPE_NEGCON 2
+// GUN CONTROLLER - gun controller SLPH-00014 from Konami
+#define PSE_PAD_TYPE_GUN 3
+// STANDARD PAD SCPH-1080, SCPH-1150
+#define PSE_PAD_TYPE_STANDARD 4
+// ANALOG JOYSTICK SCPH-1110
+#define PSE_PAD_TYPE_ANALOGJOY 5
+// GUNCON - gun controller SLPH-00034 from Namco
+#define PSE_PAD_TYPE_GUNCON 6
+// ANALOG CONTROLLER SCPH-1150
+#define PSE_PAD_TYPE_ANALOGPAD 7
+
+
+// sucess, everything configured, and went OK.
+#define PSE_PAD_ERR_SUCCESS 0
+// general plugin failure (undefined error)
+#define PSE_PAD_ERR_FAILURE -1
+
+
+// ERRORS
+// this error might be returned as critical error but none of below
+#define PSE_PAD_ERR -80
+// this driver is not configured
+#define PSE_PAD_ERR_NOTCONFIGURED PSE_PAD_ERR - 1
+// this driver failed Init
+#define PSE_PAD_ERR_INIT PSE_PAD_ERR - 2
+
+
+// WARNINGS
+// this warning might be returned as undefined warning but allowing driver to continue
+#define PSE_PAD_WARN 80
+
+
+typedef struct
+{
+ // controler type - fill it withe predefined values above
+ unsigned char controllerType;
+
+ // status of buttons - every controller fills this field
+ unsigned short buttonStatus;
+
+ // for analog pad fill those next 4 bytes
+ // values are analog in range 0-255 where 128 is center position
+ unsigned char rightJoyX, rightJoyY, leftJoyX, leftJoyY;
+
+ // for mouse fill those next 2 bytes
+ // values are in range -128 - 127
+ unsigned char moveX, moveY;
+
+ unsigned char reserved[91];
+
+} PadDataS;
+
+/* NET PlugIn v2 */
+/* Added by linuzappz@pcsx.net */
+
+/* Modes bits for NETsendData/NETrecvData */
+#define PSE_NET_BLOCKING 0x00000000
+#define PSE_NET_NONBLOCKING 0x00000001
+
+/*
+typedef struct {
+ char EmuName[32];
+ char CdromID[32];
+ char CdromLabel[32];
+ void *psxMem;
+ GPUshowScreenPic PAD_showScreenPic;
+ GPUdisplayText PAD_displayText;
+ PADsetSensitive PAD_setSensitive;
+ void unused[1024];
+} netInfo;
+*/
+
+/*
+ basic funcs:
+
+ long NETopen(HWND hWnd)
+ opens the connection.
+ shall return 0 on success, else -1.
+ -1 is also returned if the user selects offline mode.
+
+ long NETclose()
+ closes the connection.
+ shall return 0 on success, else -1.
+
+ void NETpause()
+ this is called when the user paused the emulator.
+
+ void NETresume()
+ this is called when the user resumed the emulator.
+
+ long NETqueryPlayer()
+ returns player number
+
+ long NETsendPadData(void *pData, int Size)
+ this should be called for the first pad only on each side.
+
+ long NETrecvPadData(void *pData, int Pad)
+ call this for Pad 1/2 to get the data sent by the above func.
+
+ extended funcs:
+
+ long NETsendData(void *pData, int Size, int Mode)
+ sends Size bytes from pData to the other side.
+
+ long NETrecvData(void *pData, int Size, int Mode)
+ receives Size bytes from pData to the other side.
+
+ void NETsetInfo(netInfo *info);
+ sets the netInfo struct.
+
+ void NETvsync()
+ called every vsync (before GPUupdateLace).
+
+ void NETkeypressed(int key)
+ key is on win32 a VK_?? keycode, and over linux a XK_?? (X11) keycode.
+*/
+
+
+#endif // _PSEMU_PLUGIN_DEFS_H
diff --git a/macosx/plugins/CDDeviceInterface/src/PlugCD.c b/macosx/plugins/CDDeviceInterface/src/PlugCD.c
new file mode 100644
index 00000000..549e137c
--- /dev/null
+++ b/macosx/plugins/CDDeviceInterface/src/PlugCD.c
@@ -0,0 +1,889 @@
+/***************************************************************************
+ PlugCD.c
+ CDDeviceInterface
+
+ Created by Gil Pedersen on Fri July 18 2003.
+ Copyright (c) 2003,2004 Gil Pedersen.
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. See also the license.txt file for *
+ * additional informations. *
+ * *
+ ***************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <paths.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <mach/mach_port.h>
+
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/storage/IOCDMedia.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOCDTypes.h>
+#include <IOKit/storage/IOCDMediaBSDClient.h>
+#include <IOKit/scsi-commands/SCSITaskLib.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+//#include "plugins.h"
+#include "PlugCD.h"
+
+//#define USE_DEVICE_INTERFACE
+
+long CDRclose(void);
+
+/////////////////////////////////////////////////////////
+typedef void* HWND;
+#include "PSEmu_Plugin_Defs.h"
+
+const char *LibName = "CD-ROM Device Interface";
+const int version = 0;
+const int revision = 1;
+const int build = 0;
+
+const char *PSEgetLibName(void) {
+ return LibName;
+}
+
+unsigned long PSEgetLibType(void) {
+ return PSE_LT_CDR;
+}
+
+unsigned long PSEgetLibVersion(void) {
+ return version << 16 | revision << 8 | build;
+}
+/////////////////////////////////////////////////////////
+
+//#define SysPrintf printf
+#define SysPrintf(X)
+
+#define UseMultiThreaded 1
+#define NoIdleSleep 1
+
+struct CdrStat {
+ unsigned long Type;
+ unsigned long Status;
+ unsigned char Time[3];
+};
+
+MMCDeviceInterface **cdInterface;
+pthread_t readThread;
+pthread_cond_t readCond;
+pthread_mutex_t readMutex;
+char deviceFilePath[ 256 ];
+
+kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator, mach_port_t *masterPort )
+{
+ kern_return_t kernResult;
+ CFMutableDictionaryRef classesToMatch;
+
+ kernResult = IOMasterPort( bootstrap_port, masterPort );
+ if ( kernResult != KERN_SUCCESS )
+ {
+ printf( "IOMasterPort returned %d\n", kernResult );
+ return kernResult;
+ }
+ // CD media are instances of class kIOCDMediaClass.
+ classesToMatch = IOServiceMatching( kIOCDMediaClass );
+ if ( classesToMatch == NULL )
+ printf( "IOServiceMatching returned a NULL dictionary.\n" );
+ else
+ {
+ // Each IOMedia object has a property with key kIOMediaEjectable
+ // which is true if the media is indeed ejectable. So add property
+ // to CFDictionary for matching.
+ CFDictionarySetValue( classesToMatch,
+ CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
+ }
+ kernResult = IOServiceGetMatchingServices( *masterPort,
+ classesToMatch, mediaIterator );
+ if ( (kernResult != KERN_SUCCESS) || (*mediaIterator == NULL) )
+ printf( "No ejectable CD media found.\n kernResult = %d\n",
+ kernResult );
+ return kernResult;
+}
+
+kern_return_t GetDeviceFilePath( io_service_t media,
+ char *deviceFilePath, CFIndex maxPathSize )
+{
+ kern_return_t kernResult = KERN_FAILURE;
+ CFTypeRef deviceFilePathAsCFString;
+
+ deviceFilePathAsCFString = IORegistryEntryCreateCFProperty(
+ media, CFSTR( kIOBSDNameKey ),
+ kCFAllocatorDefault, 0 );
+ *deviceFilePath = '\0';
+ if ( deviceFilePathAsCFString )
+ {
+ size_t devPathLength = strlen( _PATH_DEV )+0;//+1;
+
+ strcpy( deviceFilePath, _PATH_DEV );
+ // Add "r" before the BSD node name from the I/O Registry
+ // to specify the raw disk node. The raw disk node receives
+ // I/O requests directly and does not go through the
+ // buffer cache.
+ // strcat( deviceFilePath, "r"); // apparently som cd-rom drives don't like this
+
+ if ( CFStringGetCString( deviceFilePathAsCFString,
+ deviceFilePath + devPathLength,
+ maxPathSize - devPathLength,
+ kCFStringEncodingASCII ) )
+ {
+ printf( "BSD path: %s\n", deviceFilePath );
+ kernResult = KERN_SUCCESS;
+ }
+ CFRelease( deviceFilePathAsCFString );
+ }
+
+ return kernResult;
+}
+
+MMCDeviceInterface ** GetMMCInterfaceForDevice(io_service_t service)
+{
+ SInt32 score;
+ HRESULT herr;
+ kern_return_t err;
+ IOCFPlugInInterface **plugInInterface = NULL;
+ MMCDeviceInterface **mmcInterface = NULL;
+
+ // Create the IOCFPlugIn interface so we can query it.
+ err = IOCreatePlugInInterfaceForService ( service,
+ kIOMMCDeviceUserClientTypeID,
+ kIOCFPlugInInterfaceID,
+ &plugInInterface,
+ &score );
+
+ if ( err != noErr )
+ {
+ printf("IOCreatePlugInInterfaceForService returned %d\n", err);
+ return NULL;
+ }
+
+ // Query the interface for the MMCDeviceInterface.
+ herr = ( *plugInInterface )->QueryInterface ( plugInInterface,
+ CFUUIDGetUUIDBytes ( kIOMMCDeviceInterfaceID ),
+ ( LPVOID ) &mmcInterface );
+ if ( herr != S_OK )
+ {
+ printf("QueryInterface returned %ld\n", herr);
+ return NULL;
+ }
+
+// ( *mmcInterface )->Release ( mmcInterface );
+// IODestroyPlugInInterface ( plugInInterface );
+
+ return mmcInterface;
+}
+
+int GetCDROMServices()
+{
+ mach_port_t masterPort;
+ CFMutableDictionaryRef matchingDict;
+ CFMutableDictionaryRef subDict;
+ io_service_t nextDevice;
+ io_iterator_t iterator;
+ kern_return_t kr;
+ int retVal = -1;
+
+ // first create a master_port for my task
+ kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
+ if (kr || !masterPort)
+ {
+ printf("ERR: Couldn't create a master IOKit Port(%08x)\n", kr);
+ return -1;
+ }
+
+ // Create the dictionaries
+ matchingDict = CFDictionaryCreateMutable ( kCFAllocatorDefault, 0, NULL, NULL );
+ subDict = CFDictionaryCreateMutable ( kCFAllocatorDefault, 0, NULL, NULL );
+
+ // Create a dictionary with the "SCSITaskDeviceCategory" key = "SCSITaskAuthoringDevice"
+ // TODO: examine if this also work on non-authoring capable devices
+ CFDictionarySetValue ( subDict,
+ CFSTR ( kIOPropertySCSITaskDeviceCategory ),
+ CFSTR ( kIOPropertySCSITaskAuthoringDevice ) );
+
+ // Add the dictionary to the main dictionary with the key "IOPropertyMatch" to
+ // narrow the search to the above dictionary.
+ CFDictionarySetValue ( matchingDict,
+ CFSTR ( kIOPropertyMatchKey ),
+ subDict );
+
+
+ kr = IOServiceGetMatchingServices( masterPort,
+ matchingDict, &iterator );
+ if ( (kr != KERN_SUCCESS) || (iterator == NULL) ) {
+ printf( "No CDROM drives found.\n kernResult = %d\n", kr );
+ goto error;
+ }
+
+ // Find best cdrom drive - i.e. the first :-)
+ while(nextDevice = IOIteratorNext( iterator )) {
+ cdInterface = GetMMCInterfaceForDevice(nextDevice);
+ kr = IOObjectRelease(nextDevice);
+ break; // hack
+ }
+ IOObjectRelease( iterator );
+
+ retVal = 0;
+error:
+ // Now done with the master_port
+ if (masterPort)
+ mach_port_deallocate(mach_task_self(), masterPort);
+
+ return retVal;
+}
+
+/* determine if the tray is open for our cd-drive */
+int TrayIsOpen()
+{
+#ifdef USE_DEVICE_INTERFACE
+ if (cdInterface) {
+ if ((*cdInterface)->GetTrayState) {
+ IOReturn res;
+ char state;
+
+ res = (*cdInterface)->GetTrayState(cdInterface, &state);
+ if (kIOReturnSuccess == res) {
+ if (kMMCDeviceTrayOpen == state)
+ return true;
+ }
+ }
+ }
+#endif
+ return true;
+}
+
+/* opens tray if no media is in the device */
+void TrayOpen()
+{
+ if (TrayIsOpen())
+ return;
+
+ if (cdInterface) {
+ if ((*cdInterface)->SetTrayState) {
+ (*cdInterface)->SetTrayState(cdInterface, kMMCDeviceTrayOpen);
+ }
+ }
+}
+
+long openDisc()
+{
+ mach_port_t masterPort = NULL;
+ kern_return_t kernResult;
+ io_iterator_t mediaIterator;
+ io_service_t media;
+ CFTypeRef toc_cf;
+ //dk_cd_read_disc_info_t cd_read_disc_info;
+ //dk_cd_read_track_info_t cd_read_track_info;
+ //CDDiscInfo di; CDTrackInfo ti;
+ u_int16_t speed;
+ int i;
+
+ CD.cd = 0;
+ CD.status = 0x10;
+
+ // Find 1st CD
+ kernResult = FindEjectableCDMedia( &mediaIterator, &masterPort );
+ if ( kernResult != KERN_SUCCESS )
+ return -1;
+
+ media = IOIteratorNext( mediaIterator );
+ if (NULL == media)
+ return -1;
+
+ // Release the iterator.
+ IOObjectRelease( mediaIterator );
+
+ // Get The device path
+ kernResult = GetDeviceFilePath( media, deviceFilePath,
+ sizeof( deviceFilePath ) );
+ if ( kernResult != KERN_SUCCESS )
+ return -1;
+
+ toc_cf = IORegistryEntryCreateCFProperty(media,CFSTR(kIOCDMediaTOCKey),kCFAllocatorDefault,0);
+ if(toc_cf != nil)
+ {
+ CDTOC *toc = (CDTOC *)CFDataGetBytePtr(toc_cf);
+ int ndesc;
+
+ ndesc = CDTOCGetDescriptorCount(toc);
+ if (CD.tl) free(CD.tl);
+ CD.tl = calloc(ndesc, sizeof(Track));
+ if (NULL == CD.tl)
+ return -1;
+
+ CD.numtracks = 0;
+ for (i=0; i<ndesc; i++)
+ {
+ CDTOCDescriptor *desc = &toc->descriptors[i];
+
+ if(desc->point < 100)
+ {
+ CD.tl[CD.numtracks].type = ((desc->control & 0x0f) != 0) ? Mode2 : Audio; // TODO: set correct type
+ CD.tl[CD.numtracks].num = desc->point;
+ CD.tl[CD.numtracks].start[2] = desc->p.frame;
+ CD.tl[CD.numtracks].start[1] = desc->p.second;
+ CD.tl[CD.numtracks].start[0] = desc->p.minute;
+
+ if (CD.numtracks) {
+ CD.tl[CD.numtracks-1].end[2] = desc->p.frame;
+ CD.tl[CD.numtracks-1].end[1] = desc->p.second;
+ CD.tl[CD.numtracks-1].end[0] = desc->p.minute;
+ }
+ //normalizeTime(CD.tl[0].start);
+ //normalizeTime(CD.tl[0].end);
+ CD.numtracks++;
+ }
+ }
+ CDMSF end = CDConvertTrackNumberToMSF(0xa2, toc);
+ CD.tl[CD.numtracks-1].end[2] = end.frame;
+ CD.tl[CD.numtracks-1].end[1] = end.second;
+ CD.tl[CD.numtracks-1].end[0] = end.minute;
+
+ CFRelease(toc_cf);
+ } else {
+ printf("failed to read cdrom toc information\n");
+ IOObjectRelease( mediaIterator );
+ return -1;
+ }
+
+ IOObjectRelease( media );
+
+ // Free master port if we created one.
+ if (masterPort)
+ mach_port_deallocate(mach_task_self(), masterPort);
+
+ // Now open it
+ CD.cd = open(deviceFilePath, O_RDONLY, 0);
+ if (CD.cd <= 0) {
+ perror("failed to open cd: ");
+ CD.cd = 0;
+ return -1;
+ }
+
+ // get number of tracks
+/* memset(&cd_read_disc_info, 0, sizeof(dk_cd_read_disc_info_t));
+ cd_read_disc_info.bufferLength = sizeof(CDDiscInfo);
+ cd_read_disc_info.buffer = &di;
+ if (ioctl(CD.cd, DKIOCCDREADDISCINFO, &cd_read_disc_info) < 0) {
+ perror("error reading cd info: ");
+ CD.numtracks = 1;
+ }
+ else {
+ CD.numtracks = di.lastTrackNumberInLastSessionLSB-di.firstTrackNumberInLastSessionLSB+1;
+ }
+
+ CD.tl = calloc(CD.numtracks, sizeof(Track));
+ for (i=0; i<CD.numtracks; i++)
+ {
+ int blocks;
+ memset(&cd_read_track_info, 0, sizeof(dk_cd_read_track_info_t));
+ cd_read_track_info.address = di.firstTrackNumberInLastSessionLSB+i;
+ cd_read_track_info.addressType = kCDTrackInfoAddressTypeTrackNumber;
+ cd_read_track_info.bufferLength = sizeof(CDTrackInfo);
+ cd_read_track_info.buffer = &ti;
+ if (ioctl(CD.cd, DKIOCCDREADTRACKINFO, &cd_read_track_info) < 0) {
+ perror("error reading track info");
+ close(CD.cd); CD.cd = 0;
+ return -1;
+ }
+
+ //printf("Track %i: %i - %i\n", di.firstTrackNumberInLastSessionLSB+i,
+ // ti.trackStartAddress, ti.trackSize);
+
+ CD.tl[i].type = ti.trackMode ? Mode2 : Audio; // TODO: set correct type
+ CD.tl[i].num = ti.trackNumberLSB;
+ blocks = ti.trackStartAddress;
+ CD.tl[i].start[2] = blocks % 75;
+ CD.tl[i].start[1] = ((blocks - CD.tl[i].end[2]) / 75) % 60;
+ CD.tl[i].start[0] = (((blocks - CD.tl[i].end[2]) / 75) - CD.tl[i].end[1]) / 60;
+ blocks += ti.trackSize;
+ CD.tl[i].end[2] = blocks % 75;
+ CD.tl[i].end[1] = ((blocks - CD.tl[i].end[2]) / 75) % 60;
+ CD.tl[i].end[0] = (((blocks - CD.tl[i].end[2]) / 75) - CD.tl[i].end[1]) / 60;
+
+ normalizeTime(CD.tl[i].start);
+ normalizeTime(CD.tl[i].end);
+ }*/
+
+ speed = kCDSpeedMin*4; // 4x
+ if (ioctl(CD.cd, DKIOCCDSETSPEED, &speed) < 0)
+ perror("couldn't set cd speed");
+
+ CD.sectorType = kCDSectorTypeMode2Form1;
+ CD.bufferSize = 0;
+ CD.bufferPos = 0x7FFFFFFF;
+ CD.status = 0x00;
+
+// fcntl(CD.cd, F_RDAHEAD, 1);
+// fcntl(CD.cd, F_NOCACHE, 0);
+ fcntl(CD.cd, F_RDAHEAD, 0);
+ fcntl(CD.cd, F_NOCACHE, 1);
+
+ return 0;
+}
+
+// gets track
+long getTN(unsigned char* buffer)
+{
+ int numtracks = getNumTracks();
+
+ if (-1 == numtracks)
+ {
+ buffer[0]=buffer[1]=1;
+ return -1;
+ }
+
+ buffer[0]=CD.tl[0].num;
+ buffer[1]=numtracks;
+ return 0;
+}
+
+ // if track==0 -> return total length of cd
+ // otherwise return start in bcd time format
+long getTD(int track, unsigned char* buffer)
+{
+ // lasttrack just keeps track of which track TD was requested last (go fig)
+
+ if (track > getNumTracks())
+ {
+// printf("getTD bad %2d\n", track);
+ return -1;
+ }
+
+ if (track == 0)
+ {
+ buffer[0] = CD.tl[CD.numtracks-1].end[0];
+ buffer[1] = CD.tl[CD.numtracks-1].end[1];
+ buffer[2] = CD.tl[CD.numtracks-1].end[2];
+ }
+ else
+ {
+ buffer[0] = CD.tl[track-1].start[0];
+ buffer[1] = CD.tl[track-1].start[1];
+ buffer[2] = CD.tl[track-1].start[2];
+ }
+// printf("getTD %2d %02d:%02d:%02d\n", track, (int)buffer[0],
+// (int)buffer[1], (int)buffer[2]);
+
+ // bcd encode it
+ buffer[0] = intToBCD(buffer[0]);
+ buffer[1] = intToBCD(buffer[1]);
+ buffer[2] = intToBCD(buffer[2]);
+// SysPrintf("end getTD()\r\n");
+ return 0;
+}
+
+// return the sector address - the buffer address + 12 bytes for subheader offset.
+unsigned char* getSector(int subchannel)
+{
+ SysPrintf("getSector()\n");
+
+ if (readThread) {
+ int err;
+ // wait until we can obtain a lock */
+ err = pthread_mutex_lock(&readMutex);
+ if (err != 0) {
+ printf("failed to lock mutex, error = %i\n", err);
+ } else {
+ err = pthread_mutex_unlock(&readMutex);
+ if (err != 0) {
+ printf("failed to unlock mutex, error = %i\n", err);
+ }
+ }
+ }
+
+ if (CD.sector == -1)
+ return NULL;
+ else {
+ return CD.buffer /*+ (CD.sector - CD.bufferPos)*/ + ((subchannel) ? 0 : 12);
+ }
+}
+
+// returns the number of tracks
+char getNumTracks()
+{
+// SysPrintf("start getNumTracks()\r\n");
+ // if there's no open cd, return -1
+ if (CD.cd == 0) {
+ return -1;
+ }
+
+// printf("numtracks %d\n",CD.numtracks);
+// SysPrintf("end getNumTracks()\r\n");
+ return CD.numtracks;
+}
+
+// read the sector pointed to by pos
+int readSector(off_t pos, unsigned char *buffer)
+{
+ int len;
+
+ SysPrintf("start readit()\n");
+
+ if (0 == CD.cd)
+ return 0;
+
+ // go to the sector
+ pos = lseek(CD.cd, pos, SEEK_SET);
+ if (pos < 0)
+ goto error;
+
+ // and read it into the buffer
+ len = read(CD.cd, buffer, 2352);
+ if (len < 2352)
+ goto error;
+
+ SysPrintf("end readit()\n");
+ return 2352;
+
+error:
+ perror("CD read error");
+ return 0;
+}
+
+void seekSector(const unsigned char m, const unsigned char s, const unsigned char f)
+{
+ int err;
+ SysPrintf("start seekSector()\n");
+
+ if (0 == CD.cd)
+ return;
+
+ if (readThread) {
+ // wait until we're done reading
+ err = pthread_mutex_lock(&readMutex);
+ if (err != 0) {
+ printf("failed to lock mutex, error = %i\n", err);
+ } else {
+ // calc byte to search for
+ CD.sector = (( (m * 60) + (s - 2)) * 75 + f) * 2352;
+
+ // unlock again, since the mutex won't be set until
+ // we signal a cond later in this function
+ err = pthread_mutex_unlock(&readMutex);
+ if (err != 0) {
+ printf("failed to unlock mutex, error = %i\n", err);
+ }
+ }
+ } else {
+ // calc byte to search for
+ CD.sector = (( (m * 60) + (s - 2)) * 75 + f) * 2352;
+ }
+// printf("seek %d %02d:%02d:%02d",CD.sector, (int)m, (int)s, (int)f);
+
+ // is it cached?
+#if 0
+ if ((CD.sector >= CD.bufferPos) &&
+ (CD.sector < (CD.bufferPos + CD.bufferSize)) ) {
+// printf(" cached %d %d\n",CD.sector - CD.bufferPos,BUFFER_SIZE);
+// SysPrintf("end seekSector()\r\n");
+ return;
+ }
+ // not cached - read a few blocks into the cache
+ else
+#endif
+ {
+ if (readThread) {
+ SysPrintf("end seekSector()\n");
+
+ // signal that a new sector is ready to be read
+ if (pthread_cond_broadcast(&readCond) == 0)
+ return;
+
+ printf("failed to signal 'readCond'\n");
+ }
+
+ CD.bufferSize = readSector(CD.sector, CD.buffer);
+ if (CD.bufferSize==0) CD.sector = -1;
+ else CD.bufferPos = CD.sector;
+ }
+ SysPrintf("end seekSector()\n");
+}
+
+/* handles reading from the cd */
+void *read_thread(void *arg)
+{
+ struct timespec dT = { 20, 0 }; // 20 s
+ //struct timespec dT = { 0, 400*1000*1000 }; // 400 ms
+ int err;
+
+ pthread_mutex_lock(&readMutex);
+ //pthread_cleanup_push(pthread_exit, 0);
+
+ for (;;) {
+ // wait until we're signalled
+ if (NoIdleSleep) {
+ err = pthread_cond_timedwait_relative_np(&readCond, &readMutex, &dT);
+ pthread_testcancel();
+ } else {
+ err = pthread_cond_wait(&readCond, &readMutex);
+ }
+ if (err == EINVAL) {
+ printf("failed cond wait for 'readCond', error = %i\n", err);
+ return (void *)-1;
+ }
+
+ CD.bufferSize = readSector(CD.sector, CD.buffer);
+ if (CD.bufferSize==0) CD.sector = -1;
+ else CD.bufferPos = CD.sector;
+ }
+ //pthread_cleanup_pop(1);
+
+ return 0;
+}
+
+long CDRopen(void)
+{
+ SysPrintf("CDR_open()\n");
+ if (UseMultiThreaded && !readThread) {
+ int err;
+
+ err = pthread_cond_init(&readCond, NULL);
+ if (err!=0) {
+ printf("failed to create conditional, error=%i\n"
+ "going to single thread mode\n", err);
+ } else {
+ err = pthread_mutex_init(&readMutex, NULL);
+ if (err!=0) {
+ printf("failed to create mutex, error=%i\n"
+ "going to single thread mode\n", err);
+ } else {
+ struct sched_param params;
+ int policy;
+
+ err = pthread_create(&readThread, NULL, read_thread, NULL);
+ if (err!=0) {
+ printf("failed to create read thread, error=%i\n"
+ "going to single thread mode\n", err);
+ } else {
+ // set the thread to maximum priority
+ pthread_getschedparam(readThread, &policy, &params);
+ params.sched_priority = sched_get_priority_max(policy);
+ pthread_setschedparam(readThread, policy, &params);
+ }
+ }
+ }
+ }
+
+ if (openDisc() < 0) {
+ TrayOpen();
+ return 0;
+ }
+
+ seekSector(0,2,0);
+
+ SysPrintf("end CDR_open()\n");
+ return 0;
+}
+
+long CDRinit(void) {
+
+#ifdef USE_DEVICE_INTERFACE
+ return GetCDROMServices();
+#endif
+
+ return 0;
+}
+
+long CDRshutdown(void) {
+ // do cleanup
+ CDRclose();
+
+ return 0;
+}
+
+long CDRclose(void) {
+ SysPrintf("start CDR_close()\n");
+
+ if (!CD.cd)
+ return 0;
+
+ if (readThread) {
+ int termVal = 0;
+ // make sure we're done reading
+ pthread_mutex_lock(&readMutex);
+ pthread_mutex_unlock(&readMutex);
+
+ // kill read thread
+ pthread_cancel(readThread);
+ //pthread_kill(readThread, SIGTERM);
+ pthread_cond_broadcast(&readCond);
+ pthread_join(readThread, (void **)&termVal);
+
+ // remove fluff
+ pthread_mutex_destroy(&readMutex);
+ pthread_cond_destroy(&readCond);
+
+ readThread = 0;
+ }
+
+ close(CD.cd);
+ CD.cd = 0;
+
+ SysPrintf("end CDR_close()\n");
+ return 0;
+}
+
+long CDRgetTN(unsigned char *buffer) {
+ //printf("start CDRgetTN()\n");
+ return getTN(buffer);
+}
+
+long CDRgetTD(unsigned char track, unsigned char *buffer) {
+ unsigned char temp[3];
+ int result = getTD((int)track, temp);
+
+ // printf("start CDRgetTD()\n");
+
+ if (result == -1) return -1;
+
+ buffer[1] = temp[1];
+ buffer[2] = temp[0];
+
+ return 0;
+}
+
+/* called when the psx requests a read */
+long CDRreadTrack(unsigned char *time) {
+// SysPrintf("start CDR_readTrack()\r\n");
+ //printf("readTrack at %02d:%02d:%02d\n", BCDToInt(time[0]), BCDToInt(time[1]), BCDToInt(time[2]));
+
+ if (CD.cd != 0)
+ seekSector(BCDToInt(time[0]), BCDToInt(time[1]), BCDToInt(time[2]));
+
+// SysPrintf("end CDR_readTrack()\r\n");
+ return PSE_CDR_ERR_SUCCESS;
+}
+
+/* called after the read should be finished, and the data is needed */
+unsigned char *CDRgetBuffer(void) {
+ //printf("start CDR_getBuffer()\n");
+// SysPrintf("start CDR_getBuffer()\r\n");
+ if (CD.cd == 0)
+ return NULL;
+
+ return getSector(0);
+}
+
+unsigned char *CDRgetBufferSub(void) {
+ //printf("start CDR_getBuffer()\n");
+// SysPrintf("start CDR_getBuffer()\r\n");
+ return getSector(1);
+}
+
+/* from PSX manual p. 83 */
+#define CDR_STATUS_UNKNOWN 0x00
+#define CDR_STATUS_ERROR 0x02 /* command error detected */
+#define CDR_STATUS_STANDBY 0x04 /* spindle motor rotating */
+#define CDR_STATUS_SEEK_ERROR 0x08 /* seek error detected */
+#define CDR_STATUS_SHELL_OPEN 0x10 /* once shell open */
+#define CDR_STATUS_READING 0x20 /* reading data sectors */
+#define CDR_STATUS_SEEKING 0x40
+#define CDR_STATUS_PLAYING 0x80 /* playing CD-DA */
+
+// reads cdr status - from old plugin
+// type:
+// 0x00 - unknown
+// 0x01 - data
+// 0x02 - audio
+// 0xff - no cdrom
+// status: (only shell open supported)
+// 0x00 - unknown
+// 0x01 - error
+// 0x04 - seek error -> no disk???
+// 0x10 - shell open -> tray open
+// 0x20 - reading
+// 0x40 - seeking
+// 0x80 - playing
+// time:
+// byte 0 - minute
+// byte 1 - second
+// byte 2 - frame
+
+long CDRgetStatus(struct CdrStat *stat)
+{
+ if (CD.cd == 0) {
+ // no cd - check for disc
+ if (openDisc() < 0) {
+ if (TrayIsOpen()) {
+ stat->Type = 0xff;//0x00;
+ stat->Status |= CDR_STATUS_SHELL_OPEN;
+ } else {
+ TrayOpen();
+ stat->Type = 0xff; // indicates no cd
+ stat->Status = CDR_STATUS_UNKNOWN;
+ }
+ stat->Time[0] =
+ stat->Time[1] =
+ stat->Time[2] = 0;
+ return 0;
+ }
+ }
+
+ if (CD.tl[0].type == Mode1 || CD.tl[0].type == Mode2) {
+ stat->Type = 0x01;
+ stat->Status = CDR_STATUS_UNKNOWN;
+ } else if (CD.tl[0].type == Audio) {
+ stat->Type = 0x02;
+ stat->Status = CDR_STATUS_UNKNOWN; // FIXME
+ } else {
+ stat->Type = 0x00;
+ stat->Status = CDR_STATUS_UNKNOWN; // FIXME
+ }
+
+ stat->Time[0] =
+ stat->Time[1] =
+ stat->Time[2] = 0; // FIXME
+
+ return 0;
+}
+
+char *CDRgetDriveLetter(void) {
+ //printf("start CDR_getBuffer()\n");
+// SysPrintf("start CDR_getBuffer()\r\n");
+ return deviceFilePath;
+}
+
+#if 0
+AudioFilePlayID cdFilePlayID;
+long CDRplay(unsigned char *sector)
+{
+ // TODO: find the correct track...
+
+ NewAudioFilePlayID(&fsref, &cdFilePlayID);
+
+ return 0;
+}
+
+long CDRstop(void)
+{
+
+ return 0;
+}
+#endif
+/*
+long (CALLBACK* CDRconfigure)(void);
+long (CALLBACK* CDRtest)(void);
+void (CALLBACK* CDRabout)(void);
+*/
+
+#ifdef TEST
+int main (int argc, int *argv)
+{
+ CDRopen();
+ CDRclose();
+ return 0;
+}
+#endif
diff --git a/macosx/plugins/CDDeviceInterface/src/PlugCD.h b/macosx/plugins/CDDeviceInterface/src/PlugCD.h
new file mode 100644
index 00000000..9ca68acf
--- /dev/null
+++ b/macosx/plugins/CDDeviceInterface/src/PlugCD.h
@@ -0,0 +1,120 @@
+/***************************************************************************
+ PlugCD.h
+ CDDeviceInterface
+
+ Created by Gil Pedersen on Fri July 18 2003.
+ Copyright (c) 2003,2004 Gil Pedersen.
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. See also the license.txt file for *
+ * additional informations. *
+ * *
+ ***************************************************************************/
+
+#ifndef _PLUGCD_H_
+#define _PLUGCD_H_
+
+#include <stdio.h>
+
+#define CHAR_LEN 256
+
+// 2352 is a sector size
+#define BUFFER_SECTORS 50
+#define BUFFER_SIZE BUFFER_SECTORS*2352
+#define BZIP_BUFFER_SECTORS 10
+
+// 74 minutes * 60 sex/min * 75 frames/sec * 96 bytes needed per frame
+#define TOTAL_CD_LENGTH 74*60*75
+#define BYTES_PER_SUBCHANNEL_FRAME 96
+#define MAX_SUBCHANNEL_DATA TOTAL_CD_LENGTH*BYTES_PER_SUBCHANNEL_FRAME
+
+typedef struct {
+ char dn[128];
+ char fn[128];
+} cd_conf;
+
+cd_conf CDConfiguration;
+
+int rc;
+
+enum TrackType
+{
+ unknown, Mode1, Mode2, Audio, Pregap = 0x80
+};
+
+typedef struct
+{
+ enum TrackType type;
+ char num;
+ unsigned char start[3];
+ unsigned char end[3];
+} Track;
+
+struct
+{
+ int cd;
+ FILE* cdda;
+ int numtracks;
+ long bufferPos;
+ long bufferSize;
+ long sector;
+ long sectorType;
+ long status;
+ Track* tl;
+ unsigned char buffer[BUFFER_SIZE];
+} CD;
+
+void CDDAclose(void);
+
+// function headers for cdreader.c
+char getNumTracks();
+void seekSector(const unsigned char m, const unsigned char s, const unsigned char f);
+unsigned char* getSector();
+void newCD(const char * filename);
+void readit();
+
+
+// subtracts two times in integer format (non-BCD) -> l - r = a
+#define sub(l, r, a)\
+ a[1] = 0;\
+ a[0] = 0;\
+ a[2] = l[2] - r[2];\
+ if ((char)a[2] < 0)\
+ {\
+ a[2] += 75;\
+ a[1] -= 1;\
+ }\
+ a[1] += l[1] - r[1];\
+ if ((char)a[1] < 0)\
+ {\
+ a[1] += 60;\
+ a[0] -= 1;\
+ }\
+ a[0] += l[0] - r[0];\
+
+// converts a time like 17:61:00 to 18:01:00
+#define normalizeTime(c)\
+ while(c[2] > 75)\
+ {\
+ c[2] -= 75;\
+ c[1] += 1;\
+ }\
+ while(c[1] > 60)\
+ {\
+ c[1] -= 60;\
+ c[0] += 1;\
+ }
+
+// converts uchar in c to BCD character
+#define intToBCD(c) (unsigned char)((c%10) | ((c/10)<<4))
+
+// converts BCD number in c to uchar
+#define BCDToInt(c) (unsigned char)((c & 0x0F) + 10 * ((c & 0xF0) >> 4))
+
+#endif
+