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.17 by asvitkine, 2012-04-21T16:04:51Z

# 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;
72 <        io_object_t                             nextCD;
69 >        if (PrefsFindBool("nocdrom")) {
70 >                media_thread_active = (pthread_create(&media_thread, NULL, media_poll_func, NULL) == 0);
71 >                D(bug("Media poll thread installed (%ld)\n", media_thread));
72 >        }
73 > }
74  
75  
76 <        // Don't scan for drives if nocdrom option given
77 <        if ( PrefsFindBool("nocdrom") )
78 <                return;
76 > /*
77 > *  Deinitialization
78 > */
79 >
80 > void DarwinSysExit(void)
81 > {
82 >        // Stop media poll thread
83 >        if (media_thread_active) {
84 >                while (media_poll_loop == NULL || !CFRunLoopIsWaiting(media_poll_loop))
85 >                        usleep(0);
86 >                CFRunLoopStop(media_poll_loop);
87 >                pthread_join(media_thread, NULL);
88 >                media_poll_loop = NULL;
89 >                media_thread_active = false;
90 >        }
91 > }
92 >
93 >
94 > /*
95 > *  Get the BSD-style path of specified object
96 > */
97 >
98 > static kern_return_t get_device_path(io_object_t obj, char *path, size_t maxPathLength)
99 > {
100 >        kern_return_t kernResult = KERN_FAILURE;
101 >        CFTypeRef pathAsCFString = IORegistryEntryCreateCFProperty(obj, CFSTR(kIOBSDNameKey),
102 >                                                                                                                           kCFAllocatorDefault, 0);
103 >        if (pathAsCFString) {
104 >                strcpy(path, "/dev/");
105 >                size_t pathLength = strlen(path);
106 >                if (CFStringGetCString((const __CFString *)pathAsCFString,
107 >                                                           path + pathLength,
108 >                                                           maxPathLength - pathLength,
109 >                                                           kCFStringEncodingASCII))
110 >                        kernResult = KERN_SUCCESS;
111 >                CFRelease(pathAsCFString);
112 >        }
113 >        return kernResult;
114 > }
115 >
116 >
117 > /*
118 > *  kIOMatchedNotification handler
119 > */
120 >
121 > static void media_arrived(int type, io_iterator_t iterator)
122 > {
123 >        io_object_t obj;
124 >        while ((obj = IOIteratorNext(iterator))) {
125 >                char path[MAXPATHLEN];
126 >                kern_return_t kernResult = get_device_path(obj, path, sizeof(path));
127 >                if (kernResult == KERN_SUCCESS) {
128 >                        D(bug("Media Arrived: %s\n", path));
129 >                        SysMediaArrived(path, type);
130 >                }
131 >                kernResult = IOObjectRelease(obj);
132 >                if (kernResult != KERN_SUCCESS) {
133 >                        fprintf(stderr, "IOObjectRelease() returned %d\n", kernResult);
134 >                }
135 >        }
136 > }
137 >
138 >
139 > /*
140 > *  kIOTerminatedNotification handler
141 > */
142 >
143 > static void media_removed(int type, io_iterator_t iterator)
144 > {
145 >        io_object_t obj;
146 >        while ((obj = IOIteratorNext(iterator))) {
147 >                char path[MAXPATHLEN];
148 >                kern_return_t kernResult = get_device_path(obj, path, sizeof(path));
149 >                if (kernResult == KERN_SUCCESS) {
150 >                        D(bug("Media Removed: %s\n", path));
151 >                        SysMediaRemoved(path, type);
152 >                }
153 >                kernResult = IOObjectRelease(obj);
154 >                if (kernResult != KERN_SUCCESS) {
155 >                        fprintf(stderr, "IOObjectRelease() returned %d\n", kernResult);
156 >                }
157 >        }
158 > }
159 >
160 >
161 > /*
162 > *  Media poll function
163 > *
164 > *  NOTE: to facilitate orderly thread termination, media_poll_func MUST end up waiting in CFRunLoopRun.
165 > *  Early returns must be avoided, even if there is nothing useful to be done here. See DarwinSysExit.
166 > */
167 >
168 > static void dummy(void *) { };  // stub for dummy runloop source
169 >
170 > static void *media_poll_func(void *)
171 > {
172 >        media_poll_loop = CFRunLoopGetCurrent();
173 >
174 >        mach_port_t masterPort;
175 >        kern_return_t kernResult;
176 >        CFMutableDictionaryRef matchingDictionary;
177 >        CFRunLoopSourceRef loopSource = NULL;
178 >        CFRunLoopSourceRef dummySource = NULL;
179 >
180 >        if ((kernResult = IOMasterPort(bootstrap_port, &masterPort)) != KERN_SUCCESS)
181 >                fprintf(stderr, "IOMasterPort() returned %d\n", kernResult);
182 >        else if ((matchingDictionary = IOServiceMatching(kIOCDMediaClass)) == NULL)
183 >                fprintf(stderr, "IOServiceMatching() returned a NULL dictionary\n");
184 >        else {
185 >                matchingDictionary = (CFMutableDictionaryRef)CFRetain(matchingDictionary);
186 >                IONotificationPortRef notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
187 >                loopSource = IONotificationPortGetRunLoopSource(notificationPort);
188 >                CFRunLoopAddSource(media_poll_loop, loopSource, kCFRunLoopDefaultMode);
189 >
190 >                io_iterator_t mediaArrivedIterator;
191 >                kernResult = IOServiceAddMatchingNotification(notificationPort,
192 >                        kIOMatchedNotification,
193 >                        matchingDictionary,
194 >                        (IOServiceMatchingCallback)media_arrived,
195 >                        (void *)MEDIA_CD, &mediaArrivedIterator);
196 >                if (kernResult != KERN_SUCCESS)
197 >                        fprintf(stderr, "IOServiceAddMatchingNotification() returned %d\n", kernResult);
198 >                media_arrived(MEDIA_CD, mediaArrivedIterator);
199 >
200 >                io_iterator_t mediaRemovedIterator;
201 >                kernResult = IOServiceAddMatchingNotification(notificationPort,
202 >                        kIOTerminatedNotification,
203 >                        matchingDictionary,
204 >                        (IOServiceMatchingCallback)media_removed,
205 >                        (void *)MEDIA_CD, &mediaRemovedIterator);
206 >                if (kernResult != KERN_SUCCESS)
207 >                        fprintf(stderr, "IOServiceAddMatchingNotification() returned %d\n", kernResult);
208 >                media_removed(MEDIA_CD, mediaRemovedIterator);
209 >        }
210 >
211 >        if (loopSource == NULL) {
212 >                // add a dummy runloop source to prevent premature return from CFRunLoopRun
213 >                CFRunLoopSourceContext context = { 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, dummy };
214 >                dummySource = CFRunLoopSourceCreate(NULL, 0, &context);
215 >                CFRunLoopAddSource(media_poll_loop, dummySource, kCFRunLoopDefaultMode);
216 >        }
217 >
218 >        CFRunLoopRun();
219 >
220 >        if (dummySource != NULL)
221 >                CFRelease(dummySource);
222 >        return NULL;
223 > }
224 >
225 >
226 > void DarwinAddFloppyPrefs(void)
227 > {
228 >        mach_port_t                             masterPort;             // The way to talk to the kernel
229 >        io_iterator_t                   allFloppies;    // List of possible floppys
230 >        CFMutableDictionaryRef  classesToMatch;
231 >        io_object_t                             nextFloppy;
232  
233  
64        // Let this task talk to the guts of the kernel:
234          if ( IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS )
235 <                bug("IOMasterPort failed. Won't be able to do anything with CD drives");
235 >                bug("IOMasterPort failed. Won't be able to do anything with floppy drives\n");
236  
237  
238 <        // CD media are instances of class kIOCDMediaClass
239 <        classesToMatch = IOServiceMatching(kIOCDMediaClass);
238 >        // This selects all partitions of all disks
239 >        classesToMatch = IOServiceMatching(kIOMediaClass);
240          if ( classesToMatch )
241          {
242 <                // Narrow the search a little further. Each IOMedia object
243 <                // has a property with key kIOMediaEjectable.  We limit
244 <                // the match only to those CDs that are actually ejectable
242 >                // Skip drivers and partitions
243 >                CFDictionarySetValue(classesToMatch,
244 >                                                         CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
245 >        
246 >                // Skip fixed drives (hard disks?)
247                  CFDictionarySetValue(classesToMatch,
248                                                           CFSTR(kIOMediaEjectableKey), kCFBooleanTrue);
249          }
250  
251          if ( IOServiceGetMatchingServices(masterPort,
252 <                                                                          classesToMatch, &allCDs) != KERN_SUCCESS )
252 >                                                                          classesToMatch, &allFloppies) != KERN_SUCCESS )
253          {
254 <                D(bug("IOServiceGetMatchingServices failed. No CD media drives found?\n"));
254 >                D(bug("IOServiceGetMatchingServices failed. No removable drives found?\n"));
255                  return;
256          }
257  
258 +        // Iterate through each floppy
259 +        while ( nextFloppy = IOIteratorNext(allFloppies))
260 +        {
261 +                char            bsdPath[MAXPATHLEN];
262 +                long            size;
263 +                CFTypeRef       sizeAsCFNumber =
264 +                                                IORegistryEntryCreateCFProperty(nextFloppy,
265 +                                                                                                                CFSTR(kIOMediaSizeKey),
266 +                                                                                                                kCFAllocatorDefault, 0);
267 +
268 +                if ( CFNumberGetValue((CFNumberRef)sizeAsCFNumber,
269 +                                                                kCFNumberSInt32Type, &size) )
270 +                {
271 +                        D(bug("Got size of %ld\n", size));
272 +                        if ( size < 800 * 1024 || size > 1440 * 1024 )
273 +                        {
274 +                                D(puts("Device does not appear to be 800k or 1440k"));
275 +                                continue;
276 +                        }
277 +                }
278 +                else {
279 +                        D(puts("Couldn't get kIOMediaSizeKey of device"));
280 +                        continue; // if kIOMediaSizeKey is unavailable, we shouldn't use it anyway
281 +                }
282 +
283 +                if (get_device_path(nextFloppy, bsdPath, sizeof(bsdPath)) == KERN_SUCCESS) {
284 +                        PrefsAddString("floppy", bsdPath);
285 +                } else {
286 +                        D(bug("Could not get BSD device path for floppy\n"));
287 +                }
288 +        }
289 +
290 +        IOObjectRelease(nextFloppy);
291 +        IOObjectRelease(allFloppies);
292 + }
293 +
294  
295 <        // Iterate through each CD drive
296 <        while ( nextCD = IOIteratorNext(allCDs))
295 > void DarwinAddSerialPrefs(void)
296 > {
297 >        mach_port_t                             masterPort;             // The way to talk to the kernel
298 >        io_iterator_t                   allModems;              // List of modems on the system
299 >        CFMutableDictionaryRef  classesToMatch;
300 >        io_object_t                             nextModem;
301 >
302 >
303 >        if ( IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS )
304 >                bug("IOMasterPort failed. Won't be able to do anything with modems\n");
305 >
306 >
307 >    // Serial devices are instances of class IOSerialBSDClient
308 >    classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
309 >        if ( classesToMatch )
310 >        {
311 >                // Narrow the search a little further. Each serial device object has
312 >                // a property with key kIOSerialBSDTypeKey and a value that is one of
313 >                // kIOSerialBSDAllTypes, kIOSerialBSDModemType, or kIOSerialBSDRS232Type.
314 >
315 >        CFDictionarySetValue(classesToMatch,
316 >                             CFSTR(kIOSerialBSDTypeKey),
317 >                             CFSTR(kIOSerialBSDModemType));
318 >
319 >        // This will find built-in and USB modems, but not serial modems.
320 >        }
321 >
322 >        if ( IOServiceGetMatchingServices(masterPort,
323 >                                                                          classesToMatch, &allModems) != KERN_SUCCESS )
324 >        {
325 >                D(bug("IOServiceGetMatchingServices failed. No modems found?\n"));
326 >                return;
327 >        }
328 >
329 >        // Iterate through each modem
330 >        while ( nextModem = IOIteratorNext(allModems))
331          {
332                  char            bsdPath[MAXPATHLEN];
333                  CFTypeRef       bsdPathAsCFString =
334 <                                                IORegistryEntryCreateCFProperty(nextCD,
335 <                                                                                                                CFSTR(kIOBSDNameKey),
334 >                                                IORegistryEntryCreateCFProperty(nextModem,
335 >                                                                                                                CFSTR(kIOCalloutDeviceKey),
336 >                                                                                                                // kIODialinDeviceKey?
337                                                                                                                  kCFAllocatorDefault, 0);
338                  *bsdPath = '\0';
339                  if ( bsdPathAsCFString )
340                  {
99                        size_t devPathLength;
100
101                        strcpy(bsdPath, "/dev/");
102                        devPathLength = strlen(bsdPath);
103
341                          if ( CFStringGetCString((const __CFString *)bsdPathAsCFString,
342 <                                                                         bsdPath + devPathLength,
106 <                                                                         MAXPATHLEN - devPathLength,
342 >                                                                         bsdPath, MAXPATHLEN,
343                                                                           kCFStringEncodingASCII) )
344                          {
345 <                                // If we try to do raw reads on the file bsdPath (e.g. /dev/disk5),
346 <                                // we get a lot of extra padding in the data. For some reason,
347 <                                // the device we need has a different name (e.g. /dev/disk5s1)
348 <                                //strcat(bsdPath, "s1");
113 <                                D(bug("CDROM BSD path: %s\n", bsdPath));
345 >                                D(bug("Modem BSD path: %s\n", bsdPath));
346 >
347 >                                // Note that if there are multiple modems, we only get the last
348 >                                PrefsAddString("seriala", bsdPath);
349                          }
350                          else
351 <                                D(bug("Could not get BSD device path for CD\n"));
351 >                                D(bug("Could not get BSD device path for modem\n"));
352  
353                          CFRelease(bsdPathAsCFString);
354                  }
355 <
356 <                PrefsAddString("cdrom", bsdPath);
355 >                else
356 >                        D(puts("Cannot determine bsdPath for modem\n"));
357          }
358  
359 <        IOObjectRelease(nextCD);
360 <        IOObjectRelease(allCDs);
359 >        IOObjectRelease(nextModem);
360 >        IOObjectRelease(allModems);
361 >
362 >
363 >        // Getting a printer device is a bit harder. Creating a fake device
364 >        // that emulates a simple printer (e.g. a HP DeskJet) is one possibility,
365 >        // but for now I will just create a fake, safe, device entry:
366 >
367 >        PrefsAddString("serialb", "/dev/null");
368   }
369  
370  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines