$NetBSD: patch-cf,v 1.13 2013/12/12 16:41:32 jperkin Exp $

--- interface/scan_devices.c.orig	2008-08-26 09:55:22.000000000 +0000
+++ interface/scan_devices.c
@@ -1,6 +1,8 @@
 /******************************************************************
  * CopyPolicy: GNU Lesser General Public License 2.1 applies
  * Copyright (C) 1998-2008 Monty xiphmont@mit.edu
+ * FreeBSD porting (c) 2003
+ *	Simon 'corecode' Schubert <corecode@corecode.ath.cx>
  * 
  * Autoscan for or verify presence of a cdrom device
  * 
@@ -22,6 +24,8 @@
 #include "common_interface.h"
 #include "utils.h"
 
+#ifdef __linux__
+
 #define MAX_DEV_LEN 20 /* Safe because strings only come from below */
 /* must be absolute paths! */
 static char *scsi_cdrom_prefixes[]={
@@ -52,11 +56,33 @@ static char *cdrom_devices[]={
   "/dev/cm206cd",
   "/dev/gscd",
   "/dev/optcd",NULL};
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+static char *cdrom_devices[] = {
+	"/dev/cd?c",
+	"/dev/acd?c",
+	"/dev/wcd?c",
+	"/dev/mcd?c", NULL};
+#elif defined(__NetBSD__)
+static char *cdrom_devices[] = {
+	"/dev/rcd?c",
+	"/dev/rcd?d",
+	"/dev/cd?c",
+	"/dev/cd?d", NULL};
+#elif defined(__sun)
+static char *cdrom_devices[] = {
+	"/dev/dsk/c?t?d?s2", NULL};
+#endif
 
 /* Functions here look for a cdrom drive; full init of a drive type
    happens in interface.c */
 
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__sun)
 cdrom_drive *cdda_find_a_cdrom(int messagedest,char **messages){
+#if defined(__APPLE__) && defined(__MACH__)
+  cdrom_drive *d = calloc(1, sizeof(cdrom_drive));
+  d->interface = OSX_IOKIT;
+  return d;
+#else
   /* Brute force... */
   
   int i=0;
@@ -78,10 +104,12 @@ cdrom_drive *cdda_find_a_cdrom(int messa
 	if((d=cdda_identify(buffer,messagedest,messages)))
 	  return(d);
 	idmessage(messagedest,messages,"",NULL);
+#ifdef __linux__
 	buffer[pos-(cdrom_devices[i])]=j+97;
 	if((d=cdda_identify(buffer,messagedest,messages)))
 	  return(d);
 	idmessage(messagedest,messages,"",NULL);
+#endif
       }
     }else{
       /* Name.  Go for it. */
@@ -93,11 +121,13 @@ cdrom_drive *cdda_find_a_cdrom(int messa
     i++;
   }
   idmessage(messagedest,messages,
-	    "\n\nNo cdrom drives accessible to %s found.\n",
-	    cuserid(NULL));
+	    "\n\nNo cdrom drives found.\n", NULL);
+#endif
   return(NULL);
 }
+#endif	/* __linux__ */
 
