$NetBSD: patch-ce,v 1.4 2006/11/05 13:45:37 wiz Exp $

--- interface/cooked_interface.c.orig	Thu Apr 20 00:41:04 2000
+++ interface/cooked_interface.c
@@ -10,9 +10,11 @@
 #include "common_interface.h"
 #include "utils.h"
 
+#if !defined(__FreeBSD__) && !defined(__DragonFly__)
 static int cooked_readtoc (cdrom_drive *d){
   int i;
   int tracks;
+#ifdef __linux__
   struct cdrom_tochdr hdr;
   struct cdrom_tocentry entry;
 
@@ -52,6 +54,45 @@ static int cooked_readtoc (cdrom_drive *
   d->disc_toc[i].dwStartSector = entry.cdte_addr.lba;
 
   tracks=hdr.cdth_trk1+1;
+#endif
+
+#ifdef __NetBSD__
+  struct ioc_read_toc_entry hdr;
+  struct cd_toc_entry entries[MAXTRK + 1];	/* + 1 for leadout */
+
+  hdr.address_format = CD_LBA_FORMAT;
+  hdr.starting_track = 1;
+  hdr.data_len = sizeof entries;
+  hdr.data = entries;
+  memset(entries, 0, sizeof entries);
+
+  /* get all TOC entries at once */
+#ifndef CDIOREADTOCENTRIES
+#define CDIOREADTOCENTRIES CDIOREADTOCENTRYS
+#endif
+  if(ioctl(d->ioctl_fd, CDIOREADTOCENTRIES, &hdr))
+    switch(errno){
+    case EPERM:
+      cderror(d,"102: Permision denied on cdrom (ioctl) device\n");
+      return(-102);
+    default:
+      cderror(d,"004: Unable to read table of contents header\n");
+      return(-4);
+    }
+
+  for(i = 0; i < MAXTRK + 1; i++) {
+    d->disc_toc[i].bFlags = (entries[i].addr_type << 4) | (entries[i].control & 0x0f);
+    d->disc_toc[i].bTrack = entries[i].track;
+    d->disc_toc[i].dwStartSector = entries[i].addr.lba;
+    if (entries[i].track == 0) {
+      cderror(d,"005: Unable to read table of contents entry\n");
+      return(-5);
+    }
+    if (entries[i].track >= 100)
+      break;	/* leadout */
+  }
+  tracks = i;
+#endif
   d->cd_extra=FixupTOC(d,tracks);
   return(--tracks);  /* without lead-out */
 }
@@ -60,10 +101,15 @@ static int cooked_readtoc (cdrom_drive *
 /* Set operating speed */
 static int cooked_setspeed(cdrom_drive *d, int speed)
 {
+#ifdef __linux__
   if(d->ioctl_fd!=-1)
     return ioctl(d->ioctl_fd, CDROM_SELECT_SPEED, speed);
   else
     return 0;
+#endif
+#ifdef __NetBSD__
+  errx(1, "cooked_setspeed: not implemented");
+#endif
 }
 
 
@@ -72,6 +118,7 @@ static int cooked_setspeed(cdrom_drive *
  */
 
 static long cooked_read (cdrom_drive *d, void *p, long begin, long sectors){
+#ifdef __linux__
   int retry_count,err;
   struct cdrom_read_audio arg;
   char *buffer=(char *)p;
@@ -127,7 +174,147 @@ static long cooked_read (cdrom_drive *d,
   } while (err);
   
   return(sectors);
+#endif
+#ifdef __NetBSD__
+  errx(1, "cooked_read: not implemented");
+#endif
 }
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+static int
+cooked_readtoc(cdrom_drive *d)
+{
+	int i;
+	struct ioc_toc_header hdr;
+	struct ioc_read_toc_single_entry entry;
+
+	if (ioctl(d->ioctl_fd, CDIOREADTOCHEADER, &hdr) == -1) {
+		int ret;
+
+		if (errno == EPERM) {
+			ret = -102;
+			cderror(d, "102: ");
+		} else {
+			ret = -4;
+			cderror(d, "004: Unable to read table of contents header: ");
+		}
+		cderror(d, strerror(errno));
+		cderror(d, "\n");
+		return ret;
+	}
+
+	entry.address_format = CD_LBA_FORMAT;
+	for (i = hdr.starting_track; i <= hdr.ending_track; ++i) {
+		entry.track = i;
+		
+		if (ioctl(d->ioctl_fd, CDIOREADTOCENTRY, &entry) == -1) {
+			cderror(d, "005: Unable to read table of contents entry\n");
+			return -5;
+		}
+
+		d->disc_toc[i - hdr.starting_track].bFlags = entry.entry.control;
+		d->disc_toc[i - hdr.starting_track].bTrack = entry.entry.track;
+		d->disc_toc[i - hdr.starting_track].dwStartSector = be32_to_cpu(entry.entry.addr.lba);
+	}
+	
+	entry.track = 0xaa;	/* leadout */
+
+	if (ioctl(d->ioctl_fd, CDIOREADTOCENTRY, &entry) == -1) {
+		cderror(d, "005: Unable to read table of contents entry\n");
+		return -5;
+	}
+
+	d->disc_toc[i - hdr.starting_track].bFlags = entry.entry.control;
+	d->disc_toc[i - hdr.starting_track].bTrack = entry.entry.track;
+	d->disc_toc[i - hdr.starting_track].dwStartSector = be32_to_cpu(entry.entry.addr.lba);
+	
+	d->cd_extra = FixupTOC(d, hdr.ending_track - hdr.starting_track + 2);	/* with TOC */
+
+	return hdr.ending_track - hdr.starting_track + 1;
+}
+
+static int
+cooked_setspeed(cdrom_drive *d, int speed)
+{
+#ifdef CDRIOCREADSPEED
+	speed *= 177;
+	return ioctl(d->ioctl_fd, CDRIOCREADSPEED, &speed);
+#else
+	return -1;
+#endif
+}
+
+
+static long
+cooked_read(cdrom_drive *d, void *p, long begin, long sectors)
+{
+	int retry_count = 0;
+/* CDIOCREADAUDIO has been removed in FreeBSD 5.1-CURRENT */
+#if __FreeBSD_version >= 501106
+	int bsize = CD_FRAMESIZE_RAW;
+#else
+	struct ioc_read_audio arg;
+
+	if (sectors > d->nsectors)
+		sectors = d->nsectors;
+
+	arg.address_format = CD_LBA_FORMAT;
+	arg.address.lba = begin;
+	arg.buffer = p;
+#endif
+
+#if __FreeBSD_version >= 501106
+	if (ioctl(d->ioctl_fd, CDRIOCSETBLOCKSIZE, &bsize) == -1) {
+		return -7;
+	}
+#endif
+	for (;;) {
+#if  __FreeBSD_version >= 501106
+		if (pread(d->ioctl_fd, p, sectors*bsize, begin*bsize) != sectors*bsize) {
+#else
+		arg.nframes = sectors;
+		if (ioctl(d->ioctl_fd, CDIOCREADAUDIO, &arg) == -1) {
+#endif
+			if (!d->error_retry)
+				return -7;
+
+			switch (errno) {
+			case ENOMEM:
+				if (sectors == 1) {
+					cderror(d, "300: Kernel memory error\n");
+					return -300;
+				}
+				/* FALLTHROUGH */
+			default:
+				if (sectors == 1) {
+					if (retry_count > MAX_RETRIES - 1) {
+						char b[256];
+						snprintf(b, sizeof(b),
+						    "010: Unable to access sector %ld; "
+						    "skipping...\n", begin);
+						cderror(d, b);
+						return -10;
+					}
+					break;
+				}
+			}
+
+			if (retry_count > 4 && sectors > 1)
+				sectors = sectors * 3 / 4;
+
+			++retry_count;
+
+			if (retry_count > MAX_RETRIES) {
+				cderror(d, "007: Unknown, unrecoverable error reading data\n");
+				return -7;
+			}
+		} else
+			break;
+	}
+
+	return sectors;
+}
+#endif
+
 
 /* hook */
 static int Dummy (cdrom_drive *d,int Switch){
@@ -191,8 +378,11 @@ static void check_exceptions(cdrom_drive
 
 /* set function pointers to use the ioctl routines */
 int cooked_init_drive (cdrom_drive *d){
+#ifdef __NetBSD__
+  errx(1, "cooked_init_drive: not implemented");
+#else
   int ret;
-
+#ifdef __linux__
   switch(d->drive_type){
   case MATSUSHITA_CDROM_MAJOR:	/* sbpcd 1 */
   case MATSUSHITA_CDROM2_MAJOR:	/* sbpcd 2 */
@@ -243,6 +433,9 @@ int cooked_init_drive (cdrom_drive *d){
   default:
     d->nsectors=40; 
   }
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+  d->nsectors = 26;	/* FreeBSD only supports 64K I/O transfer size */
+#endif
   d->enable_cdda = Dummy;
   d->read_audio = cooked_read;
   d->set_speed = cooked_setspeed;
@@ -255,5 +448,6 @@ int cooked_init_drive (cdrom_drive *d){
   if((ret=verify_read_command(d)))return(ret);
   d->error_retry=1;
   return(0);
+#endif
 }
 
