$NetBSD: patch-cf,v 1.4 2003/10/20 12:07:23 grant Exp $

--- interface/scan_devices.c.orig	2001-03-26 15:44:01.000000000 +1000
+++ interface/scan_devices.c
@@ -19,6 +19,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[]={
@@ -49,10 +51,18 @@ static char *cdrom_devices[]={
   "/dev/cm206cd",
   "/dev/gscd",
   "/dev/optcd",NULL};
+#elif defined(__FreeBSD__)
+static char *cdrom_devices[] = {
+	"/dev/cd?c",
+	"/dev/acd?c",
+	"/dev/wcd?c",
+	"/dev/mcd?c", NULL};
+#endif
 
 /* Functions here look for a cdrom drive; full init of a drive type
    happens in interface.c */
 
+#if defined(__linux__) || defined(__FreeBSD__)
 cdrom_drive *cdda_find_a_cdrom(int messagedest,char **messages){
   /* Brute force... */
   
@@ -75,10 +85,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. */
@@ -98,6 +110,16 @@ cdrom_drive *cdda_find_a_cdrom(int messa
   }
   return(NULL);
 }
+#endif	/* __linux__ */
+
+#ifdef __NetBSD__
+
+cdrom_drive *cdda_find_a_cdrom(int messagedest,char **messages)
+{
+  errx(1, "cdda_find_a_cdrom: not implemented");
+  /* NOTREACHED */
+}
+#endif	/* __NetBSD__ */
 
 cdrom_drive *cdda_identify(const char *device, int messagedest,char **messages){
   struct stat st;
@@ -117,8 +139,14 @@ cdrom_drive *cdda_identify(const char *d
   }
 #endif
 
+#if defined(__linux__) || defined(__NetBSD__)
   d=cdda_identify_cooked(device,messagedest,messages);
   if(!d)d=cdda_identify_scsi(device,NULL,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);
@@ -146,6 +174,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;
@@ -273,8 +302,59 @@ 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__)
+	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->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
 }
 
+#ifndef __FreeBSD__
 struct  sg_id {
   long    l1; /* target | lun << 8 | channel << 16 | low_ino << 24 */
   long    l2; /* Unique id */
@@ -289,12 +369,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;
@@ -302,6 +388,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);
 }
@@ -390,6 +483,7 @@ matchfail:
   if(dev!=-1)close(dev);
   return(NULL);
 }
+#endif
 
 void strscat(char *a,char *b,int n){
   int i;
@@ -401,6 +495,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,
@@ -430,7 +525,9 @@ static int verify_SG_version(cdrom_drive
   idmessage(messagedest,messages,buffer,"");
   return(major);
 }
+#endif
 
+#if defined(__linux__) || defined(__NetBSD__)
 cdrom_drive *cdda_identify_scsi(const char *generic_device, 
 				const char *ioctl_device, int messagedest,
 				char **messages){
@@ -460,6 +557,7 @@ cdrom_drive *cdda_identify_scsi(const ch
 	       generic_device);
       return(NULL);
     }
+#ifdef __linux__
     if((int)(g_st.st_rdev>>8)!=SCSI_GENERIC_MAJOR){
       if((int)(g_st.st_rdev>>8)!=SCSI_CDROM_MAJOR){
 	idmessage(messagedest,messages,"\t\t%s is not a SCSI device",
@@ -471,6 +569,7 @@ cdrom_drive *cdda_identify_scsi(const ch
 	ioctl_device=temp;
       }
     }
+#endif
   }
   if(ioctl_device){
     if(stat(ioctl_device,&i_st)){
@@ -478,6 +577,7 @@ cdrom_drive *cdda_identify_scsi(const ch
 	       ioctl_device);
       return(NULL);
     }
+#ifdef __linux__
     if((int)(i_st.st_rdev>>8)!=SCSI_CDROM_MAJOR){
       if((int)(i_st.st_rdev>>8)!=SCSI_GENERIC_MAJOR){
 	idmessage(messagedest,messages,"\t\t%s is not a SCSI device",
@@ -489,6 +589,7 @@ cdrom_drive *cdda_identify_scsi(const ch
 	ioctl_device=temp;
       }
     }
+#endif
   }
 
   /* we need to resolve any symlinks for the lookup code to work */
@@ -505,6 +606,7 @@ cdrom_drive *cdda_identify_scsi(const ch
   }
 
   if(!generic_device || !ioctl_device){
+#ifdef __linux__
     if(generic_device){
       ioctl_device=
 	scsi_match(generic_device,scsi_cdrom_prefixes,
@@ -520,6 +622,9 @@ cdrom_drive *cdda_identify_scsi(const ch
       if(!generic_device)	
 	goto cdda_identify_scsi_fail;
     }
+#else
+    goto cdda_identify_scsi_fail;
+#endif
   }
   
   idmessage(messagedest,messages,"\t\tgeneric device: %s",generic_device);
@@ -556,6 +661,7 @@ cdrom_drive *cdda_identify_scsi(const ch
 
     type=(int)(i_st.st_rdev>>8);
 
+#ifdef __linux__
     if(type==SCSI_CDROM_MAJOR){
       if (!S_ISBLK(i_st.st_mode)) {
 	idmessage(messagedest,messages,"\t\tSCSI CDROM device %s not a "
@@ -567,8 +673,10 @@ cdrom_drive *cdda_identify_scsi(const ch
 		"major number",ioctl_device);
       goto cdda_identify_scsi_fail;
     }
+#endif
   }
 
+#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 "
@@ -580,6 +688,7 @@ cdrom_drive *cdda_identify_scsi(const ch
 	      "major number",generic_device);
     goto cdda_identify_scsi_fail;
   }
+#endif
   
 
   d=calloc(1,sizeof(cdrom_drive));
@@ -590,6 +699,7 @@ cdrom_drive *cdda_identify_scsi(const ch
   d->bigendianp=-1; /* We don't know yet... */
   d->nsectors=-1;
 
+#ifdef __linux__
   version=verify_SG_version(d,messagedest,messages);
   switch(version){
   case -1:case 0:case 1:
@@ -599,6 +709,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->sg=malloc(MAX_BIG_BUFF_SIZE);
@@ -617,7 +730,16 @@ cdrom_drive *cdda_identify_scsi(const ch
 
   /* It would seem some TOSHIBA CDROMs gets things wrong */
  
-  if (!strncmp (p + 8, "TOSHIBA", 7) &&
+#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) &&
       p[0] == TYPE_DISK) {
     p[0] = TYPE_ROM;
@@ -653,6 +775,87 @@ cdda_identify_scsi_fail:
   if(g_fd!=-1)close(g_fd);
   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->ioctl_fd = -1;
+	d->bigendianp = -1;
+	d->nsectors = -1;
+	d->lun = d->dev->target_lun;
+	d->interface = GENERIC_SCSI;
+
+	if ((d->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