+#if !(defined(__APPLE__) && defined(__MACH__))
 cdrom_drive *cdda_identify(const char *device, int messagedest,char **messages){
   struct stat st;
   cdrom_drive *d=NULL;  
@@ -119,8 +149,14 @@ cdrom_drive *cdda_identify(const char *d
 
   /* an IDE device may have scsi-ide support, SG_IO support and cooked
      support.  Prefer the SCSI variants, they give the most control */
+#if defined(__linux__) || defined(__NetBSD__) || defined(__DragonFly__)
   d=cdda_identify_scsi(NULL,device,messagedest,messages);
   if(!d)d=cdda_identify_cooked(device,messagedest,messages);
+#elif defined(__FreeBSD__)
+  d = cdda_identify_scsi(device, NULL, messagedest, messages);
+  if (d == NULL)
+	d = cdda_identify_cooked(device, messagedest, messages);
+#endif
   
 #ifdef CDDA_TEST
   if(!d)d=cdda_identify_test(device,messagedest,messages);
@@ -148,6 +184,7 @@ char *test_resolve_symlink(const char *f
 cdrom_drive *cdda_identify_cooked(const char *dev, int messagedest,
 				  char **messages){
 
+#ifdef __linux__
   cdrom_drive *d=NULL;
   struct stat st;
   int fd=-1, i;
@@ -272,8 +309,60 @@ cdrom_drive *cdda_identify_cooked(const
   }
   idmessage(messagedest,messages,"\t\tCDROM sensed: %s\n",description);
   return(d);
+#elif defined(__NetBSD__)
+  /* no kernel support for CD-DA */
+  return NULL;
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+	cdrom_drive *d;
+	struct stat st;
+
+	if (stat(dev, &st)) {
+		idperror(messagedest, messages, "\t\tCould not stat %s", dev);
+		return NULL;
+	}
+
+	if (!S_ISCHR(st.st_mode)) {
+		idmessage(messagedest, messages, "\t\t%s is no block device", dev);
+		return NULL;
+	}
+	
+	if ((d = calloc(1, sizeof(*d))) == NULL) {
+		idperror(messagedest, messages, "\t\tCould not allocate memory", NULL);
+		return NULL;
+	}
+	d->ioctl_fd = -1;
+
+	if ((d->ioctl_fd = open(dev, O_RDONLY)) == -1) {
+		idperror(messagedest, messages, "\t\tCould not open %s", dev);
+		goto cdda_identify_cooked_fail;
+	}
+
+	if (ioctl_ping_cdrom(d->ioctl_fd)) {
+		idmessage(messagedest, messages, "\t\tDevice %s is not a CDROM", dev);
+		goto cdda_identify_cooked_fail;
+	}
+
+	d->cdda_device_name = copystring(dev);
+	d->drive_model = copystring("Generic cooked ioctl CDROM");
+	d->interface = COOKED_IOCTL;
+	d->bigendianp = -1;
+	d->nsectors = -1;
+
+	idmessage(messagedest, messages, "\t\tCDROM sensed: %s\n", d->drive_model);
+
+	return d;
+
+cdda_identify_cooked_fail:
+	if (d != NULL) {
+		if (d->ioctl_fd != -1)
+			close(d->ioctl_fd);
+		free(d);
+	}
+	return NULL;
+#endif
 }
 
+#if !defined(__FreeBSD__) || defined(__DragonFly__)
 struct  sg_id {
   long    l1; /* target | lun << 8 | channel << 16 | low_ino << 24 */
   long    l2; /* Unique id */
@@ -288,12 +377,18 @@ typedef struct scsiid{
 /* Even *this* isn't as simple as it bloody well should be :-P */
 /* SG has an easy interface, but SCSI overall does not */
 static int get_scsi_id(int fd, scsiid *id){
+#ifdef __linux__
   struct sg_id argid;
+#endif
+#ifdef __NetBSD__
+  struct scsi_addr argid;
+#endif
   int busarg;
 
   /* get the host/id/lun */
 
   if(fd==-1)return(-1);
+#ifdef __linux__
   if(ioctl(fd,SCSI_IOCTL_GET_IDLUN,&argid))return(-1);
   id->bus=argid.l2; /* for now */
   id->id=argid.l1&0xff;
@@ -301,6 +396,13 @@ static int get_scsi_id(int fd, scsiid *i
 
   if(ioctl(fd,SCSI_IOCTL_GET_BUS_NUMBER,&busarg)==0)
     id->bus=busarg;
+#endif
+#ifdef __NetBSD__
+  if(ioctl(fd,SCIOCIDENTIFY,&argid))return(-1);
+  id->bus=argid.addr.scsi.scbus;
+  id->id=argid.addr.scsi.target;
+  id->lun=argid.addr.scsi.lun;
+#endif
   
   return(0);
 }
@@ -400,6 +502,7 @@ matchfail:
   if(dev!=-1)close(dev);
   return(NULL);
 }
+#endif
 
 void strscat(char *a,char *b,int n){
   int i;
@@ -411,6 +514,7 @@ void strscat(char *a,char *b,int n){
   strcat(a," ");
 }
 
+#ifdef __linux__
 /* At this point, we're going to punt compatability before SG2, and
    allow only SG2 and SG3 */
 static int verify_SG_version(cdrom_drive *d,int messagedest,
@@ -488,7 +592,9 @@ int check_sgio(const char *device, int m
   close(fd);
   return 0;
 }
+#endif
 
+#if defined(__linux__) || defined(__NetBSD__) || defined(__DragonFly__)
 /* scanning is always done by specifying a device name in
    specialized_device; generic_device is only filled when the generic device
    force option is used, and in that case, use of SG (not SGIO) should indeed be
@@ -527,11 +633,13 @@ cdrom_drive *cdda_identify_scsi(const ch
       return(NULL);
     }
 
+#ifdef __linux__
     if((int)(g_st.st_rdev>>8)!=SCSI_GENERIC_MAJOR){
       idmessage(messagedest,messages,"\t\t%s is not a generic SCSI device",
 		generic_device);
       return(NULL);
     }
+#endif
   }
   
   if(specialized_device){ 
@@ -553,6 +661,7 @@ cdrom_drive *cdda_identify_scsi(const ch
     if(specialized_device==NULL)goto cdda_identify_scsi_fail;
   }
 
+#ifdef __linux__
   /* sgio is always preferred if it's there, unless user has forced the generic scsi device name */
   if(use_sgio){
     if(check_sgio(specialized_device,messagedest,messages)){
@@ -562,18 +671,24 @@ cdrom_drive *cdda_identify_scsi(const ch
       use_sgio=0;
     }
   }
+#else
+  use_sgio=0;
+#endif
   
   if(!use_sgio){
 
     /* was a generic device passed in as the specialized device name? */
     if(specialized_device){ 
+#ifdef __linux__
       if((int)(i_st.st_rdev>>8)==SCSI_GENERIC_MAJOR){
 	char *temp=(char *)generic_device;
 	generic_device=specialized_device;
 	specialized_device=temp;
       }
+#endif
       
       if(!generic_device || !specialized_device){
+#ifdef __linux__
 	if(generic_device){
 	  specialized_device=
 	    scsi_match(generic_device,scsi_cdrom_prefixes,
@@ -589,6 +704,12 @@ cdrom_drive *cdda_identify_scsi(const ch
 	  if(!generic_device)	
 	    goto cdda_identify_scsi_fail;
 	}
+#else
+    if(!generic_device)
+      generic_device = strdup(specialized_device);
+    else
+      specialized_device = strdup(generic_device);
+#endif
       }
     }
     
@@ -639,6 +760,7 @@ cdrom_drive *cdda_identify_scsi(const ch
     type=(int)(i_st.st_rdev>>8);
 
     if(!use_sgio){
+#ifdef __linux__
       if(type==SCSI_CDROM_MAJOR){
 	if (!S_ISBLK(i_st.st_mode)) {
 	  idmessage(messagedest,messages,"\t\tSCSI CDROM device %s not a "
@@ -650,10 +772,12 @@ cdrom_drive *cdda_identify_scsi(const ch
 		  "major number",specialized_device);
 	goto cdda_identify_scsi_fail;
       }
+#endif
     }
   }
   
   if(g_fd != -1){
+#ifdef __linux__
     if((int)(g_st.st_rdev>>8)==SCSI_GENERIC_MAJOR){
       if (!S_ISCHR(g_st.st_mode)) {
 	idmessage(messagedest,messages,"\t\tGeneric SCSI device %s not a "
@@ -665,6 +789,7 @@ cdrom_drive *cdda_identify_scsi(const ch
 		"major number",generic_device);
       goto cdda_identify_scsi_fail;
     }
+#endif
   }
 
   d=calloc(1,sizeof(cdrom_drive));
@@ -685,6 +810,7 @@ cdrom_drive *cdda_identify_scsi(const ch
     d->private->sg_buffer=(unsigned char *)(d->private->sg_hd=malloc(MAX_BIG_BUFF_SIZE));
     g_fd=d->cdda_fd=dup(d->ioctl_fd);
   }else{
+#ifdef __linux__
     version=verify_SG_version(d,messagedest,messages);
     switch(version){
     case -1:case 0:case 1:
@@ -694,6 +820,9 @@ cdrom_drive *cdda_identify_scsi(const ch
       d->interface=GENERIC_SCSI;
       break;
     }
+#else
+  d->interface=GENERIC_SCSI;
+#endif
 
     /* malloc our big buffer for scsi commands */
     d->private->sg_hd=malloc(MAX_BIG_BUFF_SIZE);
@@ -740,6 +869,15 @@ cdrom_drive *cdda_identify_scsi(const ch
   }
   
   /* It would seem some TOSHIBA CDROMs gets things wrong */
+#ifndef TYPE_DISK
+#define TYPE_DISK	0	/* direct */
+#endif
+#ifndef TYPE_WORM
+#define TYPE_WORM	4	/* write once, read many */
+#endif
+#ifndef TYPE_ROM
+#define TYPE_ROM	5	/* CD-ROM */
+#endif
   if (p &&
       !strncmp (p + 8, "TOSHIBA", 7) &&
       !strncmp (p + 16, "CD-ROM", 6) &&
@@ -780,6 +918,88 @@ cdda_identify_scsi_fail:
   }
   return(NULL);
 }
+#elif defined(__FreeBSD__)
+cdrom_drive *cdda_identify_scsi(const char *device,
+    const char *dummy,
+    int messagedest,
+    char **messages)
+{
+	char *devname;
+	cdrom_drive *d = NULL;
+
+	if (device == NULL) {
+		idperror(messagedest, messages, "\t\tNo device specified", NULL);
+		return NULL;
+	}
+
+	if ((devname = test_resolve_symlink(device, messagedest, messages)) == NULL)
+		return NULL;
+
+	if ((d = calloc(1, sizeof(*d))) == NULL) {
+		idperror(messagedest, messages, "\t\tCould not allocate memory", NULL);
+		free(devname);
+		return NULL;
+	}
+
+	if ((d->dev = cam_open_device(devname, O_RDWR)) == NULL) {
+		idperror(messagedest, messages, "\t\tCould not open SCSI device: %s", cam_errbuf);
+		goto cdda_identify_scsi_fail;
+	}
+
+	if ((d->ccb = cam_getccb(d->dev)) == NULL) {
+		idperror(messagedest, messages, "\t\tCould not allocate ccb", NULL);
+		goto cdda_identify_scsi_fail;
+	}
+
+	if (strncmp(d->dev->inq_data.vendor, "TOSHIBA", 7) == 0 &&
+	    strncmp(d->dev->inq_data.product, "CD_ROM", 6) == 0 &&
+	    SID_TYPE(&d->dev->inq_data) == T_DIRECT) {
+		d->dev->inq_data.device = T_CDROM;
+		d->dev->inq_data.dev_qual2 |= 0x80;
+	}
+
+	if (SID_TYPE(&d->dev->inq_data) != T_CDROM &&
+	    SID_TYPE(&d->dev->inq_data) != T_WORM) {
+		idmessage(messagedest, messages,
+		    "\t\tDevice is neither a CDROM nor a WORM device\n", NULL);
+		goto cdda_identify_scsi_fail;
+	}
+
+	d->cdda_device_name = copystring(devname);
+	d->ioctl_fd = -1;
+	d->bigendianp = -1;
+	d->nsectors = -1;
+	d->lun = d->dev->target_lun;
+	d->interface = GENERIC_SCSI;
+
+	if ((d->private->sg_buffer = malloc(MAX_BIG_BUFF_SIZE)) == NULL) {
+		idperror(messagedest, messages, "Could not allocate buffer memory", NULL);
+		goto cdda_identify_scsi_fail;
+	}
+
+	if ((d->drive_model = calloc(36,1)) == NULL) {
+	}
+
+	strscat(d->drive_model, d->dev->inq_data.vendor, SID_VENDOR_SIZE);
+	strscat(d->drive_model, d->dev->inq_data.product, SID_PRODUCT_SIZE);
+	strscat(d->drive_model, d->dev->inq_data.revision, SID_REVISION_SIZE);
+
+	idmessage(messagedest, messages, "\nCDROM model sensed: %s", d->drive_model);
+
+	return d;
+
+cdda_identify_scsi_fail:
+	free(devname);
+	if (d) {
+		if (d->ccb)
+			cam_freeccb(d->ccb);
+		if (d->dev)
+			cam_close_device(d->dev);
+		free(d);
+	}
+	return NULL;
+}
+#endif
 
 #ifdef CDDA_TEST
 
@@ -829,3 +1049,4 @@ cdrom_drive *cdda_identify_test(const ch
 }
 
 #endif
+#endif  /* __APPLE__ && __MACH__ */
