$NetBSD$

--- /dev/null	2006-09-03 09:28:05.000000000 -0700
+++ interface/osx_interface.c	2006-09-03 09:35:39.000000000 -0700
@@ -0,0 +1,267 @@
+/******************************************************************
+ * CopyPolicy: GNU Public License 2 applies
+ * Copyright (C) 1998 Monty xiphmont@mit.edu
+ ******************************************************************/
+
+#include <math.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <paths.h>
+#include <fcntl.h>
+#include <sys/syslimits.h>
+
+#include "osx_interface.h"
+#include "utils.h"
+
+char *osx_bsd_device_for_media(io_object_t media)
+{
+  char buf[PATH_MAX];
+  size_t dev_path_length;
+  CFTypeRef str_bsd_path;
+  char *result;
+
+  str_bsd_path = IORegistryEntryCreateCFProperty(media,
+    CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0);
+
+  if(str_bsd_path == NULL) {
+    return NULL;
+  }
+
+  snprintf(buf, sizeof(buf), "%s%c", _PATH_DEV, 'r' );
+  dev_path_length = strlen(buf);
+
+  if (CFStringGetCString(str_bsd_path,
+        buf + dev_path_length,
+        sizeof(buf) - dev_path_length,
+        kCFStringEncodingASCII)) {
+    result = strdup(buf);
+  } else {
+    result = NULL;
+  }
+  CFRelease(str_bsd_path);
+  return result;
+}
+
+int osx_enumerate_devices(cdrom_drive *d,
+  int (*device_found)(cdrom_drive *, io_object_t, void *),
+  void *data)
+{
+  kern_return_t ret;
+  mach_port_t port;
+  int drives = 0;
+  CFMutableDictionaryRef classes_to_match;
+  kern_return_t kern_result;
+  io_iterator_t media_iterator;
+  io_object_t next_media;
+
+  /* get port for IOKit communication */
+  if ((ret = IOMasterPort(MACH_PORT_NULL, &port)) != KERN_SUCCESS) {
+    cderror(d,"099: IOMasterPort fail\n");
+    return -1;
+  }
+
+  classes_to_match = IOServiceMatching(kIOCDMediaClass);
+  if(classes_to_match == NULL) {
+    cderror(d,"099: IOServiceMatching: NULL\n");
+    return -1;
+  }
+
+  CFDictionarySetValue(classes_to_match, CFSTR(kIOMediaEjectableKey),
+    kCFBooleanTrue);
+
+  kern_result = IOServiceGetMatchingServices(port, classes_to_match,
+    &media_iterator);
+  if (kern_result != KERN_SUCCESS) {
+    cderror(d,"099: IOServiceGetMatchingServices fail\n");
+    return -1;
+  }
+
+  while (1) {
+    drives++;
+    next_media = IOIteratorNext(media_iterator);
+    if (next_media == 0) {
+      break;
+    }
+
+    if (!device_found(d, next_media, data))
+      break;
+    IOObjectRelease(next_media);
+  }
+  if (next_media) IOObjectRelease(next_media);
+  IOObjectRelease(media_iterator);
+
+  return drives;
+}
+
+static int find_first_device(cdrom_drive *d, io_object_t io, void *data)
+{
+  io_object_t *dev = (io_object_t *)data;
+  *dev = io;
+  IOObjectRetain(io);
+  return 0;
+}
+
+io_object_t osx_default_device(cdrom_drive *d)
+{
+  io_object_t io;
+  osx_enumerate_devices(d, find_first_device, (void *)&io);
+  return io;
+}
+
+int osx_read_toc(cdrom_drive *d)
+{
+  kern_return_t ret;
+  char *devname;
+  CFRange range;
+  CFIndex buf_len;
+  int leadout;
+  CFMutableDictionaryRef properties;
+  CFDataRef data;
+  int i;
+
+  devname = strrchr(d->dev, '/');
+
+  if (devname != NULL) {
+    devname++;
+  } else {
+    devname = d->dev;
+  }
+
+  if (*devname == 'r') devname++;
+
+  /* create a CF dictionary containing the TOC */
+  ret = IORegistryEntryCreateCFProperties(d->io, &properties,
+    kCFAllocatorDefault, kNilOptions);
+
+  if( ret != KERN_SUCCESS) {
+    cderror(d,  "099: IORegistryEntryCreateCFProperties fail\n");
+    return -1;
+  }
+
+  /* get the TOC from the dictionary */
+  data = (CFDataRef)CFDictionaryGetValue(properties,
+    CFSTR(kIOCDMediaTOCKey));
+  if(data == NULL) {
+    cderror(d,  "099: CFDictionaryGetValue fail\n");
+    return -1;
+  }
+
+  buf_len = CFDataGetLength(data) + 1;
+  range = CFRangeMake(0, buf_len);
+
+  d->raw_toc = (CDTOC *)malloc(buf_len);
+  if (d->raw_toc == NULL) {
+    cderror(d,  "099: toc malloc fail\n");
+    CFRelease(properties);
+    return -1;
+  }
+  CFDataGetBytes(data, range, (u_char *)d->raw_toc);
+
+  CFRelease(properties);
+
+  d->descriptor_count = CDTOCGetDescriptorCount(d->raw_toc);
+  d->tracks = 0;
+
+  for (i = 0; i < d->descriptor_count; i++) {
+    int track_num = d->raw_toc->descriptors[i].point;
+    CDMSF msf = d->raw_toc->descriptors[i].p;
+    int start_sector = CDConvertMSFToLBA(msf);
+    if (track_num == 0xa2) {
+      leadout = i;
+    }
+    fprintf(stderr,
+            "track_num = %d start sector %d msf: %d,%d,%d\n",
+            track_num, start_sector,
+            msf.minute, msf.second, msf.frame);
+    if (track_num > 99 || track_num < 1) {
+      // e.g.:
+      // track_num = 160 start sector 4350 msf: 1,0,0
+      // track_num = 161 start sector 67350 msf: 15,0,0
+      // track_num = 162 start sector 330645 msf: 73,30,45
+
+      continue;
+      // XXX don't know what happens here. tracks 0xa0, 0xa1, 0xa2 (leadout)
+    }
+    d->disc_toc[d->tracks].bTrack = track_num;
+    d->disc_toc[d->tracks].bFlags = (d->raw_toc->descriptors[i].adr << 4) |
+      d->raw_toc->descriptors[i].control;
+    d->disc_toc[d->tracks].dwStartSector = start_sector;
+    d->tracks++;
+  }
+  d->disc_toc[d->tracks].bTrack = 0xaa;
+  d->disc_toc[d->tracks].bFlags = (d->raw_toc->descriptors[i].adr << 4) |
+    d->raw_toc->descriptors[leadout].control;
+  d->disc_toc[d->tracks].dwStartSector = CDConvertMSFToLBA(
+    d->raw_toc->descriptors[leadout].p);
+
+  return 0;
+}
+
+int osx_open_device_orig(cdrom_drive *d, io_object_t io)
+{
+  if (io == NULL) {
+    d->io = osx_default_device(d);
+  } else {
+    IOObjectRetain(io);
+    d->io = io;
+  }
+  d->dev = osx_bsd_device_for_media(d->io);
+  if (!d->dev) {
+    IOObjectRelease(d->io);
+    return -1;
+  }
+
+  d->fd = open(d->dev, O_RDONLY | O_NONBLOCK, 0);
+  d->enable_cdda = osx_enable_cdda;
+  d->read_toc = osx_read_toc;
+  d->read_audio = osx_read_audio;
+  d->set_speed = osx_set_speed;
+
+  if (d->fd == -1) {
+    free(d->dev);
+    IOObjectRelease(d->io);
+    return -1;
+  }
+
+  osx_read_toc(d);
+
+  d->nsectors = 32;
+  d->opened = 1;
+  return 0;
+}
+
+int osx_open_device(cdrom_drive *d)
+{
+  osx_open_device_orig(d, NULL);
+}
+
+int osx_set_speed(cdrom_drive *d, int speed)
+{
+  return 0;
+}
+
+int osx_enable_cdda(cdrom_drive *d, int enable)
+{
+  return 0;
+}
+
+long osx_read_audio(cdrom_drive *d, void *buf, long begin, long sectors)
+{
+  dk_cd_read_t cd_read;
+
+  // fprintf(stderr, "read_audio %p, %d, %d\n", buf, begin, sectors);
+
+  memset(&cd_read, 0, sizeof(cd_read));
+
+  cd_read.offset = begin * kCDSectorSizeCDDA;
+  cd_read.sectorArea = kCDSectorAreaUser;
+  cd_read.sectorType = kCDSectorTypeCDDA;
+
+  cd_read.buffer = buf;
+  cd_read.bufferLength = kCDSectorSizeCDDA * sectors;
+
+  if( ioctl(d->fd, DKIOCCDREAD, &cd_read) == -1) {
+    return 0;
+  }
+  return cd_read.bufferLength / kCDSectorSizeCDDA;
+}
