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

Comparing BasiliskII/src/Unix/sys_unix.cpp (file contents):
Revision 1.28 by cebix, 2005-11-24T17:23:43Z vs.
Revision 1.29 by gbeauche, 2006-05-08T12:15:58Z

# Line 41 | Line 41
41   #include <sys/cdio.h>
42   #endif
43  
44 + #if defined __APPLE__ && defined __MACH__
45 + #include <sys/disk.h>
46 + #if (defined AQUA || defined HAVE_FRAMEWORK_COREFOUNDATION)
47 + #ifndef __MACOSX__
48 + #define __MACOSX__ MAC_OS_X_VERSION_MIN_REQUIRED
49 + #endif
50 + #endif
51 + #endif
52 +
53   #include "main.h"
54   #include "macos_util.h"
55   #include "prefs.h"
# Line 61 | Line 70 | struct file_handle {
70          bool read_only;         // Copy of Sys_open() flag
71          loff_t start_byte;      // Size of file header (if any)
72          loff_t file_size;       // Size of file data (only valid if is_file is true)
73 +        bool is_media_present;          // Flag: media is inserted and available
74  
75   #if defined(__linux__)
76          int cdrom_cap;          // CD-ROM capability flags (only valid if is_cdrom is true)
# Line 72 | Line 82 | struct file_handle {
82   #endif
83   };
84  
85 + // Open file handles
86 + struct open_file_handle {
87 +        file_handle *fh;
88 +        open_file_handle *next;
89 + };
90 + static open_file_handle *open_file_handles = NULL;
91 +
92   // File handle of first floppy drive (for SysMountFirstFloppy())
93   static file_handle *first_floppy = NULL;
94  
95 + // Prototypes
96 + static void cdrom_close(file_handle *fh);
97 + static bool cdrom_open(file_handle *fh, const char *path = NULL);
98 +
99  
100   /*
101   *  Initialization
# Line 82 | Line 103 | static file_handle *first_floppy = NULL;
103  
104   void SysInit(void)
105   {
106 + #if defined __MACOSX__
107 +        extern void DarwinSysInit(void);
108 +        DarwinSysInit();
109 + #endif
110   }
111  
112  
# Line 91 | Line 116 | void SysInit(void)
116  
117   void SysExit(void)
118   {
119 + #if defined __MACOSX__
120 +        extern void DarwinSysExit(void);
121 +        DarwinSysExit();
122 + #endif
123 + }
124 +
125 +
126 + /*
127 + *  Manage open file handles
128 + */
129 +
130 + static void sys_add_file_handle(file_handle *fh)
131 + {
132 +        open_file_handle *p = new open_file_handle;
133 +        p->fh = fh;
134 +        p->next = open_file_handles;
135 +        open_file_handles = p;
136 + }
137 +
138 + static void sys_remove_file_handle(file_handle *fh)
139 + {
140 +        open_file_handle *p = open_file_handles;
141 +        open_file_handle *q = NULL;
142 +
143 +        while (p) {
144 +                if (p->fh == fh) {
145 +                        if (q)
146 +                                q->next = p->next;
147 +                        else
148 +                                open_file_handles = p->next;
149 +                        delete p;
150 +                        break;
151 +                }
152 +                q = p;
153 +                p = p->next;
154 +        }
155 + }
156 +
157 +
158 + /*
159 + *  Account for media that has just arrived
160 + */
161 +
162 + void SysMediaArrived(const char *path, int type)
163 + {
164 +        // Replace the "cdrom" entry (we are polling, it's unique)
165 +        if (type == MEDIA_CD && !PrefsFindBool("nocdrom"))
166 +                PrefsReplaceString("cdrom", path);
167 +
168 +        // Wait for media to be available for reading
169 +        if (open_file_handles) {
170 +                const int MAX_WAIT = 5;
171 +                for (int i = 0; i < MAX_WAIT; i++) {
172 +                        if (access(path, R_OK) == 0)
173 +                                break;
174 +                        switch (errno) {
175 +                        case ENOENT: // Unlikely
176 +                        case EACCES: // MacOS X is mounting the media
177 +                                sleep(1);
178 +                                continue;
179 +                        }
180 +                        printf("WARNING: Cannot access %s (%s)\n", path, strerror(errno));
181 +                        return;
182 +                }
183 +        }
184 +
185 +        for (open_file_handle *p = open_file_handles; p != NULL; p = p->next) {
186 +                file_handle * const fh = p->fh;
187 +
188 +                // Re-open CD-ROM device
189 +                if (fh->is_cdrom && type == MEDIA_CD) {
190 +                        cdrom_close(fh);
191 +                        if (cdrom_open(fh, path)) {
192 +                                fh->is_media_present = true;
193 +                                MountVolume(fh);
194 +                        }
195 +                }
196 +        }
197 + }
198 +
199 +
200 + /*
201 + *  Account for media that has just been removed
202 + */
203 +
204 + void SysMediaRemoved(const char *path, int type)
205 + {
206 +        if ((type & MEDIA_REMOVABLE) != MEDIA_CD)
207 +                return;
208 +
209 +        for (open_file_handle *p = open_file_handles; p != NULL; p = p->next) {
210 +                file_handle * const fh = p->fh;
211 +
212 +                // Mark media as not available
213 +                if (!fh->is_cdrom || !fh->is_media_present)
214 +                        continue;
215 +                if (fh->name && strcmp(fh->name, path) == 0) {
216 +                        fh->is_media_present = false;
217 +                        break;
218 +                }
219 + #if defined __MACOSX__
220 +                if (fh->ioctl_name && strcmp(fh->ioctl_name, path) == 0) {
221 +                        fh->is_media_present = false;
222 +                        break;
223 +                }
224 + #endif
225 +        }
226   }
227  
228  
# Line 211 | Line 343 | void SysAddCDROMPrefs(void)
343                          closedir(cd_dir);
344                  }
345          }
346 < #elif defined(__APPLE__) && defined(__MACH__)
347 <  #if defined(AQUA) || defined(HAVE_FRAMEWORK_COREFOUNDATION)
348 <        extern  void DarwinAddCDROMPrefs(void);
349 <
350 <        DarwinAddCDROMPrefs();
351 <  #else
220 <        // Until I can convince the other guys that my Darwin code is useful,
221 <        // we just do nothing (it is safe to have no cdrom device)
222 <  #endif
346 > #elif defined __MACOSX__
347 >        // There is no predefined path for CD-ROMs on MacOS X. Rather, we
348 >        // define a single fake CD-ROM entry for the emulated MacOS.
349 >        // XXX this means we handle only CD-ROM drive at a time, wherever
350 >        // the disk is, the latest one is used.
351 >        PrefsAddString("cdrom", "/dev/poll/cdrom");
352   #elif defined(__FreeBSD__) || defined(__NetBSD__)
353          PrefsAddString("cdrom", "/dev/cd0c");
354   #endif
# Line 262 | Line 391 | void SysAddSerialPrefs(void)
391  
392  
393   /*
394 + *  Open CD-ROM device and initialize internal data
395 + */
396 +
397 + static bool cdrom_open_1(file_handle *fh)
398 + {
399 + #if defined __MACOSX__
400 +        // In OS X, the device name is OK for sending ioctls to,
401 +        // but not for reading raw CDROM data from.
402 +        // (it seems to have extra data padded in)
403 +        //
404 +        // So, we keep the already opened file handle,
405 +        // and open a slightly different file for CDROM data
406 +        //
407 +        fh->ioctl_fd = fh->fd;
408 +        fh->ioctl_name = fh->name;
409 +        fh->fd = -1;
410 +        fh->name = (char *)malloc(strlen(fh->ioctl_name) + 3);
411 +        if (fh->name) {
412 +                strcpy(fh->name, fh->ioctl_name);
413 +                strcat(fh->name, "s1");
414 +                fh->fd = open(fh->name, O_RDONLY, O_NONBLOCK);
415 +        }
416 +        if (fh->ioctl_fd < 0)
417 +                return false;
418 + #endif
419 +        return true;
420 + }
421 +
422 + bool cdrom_open(file_handle *fh, const char *path)
423 + {
424 +        if (path)
425 +                fh->name = strdup(path);
426 +        fh->fd = open(fh->name, O_RDONLY, O_NONBLOCK);
427 +        fh->start_byte = 0;
428 +        if (!cdrom_open_1(fh))
429 +                return false;
430 +        return fh->fd >= 0;
431 + }
432 +
433 +
434 + /*
435 + *  Close a CD-ROM device
436 + */
437 +
438 + void cdrom_close(file_handle *fh)
439 + {
440 +        if (fh->fd >= 0) {
441 +                close(fh->fd);
442 +                fh->fd = -1;
443 +        }
444 +        if (fh->name) {
445 +                free(fh->name);
446 +                fh->name = NULL;
447 +        }
448 + #if defined __MACOSX__
449 +        if (fh->ioctl_fd >= 0) {
450 +                close(fh->ioctl_fd);
451 +                fh->ioctl_fd = -1;
452 +        }
453 +        if (fh->ioctl_name) {
454 +                free(fh->ioctl_name);
455 +                fh->ioctl_name = NULL;
456 +        }
457 + #endif
458 + }
459 +
460 +
461 + /*
462   *  Check if device is a mounted HFS volume, get mount name
463   */
464  
# Line 310 | Line 507 | void *Sys_open(const char *name, bool re
507   #endif
508          bool is_floppy = strncmp(name, "/dev/fd", 7) == 0;
509  
510 < #if defined(__APPLE__) && defined(__MACH__)
511 <        //
510 >        bool is_polled_media = strncmp(name, "/dev/poll/", 10) == 0;
511 >        if (is_floppy) // Floppy open fails if there's no disk inserted
512 >                is_polled_media = true;
513 >
514 > #if defined __MACOSX__
515          // There is no set filename in /dev which is the cdrom,
516          // so we have to see if it is any of the devices that we found earlier
317        //
318        const char      *cdrom;
319        int                     tmp = 0;
320
321        while ( (cdrom = PrefsFindString("cdrom", tmp) ) != NULL )
517          {
518 <                if ( strcmp(name, cdrom) == 0 )
519 <                {
520 <                        is_cdrom = 1;
521 <                        read_only = 1;
522 <                        break;
518 >                int index = 0;
519 >                const char *str;
520 >                while ((str = PrefsFindString("cdrom", index++)) != NULL) {
521 >                        if (is_polled_media || strcmp(str, name) == 0) {
522 >                                is_cdrom = true;
523 >                                read_only = true;
524 >                                break;
525 >                        }
526                  }
329                ++tmp;
527          }
528   #endif
529  
# Line 351 | Line 548 | void *Sys_open(const char *name, bool re
548          }
549  
550          // Open file/device
551 < #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
551 > #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__MACOSX__)
552          int fd = open(name, (read_only ? O_RDONLY : O_RDWR) | (is_cdrom ? O_NONBLOCK : 0));
553   #else
554          int fd = open(name, read_only ? O_RDONLY : O_RDWR);
# Line 361 | Line 558 | void *Sys_open(const char *name, bool re
558                  read_only = true;
559                  fd = open(name, O_RDONLY);
560          }
561 <        if (fd >= 0 || is_floppy) { // Floppy open fails if there's no disk inserted
561 >        if (fd >= 0 || is_polled_media) {
562                  file_handle *fh = new file_handle;
563                  fh->name = strdup(name);
564                  fh->fd = fd;
# Line 370 | Line 567 | void *Sys_open(const char *name, bool re
567                  fh->start_byte = 0;
568                  fh->is_floppy = is_floppy;
569                  fh->is_cdrom = is_cdrom;
570 +                fh->is_media_present = false;
571 + #if defined __MACOSX__
572 +                fh->ioctl_fd = -1;
573 +                fh->ioctl_name = NULL;
574 + #endif
575                  if (fh->is_file) {
576 +                        fh->is_media_present = true;
577                          // Detect disk image file layout
578                          loff_t size = 0;
579                          size = lseek(fd, 0, SEEK_END);
# Line 381 | Line 584 | void *Sys_open(const char *name, bool re
584                  } else {
585                          struct stat st;
586                          if (fstat(fd, &st) == 0) {
587 +                                fh->is_media_present = true;
588                                  if (S_ISBLK(st.st_mode)) {
589                                          fh->is_cdrom = is_cdrom;
590   #if defined(__linux__)
# Line 408 | Line 612 | void *Sys_open(const char *name, bool re
612                                          fh->is_floppy = ((st.st_rdev >> 16) == 2);
613   #endif
614                                  }
615 < #if defined(__APPLE__) && defined(__MACH__)
616 <
617 <                                // In OS X, the device name is OK for sending ioctls to,
618 <                                // but not for reading raw CDROM data from.
619 <                                // (it seems to have extra data padded in)
620 <                                //
417 <                                // So, we keep the already opened fiole handle,
418 <                                // and open a slightly different file for CDROM data
419 <                                //
420 <                                if ( is_cdrom )
421 <                                {
422 <                                        fh->ioctl_name  = fh->name;
423 <                                        fh->ioctl_fd    = fh->fd;
424 <
425 <                                        fh->name = (char *) malloc(strlen(name) + 2);
426 <                                        if ( fh->name )
427 <                                        {
428 <                                                *fh->name = '\0';
429 <                                                strcat(fh->name, name);
430 <                                                strcat(fh->name, "s1");
431 <                                                fh->fd = open(fh->name, (read_only ? O_RDONLY : O_RDWR));
432 <                                                if ( fh->fd < 0 ) {
433 <                                                        printf("WARNING: Cannot open %s (%s)\n",
434 <                                                                                        fh->name, strerror(errno));
435 <                                                        return NULL;
436 <                                                }
437 <                                        }
615 > #if defined __MACOSX__
616 >                                if (is_cdrom) {
617 >                                        fh->is_cdrom = true;
618 >                                        fh->is_floppy = false;
619 >                                        if (cdrom_open_1(fh))
620 >                                                fh->is_media_present = true;
621                                  }
622   #endif
623                          }
624                  }
625                  if (fh->is_floppy && first_floppy == NULL)
626                          first_floppy = fh;
627 +                sys_add_file_handle(fh);
628                  return fh;
629          } else {
630                  printf("WARNING: Cannot open %s (%s)\n", name, strerror(errno));
# Line 459 | Line 643 | void Sys_close(void *arg)
643          if (!fh)
644                  return;
645  
646 +        sys_remove_file_handle(fh);
647 +
648 +        if (fh->is_cdrom)
649 +                cdrom_close(fh);
650          if (fh->fd >= 0)
651                  close(fh->fd);
652          if (fh->name)
# Line 526 | Line 714 | loff_t SysGetFileSize(void *arg)
714                          return 0;
715                  D(bug(" BLKGETSIZE returns %d blocks\n", blocks));
716                  return (loff_t)blocks * 512;
717 + #elif defined __MACOSX__
718 +                uint32 block_size;
719 +                if (ioctl(fh->ioctl_fd, DKIOCGETBLOCKSIZE, &block_size) < 0)
720 +                        return 0;
721 +                D(bug(" DKIOCGETBLOCKSIZE returns %lu bytes\n", (unsigned long)block_size));
722 +                uint64 block_count;
723 +                if (ioctl(fh->ioctl_fd, DKIOCGETBLOCKCOUNT, &block_count) < 0)
724 +                        return 0;
725 +                D(bug(" DKIOCGETBLOCKCOUNT returns %llu blocks\n", (unsigned long long)block_count));
726 +                return block_count * block_size;
727   #else
728                  return lseek(fh->fd, 0, SEEK_END) - fh->start_byte;
729   #endif
# Line 566 | Line 764 | void SysEject(void *arg)
764                  fh->fd = open(fh->name, O_RDONLY | O_NONBLOCK);
765          }
766   #elif defined(__APPLE__) && defined(__MACH__)
767 <        if ( fh->is_cdrom ) {
570 <
571 <                // Stolen from IOKit/storage/IOMediaBSDClient.h
572 <                #define DKIOCEJECT _IO('d', 21)
573 <
767 >        if (fh->is_cdrom && fh->is_media_present) {
768                  close(fh->fd);
769 <                if ( ioctl(fh->ioctl_fd, DKIOCEJECT) < 0 )
770 <                {
771 <                        printf("ioctl(DKIOCEJECT) failed on file %s: %s\n",
772 <                                                                fh->ioctl_name, strerror(errno));
769 >                fh->fd = -1;
770 >                if (ioctl(fh->ioctl_fd, DKIOCEJECT) < 0) {
771 >                        D(bug(" DKIOCEJECT failed on file %s: %s\n",
772 >                                   fh->ioctl_name, strerror(errno)));
773  
774 <                        // If we are running OSX, the device may be is busy
775 <                        // due to the Finder having the disk mounted and open,
582 <                        // so we have to use another method.
583 <
584 <                        // The only problem is that this takes about 5 seconds:
585 <
586 <                        char    *cmd = (char *) malloc(30+sizeof(fh->name));
587 <
588 <                        if ( ! cmd )
589 <                                return;
774 >                        // If we are running MacOS X, the device may be in busy
775 >                        // state because the Finder has mounted the disk
776                          close(fh->ioctl_fd);
777 <                        sprintf(cmd, "diskutil eject %s 2>&1 >/dev/null", fh->name);
777 >                        fh->ioctl_fd = -1;
778 >
779 >                        // Try to use "diskutil eject" but it can take up to 5
780 >                        // seconds to complete
781 >                        static const char eject_cmd[] = "/usr/sbin/diskutil eject %s 2>&1 >/dev/null";
782 >                        char *cmd = (char *)alloca(strlen(eject_cmd) + strlen(fh->ioctl_name) + 1);
783 >                        sprintf(cmd, eject_cmd, fh->ioctl_name);
784                          system(cmd);
785                  }
786 +                fh->is_media_present = false;
787          }
788   #endif
789   }
# Line 703 | Line 896 | bool SysIsDiskInserted(void *arg)
896          } else if (fh->is_cdrom) {
897                  struct ioc_toc_header header;
898                  return ioctl(fh->fd, CDIOREADTOCHEADER, &header) == 0;
899 + #elif defined __MACOSX__
900 +        } else if (fh->is_cdrom || fh->is_floppy) {
901 +                return fh->is_media_present;
902   #endif
903  
904          } else
# Line 801 | Line 997 | bool SysCDReadTOC(void *arg, uint8 *toc)
997                  *toc++ = toc_size >> 8;
998                  *toc++ = toc_size & 0xff;
999                  return true;
1000 < #elif defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_2) && defined(HAVE_FRAMEWORK_COREFOUNDATION)
1001 <                extern  bool    DarwinCDReadTOC(char *name, uint8 *toc);
1002 <
1003 <                return  DarwinCDReadTOC(fh->name, toc);
1000 > #elif defined __MACOSX__ && defined MAC_OS_X_VERSION_10_2
1001 >                if (fh->is_media_present) {
1002 >                        extern bool DarwinCDReadTOC(char *name, uint8 *toc);
1003 >                        return DarwinCDReadTOC(fh->name, toc);
1004 >                }
1005 >                return false;
1006   #elif defined(__FreeBSD__)
1007                  uint8 *p = toc + 2;
1008  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines