pcsxr-1.9.92
[pcsx_rearmed.git] / macosx / plugins / DFCdrom / macsrc / cdr-macosx.c
1 /*
2  * Copyright (c) 2010, Wei Mingzhi <whistler@openoffice.org>.
3  * All Rights Reserved.
4  *
5  * Based on: Cdrom for Psemu Pro like Emulators
6  * By: linuzappz <linuzappz@hotmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, see <http://www.gnu.org/licenses>.
20  */
21
22 #include "cdr.h"
23
24 #ifdef _MACOSX
25
26 #include <IOKit/IOKitLib.h>
27 #include <IOKit/IOBSD.h>
28 #include <IOKit/storage/IOCDMedia.h>
29 #include <IOKit/storage/IODVDMedia.h>
30 #include <IOKit/storage/IOMedia.h>
31 #include <IOKit/storage/IOCDMediaBSDClient.h>
32 #include <CoreFoundation/CoreFoundation.h>
33
34 int cdHandle = -1;
35 char cdDevice[4096] = "";
36
37 static int IsPsxDisc(const char *dev) {
38         int fd;
39         char buf[CD_FRAMESIZE_RAW];
40         dk_cd_read_t r;
41
42         fd = open(dev, O_RDONLY, 0);
43         if (fd < 0) return 0;
44
45         memset(&r, 0, sizeof(r));
46
47         r.offset = msf_to_lba(0, 2, 4) * CD_FRAMESIZE_RAW;
48         r.sectorArea = 0xF8;
49         r.sectorType = kCDSectorTypeUnknown;
50         r.bufferLength = CD_FRAMESIZE_RAW;
51         r.buffer = buf;
52
53         if (ioctl(fd, DKIOCCDREAD, &r) != kIOReturnSuccess) {
54                 close(fd);
55                 return 0;
56         }
57
58         close(fd);
59
60         if (strncmp(buf + 56, "Sony Computer Entertainment", 27) == 0) {
61                 return 1;
62         }
63
64         return 0;
65 }
66
67 static void FindCdDevice(char *dev) {
68         io_object_t   next_media;
69         kern_return_t kern_result;
70         io_iterator_t media_iterator;
71         CFMutableDictionaryRef classes_to_match;
72         const char *name, *cd = kIOCDMediaClass, *dvd = kIODVDMediaClass;
73
74         dev[0] = '\0';
75         name = cd;
76
77 start:
78         classes_to_match = IOServiceMatching(name);
79         if (classes_to_match == NULL) goto end;
80
81         CFDictionarySetValue(classes_to_match, CFSTR(kIOMediaEjectableKey),
82                 kCFBooleanTrue);
83
84         kern_result = IOServiceGetMatchingServices(kIOMasterPortDefault, 
85                 classes_to_match, &media_iterator);
86
87         if (kern_result != KERN_SUCCESS) goto end;
88
89         next_media = IOIteratorNext(media_iterator);
90         if (next_media != 0) {
91                 char psz_buf[0x32];
92                 size_t dev_path_length;
93                 CFTypeRef str_bsd_path;
94
95                 do {
96                         str_bsd_path = IORegistryEntryCreateCFProperty(next_media,
97                                 CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0);
98
99                         if (str_bsd_path == NULL) {
100                                 IOObjectRelease(next_media);
101                                 continue;
102                         }
103
104                         strcpy(psz_buf, "/dev/r");
105                         dev_path_length = strlen(psz_buf);
106
107                         if (CFStringGetCString(str_bsd_path, (char *)&psz_buf + dev_path_length,
108                                 sizeof(psz_buf) - dev_path_length, kCFStringEncodingASCII))
109                         {
110                                 strcpy(dev, psz_buf);
111
112                                 if (IsPsxDisc(dev)) {
113                                         CFRelease(str_bsd_path);
114                                         IOObjectRelease(next_media);
115                                         IOObjectRelease(media_iterator);
116                                         return;
117                                 }
118                         }
119
120                         CFRelease(str_bsd_path);
121                         IOObjectRelease(next_media);
122                 } while ((next_media = IOIteratorNext(media_iterator)) != 0);
123         }
124
125         IOObjectRelease(media_iterator);
126
127 end:
128         if (dev[0] == '\0') {
129                 if (name == cd) {
130                         name = dvd; // Is this really necessary or correct? Dunno...
131                         goto start;
132                 }
133         }
134 }
135
136 int OpenCdHandle(const char *dev) {
137         if (dev != NULL && dev[0] != '\0') strcpy(cdDevice, dev);
138         else if (cdDevice[0] == '\0') FindCdDevice(cdDevice);
139
140         cdHandle = open(cdDevice, O_RDONLY, 0);
141         if (cdHandle < 0) return -1;
142
143         if (CdrSpeed > 0) {
144                 u_int16_t speed = kCDSpeedMin * CdrSpeed;
145                 ioctl(cdHandle, DKIOCCDSETSPEED, &speed);
146         }
147
148         return 0;
149 }
150
151 void CloseCdHandle() {
152         if (cdHandle != -1) close(cdHandle);
153         cdHandle = -1;
154 }
155
156 int IsCdHandleOpen() {
157         return 1;
158 }
159
160 long GetTN(unsigned char *buffer) {
161         if (cdHandle < 0) return -1;
162
163         // TODO
164         buffer[0] = 1;
165         buffer[1] = 1;
166
167         return 0;
168 }
169
170 long GetTD(unsigned char track, unsigned char *buffer) {
171         if (cdHandle < 0) return -1;
172
173         // TODO
174         memset(buffer + 1, 0, 3);
175         return 0;
176 }
177
178 long GetTE(unsigned char track, unsigned char *m, unsigned char *s, unsigned char *f) {
179         return -1; // TODO
180 }
181
182 long ReadSector(crdata *cr) {
183         int lba;
184         dk_cd_read_t r;
185
186         if (cdHandle < 0) return -1;
187
188         lba = msf_to_lba(cr->msf.cdmsf_min0, cr->msf.cdmsf_sec0, cr->msf.cdmsf_frame0);
189
190         memset(&r, 0, sizeof(r));
191
192         r.offset = lba * CD_FRAMESIZE_RAW;
193         r.sectorArea = 0xF8;
194         r.sectorType = kCDSectorTypeUnknown;
195         r.bufferLength = CD_FRAMESIZE_RAW;
196         r.buffer = cr->buf;
197
198         if (ioctl(cdHandle, DKIOCCDREAD, &r) != kIOReturnSuccess) {
199                 return -1;
200         }
201
202         return 0;
203 }
204
205 long PlayCDDA(unsigned char *sector) {
206         return 0; // TODO
207 }
208
209 long StopCDDA() {
210         return 0; // TODO
211 }
212
213 long GetStatus(int playing, struct CdrStat *stat) {
214         memset(stat, 0, sizeof(struct CdrStat));
215         stat->Type = 0x01;
216
217         // Close and reopen the CD handle. If opening failed,
218         // then there is no CD in drive.
219         // Note that this WILL be screwed if user inserted another
220         // removable device such as USB stick when tray is open.
221         // There may be a better way, but this should do the job.
222         if (cdHandle >= 0) {
223                 close(cdHandle);
224                 cdHandle = -1;
225         }
226
227         cdHandle = open(cdDevice, O_RDONLY, 0);
228         if (cdHandle < 0) {
229                 // No CD in drive
230                 stat->Type = 0xff;
231                 stat->Status |= 0x10;
232         } else {
233                 if (CdrSpeed > 0) {
234                         u_int16_t speed = kCDSpeedMin * CdrSpeed;
235                         ioctl(cdHandle, DKIOCCDSETSPEED, &speed);
236                 }
237         }
238
239         return 0;
240 }
241
242 unsigned char *ReadSub(const unsigned char *time) {
243         return NULL; // TODO
244 }
245
246 char *CDRgetDriveLetter(void) {
247         return cdDevice;
248 }
249
250 #endif