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.3 by nigel, 2004-01-20T23:31:46Z 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 28 | Line 28
28   #import <sys/param.h>
29   #import <IOKit/IOKitLib.h>
30   #import <IOKit/IOBSD.h>
31 + #import <IOKit/serial/IOSerialKeys.h>
32   #import <IOKit/storage/IOMedia.h>
33   #import <IOKit/storage/IOMediaBSDClient.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
48 < *  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;
56 <        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 >
91 >
92 > /*
93 > *  Get the BSD-style path of specified object
94 > */
95 >
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 >
114 >
115 > /*
116 > *  kIOMatchedNotification handler
117 > */
118 >
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 >
136 >
137 > /*
138 > *  kIOTerminatedNotification handler
139 > */
140 >
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 >        }
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 >        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 possible floppys
228 >        CFMutableDictionaryRef  classesToMatch;
229 >        io_object_t                             nextFloppy;
230  
231  
64        // Let this task talk to the guts of the kernel:
232          if ( IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS )
233 <                bug("IOMasterPort failed. Won't be able to do anything with CD drives");
233 >                bug("IOMasterPort failed. Won't be able to do anything with floppy drives\n");
234  
235  
236 <        // CD media are instances of class kIOCDMediaClass
237 <        classesToMatch = IOServiceMatching(kIOCDMediaClass);
236 >        // This selects all partitions of all disks
237 >        classesToMatch = IOServiceMatching(kIOMediaClass);
238          if ( classesToMatch )
239          {
240 <                // Narrow the search a little further. Each IOMedia object
241 <                // has a property with key kIOMediaEjectable.  We limit
242 <                // the match only to those CDs that are actually ejectable
240 >                // Skip drivers and partitions
241 >                CFDictionarySetValue(classesToMatch,
242 >                                                         CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
243 >        
244 >                // Skip fixed drives (hard disks?)
245                  CFDictionarySetValue(classesToMatch,
246                                                           CFSTR(kIOMediaEjectableKey), kCFBooleanTrue);
247          }
248  
249          if ( IOServiceGetMatchingServices(masterPort,
250 <                                                                          classesToMatch, &allCDs) != KERN_SUCCESS )
250 >                                                                          classesToMatch, &allFloppies) != KERN_SUCCESS )
251          {
252 <                D(bug("IOServiceGetMatchingServices failed. No CD media drives found?\n"));
252 >                D(bug("IOServiceGetMatchingServices failed. No removable drives found?\n"));
253                  return;
254          }
255  
256 +        // Iterate through each floppy
257 +        while ( nextFloppy = IOIteratorNext(allFloppies))
258 +        {
259 +                char            bsdPath[MAXPATHLEN];
260 +                long            size;
261 +                CFTypeRef       sizeAsCFNumber =
262 +                                                IORegistryEntryCreateCFProperty(nextFloppy,
263 +                                                                                                                CFSTR(kIOMediaSizeKey),
264 +                                                                                                                kCFAllocatorDefault, 0);
265 +
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(puts("Device does not appear to be 800k or 1440k"));
273 +                                continue;
274 +                        }
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 +                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 +                }
286 +        }
287 +
288 +        IOObjectRelease(nextFloppy);
289 +        IOObjectRelease(allFloppies);
290 + }
291 +
292 +
293 + void DarwinAddSerialPrefs(void)
294 + {
295 +        mach_port_t                             masterPort;             // The way to talk to the kernel
296 +        io_iterator_t                   allModems;              // List of modems on the system
297 +        CFMutableDictionaryRef  classesToMatch;
298 +        io_object_t                             nextModem;
299 +
300 +
301 +        if ( IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS )
302 +                bug("IOMasterPort failed. Won't be able to do anything with modems\n");
303 +
304 +
305 +    // Serial devices are instances of class IOSerialBSDClient
306 +    classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
307 +        if ( classesToMatch )
308 +        {
309 +                // Narrow the search a little further. Each serial device object has
310 +                // a property with key kIOSerialBSDTypeKey and a value that is one of
311 +                // kIOSerialBSDAllTypes, kIOSerialBSDModemType, or kIOSerialBSDRS232Type.
312 +
313 +        CFDictionarySetValue(classesToMatch,
314 +                             CFSTR(kIOSerialBSDTypeKey),
315 +                             CFSTR(kIOSerialBSDModemType));
316 +
317 +        // This will find built-in and USB modems, but not serial modems.
318 +        }
319 +
320 +        if ( IOServiceGetMatchingServices(masterPort,
321 +                                                                          classesToMatch, &allModems) != KERN_SUCCESS )
322 +        {
323 +                D(bug("IOServiceGetMatchingServices failed. No modems found?\n"));
324 +                return;
325 +        }
326  
327 <        // Iterate through each CD drive
328 <        while ( nextCD = IOIteratorNext(allCDs))
327 >        // Iterate through each modem
328 >        while ( nextModem = IOIteratorNext(allModems))
329          {
330                  char            bsdPath[MAXPATHLEN];
331                  CFTypeRef       bsdPathAsCFString =
332 <                                                IORegistryEntryCreateCFProperty(nextCD,
333 <                                                                                                                CFSTR(kIOBSDNameKey),
332 >                                                IORegistryEntryCreateCFProperty(nextModem,
333 >                                                                                                                CFSTR(kIOCalloutDeviceKey),
334 >                                                                                                                // kIODialinDeviceKey?
335                                                                                                                  kCFAllocatorDefault, 0);
336                  *bsdPath = '\0';
337                  if ( bsdPathAsCFString )
338                  {
99                        size_t devPathLength;
100
101                        strcpy(bsdPath, "/dev/");
102                        devPathLength = strlen(bsdPath);
103
339                          if ( CFStringGetCString((const __CFString *)bsdPathAsCFString,
340 <                                                                         bsdPath + devPathLength,
106 <                                                                         MAXPATHLEN - devPathLength,
340 >                                                                         bsdPath, MAXPATHLEN,
341                                                                           kCFStringEncodingASCII) )
342                          {
343 <                                // If we try to do raw reads on the file bsdPath (e.g. /dev/disk5),
344 <                                // we get a lot of extra padding in the data. For some reason,
345 <                                // the device we need has a different name (e.g. /dev/disk5s1)
346 <                                //strcat(bsdPath, "s1");
113 <                                D(bug("CDROM BSD path: %s\n", bsdPath));
343 >                                D(bug("Modem BSD path: %s\n", bsdPath));
344 >
345 >                                // Note that if there are multiple modems, we only get the last
346 >                                PrefsAddString("seriala", bsdPath);
347                          }
348                          else
349 <                                D(bug("Could not get BSD device path for CD\n"));
349 >                                D(bug("Could not get BSD device path for modem\n"));
350  
351                          CFRelease(bsdPathAsCFString);
352                  }
353 <
354 <                PrefsAddString("cdrom", bsdPath);
353 >                else
354 >                        D(puts("Cannot determine bsdPath for modem\n"));
355          }
356  
357 <        IOObjectRelease(nextCD);
358 <        IOObjectRelease(allCDs);
357 >        IOObjectRelease(nextModem);
358 >        IOObjectRelease(allModems);
359 >
360 >
361 >        // Getting a printer device is a bit harder. Creating a fake device
362 >        // that emulates a simple printer (e.g. a HP DeskJet) is one possibility,
363 >        // but for now I will just create a fake, safe, device entry:
364 >
365 >        PrefsAddString("serialb", "/dev/null");
366   }
367  
368  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines