ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/MacOSX/sys_darwin.cpp
(Generate patch)

Comparing BasiliskII/src/MacOSX/sys_darwin.cpp (file contents):
Revision 1.4 by nigel, 2004-01-26T11:11:33Z vs.
Revision 1.15 by asvitkine, 2008-07-20T07:38:27Z

# Line 7 | Line 7
7   *
8   *      Based on Apple's CDROMSample.c and Evan Jones' cd-discid.c patches
9   *
10 < *  Basilisk II (C) 1997-2004 Christian Bauer
10 > *  Basilisk II (C) 1997-2008 Christian Bauer
11   *
12   *  This program is free software; you can redistribute it and/or modify
13   *  it under the terms of the GNU General Public License as published by
# Line 31 | Line 31
31   #import <IOKit/serial/IOSerialKeys.h>
32   #import <IOKit/storage/IOMedia.h>
33   #import <IOKit/storage/IOMediaBSDClient.h>
34 < #import <IOKit/storage/IOBlockStorageDevice.h>
34 > #ifdef HAVE_IOKIT_STORAGE_IOBLOCKSTORAGEDEVICE_H
35 >        #import <IOKit/storage/IOBlockStorageDevice.h>
36 > #endif
37   #import <IOKit/storage/IOCDMedia.h>
38   #import <IOKit/storage/IOCDMediaBSDClient.h>
39   #import <CoreFoundation/CoreFoundation.h>
40  
41 < #import "sysdeps.h"
41 > #include "sysdeps.h"
42  
43 < #import "prefs.h"
43 > #include "sys.h"
44 > #include "prefs.h"
45  
46   #define DEBUG 0
47   #import "debug.h"
48  
49  
50 + // Global variables
51 + static volatile CFRunLoopRef media_poll_loop = NULL;
52 + static bool media_thread_active = false;
53 + static pthread_t media_thread;
54 +
55 + // Prototypes
56 + static void *media_poll_func(void *);
57 +
58 + // From sys_unix.cpp
59 + extern void SysMediaArrived(const char *path, int type);
60 + extern void SysMediaRemoved(const char *path, int type);
61 +
62  
63   /*
64 < *  This gets called when no "cdrom" prefs items are found
50 < *  It scans for available CD-ROM drives and adds appropriate prefs items
64 > *  Initialization
65   */
66  
67 < void DarwinAddCDROMPrefs(void)
67 > void DarwinSysInit(void)
68   {
69 <        mach_port_t                             masterPort;     // The way to talk to the kernel
70 <        io_iterator_t                   allCDs;         // List of CD drives on the system
71 <        CFMutableDictionaryRef  classesToMatch;
58 <        io_object_t                             nextCD;
69 >        media_thread_active = (pthread_create(&media_thread, NULL, media_poll_func, NULL) == 0);
70 >        D(bug("Media poll thread installed (%ld)\n", media_thread));
71 > }
72  
73  
74 <        // Don't scan for drives if nocdrom option given
75 <        if ( PrefsFindBool("nocdrom") )
76 <                return;
74 > /*
75 > *  Deinitialization
76 > */
77  
78 + void DarwinSysExit(void)
79 + {
80 +        // Stop media poll thread
81 +        if (media_thread_active) {
82 +                while (media_poll_loop == NULL || !CFRunLoopIsWaiting(media_poll_loop))
83 +                        usleep(0);
84 +                CFRunLoopStop(media_poll_loop);
85 +                pthread_join(media_thread, NULL);
86 +                media_poll_loop = NULL;
87 +                media_thread_active = false;
88 +        }
89 + }
90  
66        // Let this task talk to the guts of the kernel:
67        if ( IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS )
68                bug("IOMasterPort failed. Won't be able to do anything with CD drives\n");
91  
92 + /*
93 + *  Get the BSD-style path of specified object
94 + */
95  
96 <        // CD media are instances of class kIOCDMediaClass
97 <        classesToMatch = IOServiceMatching(kIOCDMediaClass);
98 <        if ( classesToMatch )
99 <        {
100 <                // Narrow the search a little further. Each IOMedia object
101 <                // has a property with key kIOMediaEjectable.  We limit
102 <                // the match only to those CDs that are actually ejectable
103 <                CFDictionarySetValue(classesToMatch,
104 <                                                         CFSTR(kIOMediaEjectableKey), kCFBooleanTrue);
96 > static kern_return_t get_device_path(io_object_t obj, char *path, size_t maxPathLength)
97 > {
98 >        kern_return_t kernResult = KERN_FAILURE;
99 >        CFTypeRef pathAsCFString = IORegistryEntryCreateCFProperty(obj, CFSTR(kIOBSDNameKey),
100 >                                                                                                                           kCFAllocatorDefault, 0);
101 >        if (pathAsCFString) {
102 >                strcpy(path, "/dev/");
103 >                size_t pathLength = strlen(path);
104 >                if (CFStringGetCString((const __CFString *)pathAsCFString,
105 >                                                           path + pathLength,
106 >                                                           maxPathLength - pathLength,
107 >                                                           kCFStringEncodingASCII))
108 >                        kernResult = KERN_SUCCESS;
109 >                CFRelease(pathAsCFString);
110          }
111 +        return kernResult;
112 + }
113  
82        if ( IOServiceGetMatchingServices(masterPort,
83                                                                          classesToMatch, &allCDs) != KERN_SUCCESS )
84        {
85                D(bug("IOServiceGetMatchingServices failed. No CD media drives found?\n"));
86                return;
87        }
114  
115 + /*
116 + *  kIOMatchedNotification handler
117 + */
118  
119 <        // Iterate through each CD drive
120 <        while ( nextCD = IOIteratorNext(allCDs))
121 <        {
122 <                char            bsdPath[MAXPATHLEN];
123 <                CFTypeRef       bsdPathAsCFString =
124 <                                                IORegistryEntryCreateCFProperty(nextCD,
125 <                                                                                                                CFSTR(kIOBSDNameKey),
126 <                                                                                                                kCFAllocatorDefault, 0);
127 <                *bsdPath = '\0';
128 <                if ( bsdPathAsCFString )
129 <                {
130 <                        size_t devPathLength;
119 > static void media_arrived(int type, io_iterator_t iterator)
120 > {
121 >        io_object_t obj;
122 >        while ((obj = IOIteratorNext(iterator))) {
123 >                char path[MAXPATHLEN];
124 >                kern_return_t kernResult = get_device_path(obj, path, sizeof(path));
125 >                if (kernResult == KERN_SUCCESS) {
126 >                        D(bug("Media Arrived: %s\n", path));
127 >                        SysMediaArrived(path, type);
128 >                }
129 >                kernResult = IOObjectRelease(obj);
130 >                if (kernResult != KERN_SUCCESS) {
131 >                        fprintf(stderr, "IOObjectRelease() returned %d\n", kernResult);
132 >                }
133 >        }
134 > }
135  
103                        strcpy(bsdPath, "/dev/");
104                        devPathLength = strlen(bsdPath);
136  
137 <                        if ( CFStringGetCString((const __CFString *)bsdPathAsCFString,
138 <                                                                         bsdPath + devPathLength,
139 <                                                                         MAXPATHLEN - devPathLength,
109 <                                                                         kCFStringEncodingASCII) )
110 <                        {
111 <                                D(bug("CDROM BSD path: %s\n", bsdPath));
112 <                                PrefsAddString("cdrom", bsdPath);
113 <                        }
114 <                        else
115 <                                D(bug("Could not get BSD device path for CD\n"));
137 > /*
138 > *  kIOTerminatedNotification handler
139 > */
140  
141 <                        CFRelease(bsdPathAsCFString);
141 > static void media_removed(int type, io_iterator_t iterator)
142 > {
143 >        io_object_t obj;
144 >        while ((obj = IOIteratorNext(iterator))) {
145 >                char path[MAXPATHLEN];
146 >                kern_return_t kernResult = get_device_path(obj, path, sizeof(path));
147 >                if (kernResult == KERN_SUCCESS) {
148 >                        D(bug("Media Removed: %s\n", path));
149 >                        SysMediaRemoved(path, type);
150 >                }
151 >                kernResult = IOObjectRelease(obj);
152 >                if (kernResult != KERN_SUCCESS) {
153 >                        fprintf(stderr, "IOObjectRelease() returned %d\n", kernResult);
154                  }
155 <                else
156 <                        D(bug("Cannot determine bsdPath for CD\n"));
155 >        }
156 > }
157 >
158 >
159 > /*
160 > *  Media poll function
161 > *
162 > *  NOTE: to facilitate orderly thread termination, media_poll_func MUST end up waiting in CFRunLoopRun.
163 > *  Early returns must be avoided, even if there is nothing useful to be done here. See DarwinSysExit.
164 > */
165 >
166 > static void dummy(void *) { };  // stub for dummy runloop source
167 >
168 > static void *media_poll_func(void *)
169 > {
170 >        media_poll_loop = CFRunLoopGetCurrent();
171 >
172 >        mach_port_t masterPort;
173 >        kern_return_t kernResult;
174 >        CFMutableDictionaryRef matchingDictionary;
175 >        CFRunLoopSourceRef loopSource = NULL;
176 >        CFRunLoopSourceRef dummySource = NULL;
177 >
178 >        if ((kernResult = IOMasterPort(bootstrap_port, &masterPort)) != KERN_SUCCESS)
179 >                fprintf(stderr, "IOMasterPort() returned %d\n", kernResult);
180 >        else if ((matchingDictionary = IOServiceMatching(kIOCDMediaClass)) == NULL)
181 >                fprintf(stderr, "IOServiceMatching() returned a NULL dictionary\n");
182 >        else {
183 >                matchingDictionary = (CFMutableDictionaryRef)CFRetain(matchingDictionary);
184 >                IONotificationPortRef notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
185 >                loopSource = IONotificationPortGetRunLoopSource(notificationPort);
186 >                CFRunLoopAddSource(media_poll_loop, loopSource, kCFRunLoopDefaultMode);
187 >
188 >                io_iterator_t mediaArrivedIterator;
189 >                kernResult = IOServiceAddMatchingNotification(notificationPort,
190 >                        kIOMatchedNotification,
191 >                        matchingDictionary,
192 >                        (IOServiceMatchingCallback)media_arrived,
193 >                        (void *)MEDIA_CD, &mediaArrivedIterator);
194 >                if (kernResult != KERN_SUCCESS)
195 >                        fprintf(stderr, "IOServiceAddMatchingNotification() returned %d\n", kernResult);
196 >                media_arrived(MEDIA_CD, mediaArrivedIterator);
197 >
198 >                io_iterator_t mediaRemovedIterator;
199 >                kernResult = IOServiceAddMatchingNotification(notificationPort,
200 >                        kIOTerminatedNotification,
201 >                        matchingDictionary,
202 >                        (IOServiceMatchingCallback)media_removed,
203 >                        (void *)MEDIA_CD, &mediaRemovedIterator);
204 >                if (kernResult != KERN_SUCCESS)
205 >                        fprintf(stderr, "IOServiceAddMatchingNotification() returned %d\n", kernResult);
206 >                media_removed(MEDIA_CD, mediaRemovedIterator);
207          }
208  
209 <        IOObjectRelease(nextCD);
210 <        IOObjectRelease(allCDs);
209 >        if (loopSource == NULL) {
210 >                // add a dummy runloop source to prevent premature return from CFRunLoopRun
211 >                CFRunLoopSourceContext context = { 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, dummy };
212 >                dummySource = CFRunLoopSourceCreate(NULL, 0, &context);
213 >                CFRunLoopAddSource(media_poll_loop, dummySource, kCFRunLoopDefaultMode);
214 >        }
215 >
216 >        CFRunLoopRun();
217 >
218 >        if (dummySource != NULL)
219 >                CFRelease(dummySource);
220 >        return NULL;
221   }
222  
223  
224   void DarwinAddFloppyPrefs(void)
225   {
226          mach_port_t                             masterPort;             // The way to talk to the kernel
227 <        io_iterator_t                   allFloppies;    // List of CD drives on the system
227 >        io_iterator_t                   allFloppies;    // List of possible floppys
228          CFMutableDictionaryRef  classesToMatch;
229          io_object_t                             nextFloppy;
230  
# Line 137 | Line 233 | void DarwinAddFloppyPrefs(void)
233                  bug("IOMasterPort failed. Won't be able to do anything with floppy drives\n");
234  
235  
236 +        // This selects all partitions of all disks
237          classesToMatch = IOServiceMatching(kIOMediaClass);
238          if ( classesToMatch )
239          {
240 <                // We acually want removables that are _not_ CDs,
241 <                // but I don't know how to do that yet.
240 >                // Skip drivers and partitions
241 >                CFDictionarySetValue(classesToMatch,
242 >                                                         CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
243 >        
244 >                // Skip fixed drives (hard disks?)
245                  CFDictionarySetValue(classesToMatch,
246 <                                                         CFSTR(kIOMediaRemovableKey), kCFBooleanTrue);
246 >                                                         CFSTR(kIOMediaEjectableKey), kCFBooleanTrue);
247          }
248  
249          if ( IOServiceGetMatchingServices(masterPort,
# Line 153 | Line 253 | void DarwinAddFloppyPrefs(void)
253                  return;
254          }
255  
156
256          // Iterate through each floppy
257          while ( nextFloppy = IOIteratorNext(allFloppies))
258          {
259                  char            bsdPath[MAXPATHLEN];
260 <                CFTypeRef       bsdPathAsCFString =
260 >                long            size;
261 >                CFTypeRef       sizeAsCFNumber =
262                                                  IORegistryEntryCreateCFProperty(nextFloppy,
263 <                                                                                                                CFSTR(kIOBSDNameKey),
263 >                                                                                                                CFSTR(kIOMediaSizeKey),
264                                                                                                                  kCFAllocatorDefault, 0);
165                *bsdPath = '\0';
166                if ( bsdPathAsCFString )
167                {
168                        size_t devPathLength;
169
170                        strcpy(bsdPath, "/dev/");
171                        devPathLength = strlen(bsdPath);
265  
266 <                        if ( CFStringGetCString((const __CFString *)bsdPathAsCFString,
267 <                                                                         bsdPath + devPathLength,
268 <                                                                         MAXPATHLEN - devPathLength,
269 <                                                                         kCFStringEncodingASCII) )
266 >                if ( CFNumberGetValue((CFNumberRef)sizeAsCFNumber,
267 >                                                                kCFNumberSInt32Type, &size) )
268 >                {
269 >                        D(bug("Got size of %ld\n", size));
270 >                        if ( size < 800 * 1024 || size > 1440 * 1024 )
271                          {
272 <                                D(bug("Floppy BSD path: %s\n", bsdPath));
273 <                                PrefsAddString("floppy", bsdPath);
272 >                                D(puts("Device does not appear to be 800k or 1440k"));
273 >                                continue;
274                          }
275 <                        else
276 <                                D(bug("Could not get BSD device path for floppy\n"));
275 >                }
276 >                else {
277 >                        D(puts("Couldn't get kIOMediaSizeKey of device"));
278 >                        continue; // if kIOMediaSizeKey is unavailable, we shouldn't use it anyway
279 >                }
280  
281 <                        CFRelease(bsdPathAsCFString);
281 >                if (get_device_path(nextFloppy, bsdPath, sizeof(bsdPath)) == KERN_SUCCESS) {
282 >                        PrefsAddString("floppy", bsdPath);
283 >                } else {
284 >                        D(bug("Could not get BSD device path for floppy\n"));
285                  }
186                else
187                        D(bug("Cannot determine bsdPath for floppy\n"));
286          }
287  
288          IOObjectRelease(nextFloppy);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines