patch-1.3.36 linux/drivers/cdrom/gscd.c

Next file: linux/drivers/cdrom/mcd.c
Previous file: linux/drivers/cdrom/cm206.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.35/linux/drivers/cdrom/gscd.c linux/drivers/cdrom/gscd.c
@@ -0,0 +1,1126 @@
+#define GSCD_VERSION "0.4a Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>"
+
+/*
+	linux/drivers/block/gscd.c - GoldStar R420 CDROM driver
+
+        Copyright (C) 1995  Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>
+        based upon pre-works by   Eberhard Moenkeberg <emoenke@gwdg.de>
+        
+
+        For all kind of other information about the GoldStar CDROM
+        and this Linux device driver I installed a WWW-URL:
+        http://linux.rz.fh-hannover.de/~raupach        
+
+
+             If you are the editor of a Linux CD, you should
+             enable gscd.c within your boot floppy kernel and
+             send me one of your CDs for free.
+
+
+        --------------------------------------------------------------------
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2, or (at your option)
+	any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/* These settings are for various debug-level. Leave they untouched ... */ 
+#define  NO_GSCD_DEBUG 
+#define  NO_IOCTL_DEBUG
+#define  NO_MODULE_DEBUG
+#define  NO_FUTURE_WORK
+/*------------------------*/
+
+#include <linux/config.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/malloc.h>
+#ifndef CONFIG_MODVERSIONS
+char kernel_version[] = UTS_RELEASE;
+#endif
+#endif MODULE
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/cdrom.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <linux/string.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
+#define MAJOR_NR GOLDSTAR_CDROM_MAJOR
+#include <linux/blk.h>
+#define gscd_port gscd /* for compatible parameter passing with "insmod" */
+#include <linux/gscd.h>
+
+
+static int gscdPresent            = 0;
+
+static unsigned char gscd_buf[2048];    /* buffer for block size conversion */
+static int   gscd_bn              = -1;
+static short gscd_port            = GSCD_BASE_ADDR;
+
+/* Kommt spaeter vielleicht noch mal dran ...
+ *    static struct wait_queue *gscd_waitq = NULL;
+ */ 
+
+static void gscd_transfer         (void);
+static void gscd_read_cmd         (void);
+static void gscd_hsg2msf          (long hsg, struct msf *msf);
+static void gscd_bin2bcd          (unsigned char *p);
+
+/* Schnittstellen zum Kern/FS */
+
+static void do_gscd_request       (void);
+static int  gscd_ioctl            (struct inode *, struct file *, unsigned int, unsigned long);
+static int  gscd_open             (struct inode *, struct file *);
+static void gscd_release          (struct inode *, struct file *);
+static int  check_gscd_med_chg    (kdev_t);
+
+/*      GoldStar Funktionen    */
+
+static void cc_Reset             (void);
+static int  wait_drv_ready       (void);
+static int  find_drives          (void);
+static void cmd_out              (int, char *, char *, int);
+static void cmd_status           (void);
+static void cc_Ident             (char *);
+static void cc_SetSpeed          (void);
+static void init_cd_drive        (int);
+
+static int  get_status           (void);
+static void clear_Audio          (void);
+static void cc_invalidate        (void);
+
+/* some things for the next version */
+#ifdef FUTURE_WORK
+static void update_state          (void);
+static long gscd_msf2hsg          (struct msf *mp);
+static int  gscd_bcd2bin          (unsigned char bcd);
+#endif
+
+/*    common GoldStar Initialization    */
+
+static int my_gscd_init (void);
+
+
+/*      lo-level cmd-Funktionen    */
+
+static void cmd_info_in          ( char *, int );
+static void cmd_end              ( void );
+static void cmd_read_b           ( char *, int, int );
+static void cmd_read_w           ( char *, int, int );
+static int  cmd_unit_alive       ( void );
+static void cmd_write_cmd        ( char * );
+
+
+/*      GoldStar Variablen     */
+
+static int  curr_drv_state;
+static int  drv_states[]       = {0,0,0,0,0,0,0,0};
+static int  drv_mode;
+static int  disk_state;
+static int  speed;
+static int  ndrives;
+
+static unsigned char drv_num_read;
+static unsigned char f_dsk_valid;
+static unsigned char current_drive;
+static unsigned char f_drv_ok;
+
+
+static char f_AudioPlay;
+static char f_AudioPause;
+static int  AudioStart_m;
+static int  AudioStart_f;
+static int  AudioEnd_m;
+static int  AudioEnd_f;
+ 
+
+static struct file_operations gscd_fops = {
+	NULL,			/* lseek - default */
+	block_read,		/* read - general block-dev read */
+	block_write,		/* write - general block-dev write */
+	NULL,			/* readdir - bad */
+	NULL,			/* select */
+	gscd_ioctl,		/* ioctl */
+	NULL,			/* mmap */
+	gscd_open,		/* open */
+	gscd_release,		/* release */
+	NULL,                   /* fsync */
+	NULL,                   /* fasync*/
+	check_gscd_med_chg,     /* media change */
+	NULL                    /* revalidate */
+};
+
+/* 
+ * Checking if the media has been changed
+ * (not yet implemented)
+ */
+static int check_gscd_med_chg (kdev_t full_dev)
+{
+   int target;
+
+
+   target = MINOR(full_dev);
+
+   if (target > 0) 
+   {
+      printk("GSCD: GoldStar CD-ROM request error: invalid device.\n");
+      return 0;
+   }
+
+   #ifdef GSCD_DEBUG
+   printk ("gscd: check_med_change\n");
+   #endif
+ 
+  return 0;
+}
+
+
+void gscd_setup (char *str, int *ints)
+{
+  if (ints[0] > 0) 
+  {
+     gscd_port = ints[1];
+  }
+}
+
+
+static int gscd_ioctl (struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
+{
+unsigned char to_do[10];
+unsigned char dummy;
+
+                             
+    switch (cmd)
+    {
+       case CDROMSTART:     /* Spin up the drive */
+		/* Don't think we can do this.  Even if we could,
+ 		 * I think the drive times out and stops after a while
+		 * anyway.  For now, ignore it.
+		 */
+            return 0;
+
+       case CDROMRESUME:   /* keine Ahnung was das ist */
+            return 0;
+
+
+       case CDROMEJECT:
+            cmd_status ();
+            to_do[0] = CMD_TRAY_CTL;
+            cmd_out (TYPE_INFO, (char *)&to_do, (char *)&dummy, 0);
+
+            return 0;
+
+       default:
+            return -EINVAL;
+    }
+
+}
+
+
+/*
+ * Take care of the different block sizes between cdrom and Linux.
+ * When Linux gets variable block sizes this will probably go away.
+ */
+
+static void gscd_transfer (void)
+{
+long offs;
+
+	while (CURRENT -> nr_sectors > 0 && gscd_bn == CURRENT -> sector / 4)
+	{
+		offs = (CURRENT -> sector & 3) * 512;
+		memcpy(CURRENT -> buffer, gscd_buf + offs, 512);
+		CURRENT -> nr_sectors--;
+		CURRENT -> sector++;
+		CURRENT -> buffer += 512;
+	}
+}
+
+
+/*
+ * I/O request routine called from Linux kernel.
+ */
+
+static void do_gscd_request (void)
+{
+unsigned int block,dev;
+unsigned int nsect;
+
+repeat:
+	if (!(CURRENT) || CURRENT->rq_status == RQ_INACTIVE) return;
+	INIT_REQUEST;
+	dev = MINOR(CURRENT->rq_dev);
+	block = CURRENT->sector;
+	nsect = CURRENT->nr_sectors;
+
+	if (CURRENT == NULL || CURRENT -> sector == -1)
+		return;
+
+	if (CURRENT -> cmd != READ)
+	{
+		printk("GSCD: bad cmd %d\n", CURRENT -> cmd);
+		end_request(0);
+		goto repeat;
+	}
+
+	if (MINOR(CURRENT -> rq_dev) != 0)
+	{
+		printk("GSCD: this version supports only one device\n");
+		end_request(0);
+		goto repeat;
+	}
+
+	gscd_transfer();
+
+	/* if we satisfied the request from the buffer, we're done. */
+
+	if (CURRENT -> nr_sectors == 0)
+	{
+		end_request(1);
+		goto repeat;
+	}
+
+#ifdef GSCD_DEBUG
+        printk ("GSCD: dev %d, block %d, nsect %d\n", dev, block, nsect );
+#endif
+
+	gscd_read_cmd ();
+}
+
+
+
+/*
+ * Check the result of the set-mode command.  On success, send the
+ * read-data command.
+ */
+
+static void
+gscd_read_cmd (void)
+{
+long   block;
+struct gscd_Play_msf gscdcmd;
+char   cmd[] = { CMD_READ, 0x80, 0,0,0, 0,1 }; /* cmd mode M-S-F secth sectl */
+
+
+
+        cmd_status ();
+        if ( disk_state & (ST_NO_DISK | ST_DOOR_OPEN) )
+        {
+           printk ( "GSCD: no disk or door open\n" );
+           end_request (0);
+        }
+        else
+        {
+           if ( disk_state & ST_INVALID )
+           {
+              printk ( "GSCD: disk invalid\n" );
+              end_request (0);
+           }
+           else
+           {
+              gscd_bn = -1;		/* purge our buffer */
+              block = CURRENT -> sector / 4;
+              gscd_hsg2msf(block, &gscdcmd.start);	/* cvt to msf format */
+
+              cmd[2] = gscdcmd.start.min;
+              cmd[3] = gscdcmd.start.sec;
+              cmd[4] = gscdcmd.start.frame;
+
+#ifdef GSCD_DEBUG
+              printk ("GSCD: read msf %d:%d:%d\n", cmd[2], cmd[3], cmd[4] ); 
+#endif 
+              cmd_out ( TYPE_DATA, (char *)&cmd, (char *)&gscd_buf[0], 1 );
+        
+              gscd_bn = CURRENT -> sector / 4;
+              gscd_transfer();
+              end_request(1);
+	   }
+	}
+	SET_TIMER(do_gscd_request, 1);
+}
+
+
+/*
+ * Open the device special file.  Check that a disk is in.
+ */
+
+static int gscd_open (struct inode *ip, struct file *fp)
+{
+int   st;
+
+#ifdef GSCD_DEBUG
+printk ( "GSCD: open\n" );
+#endif
+
+	if (gscdPresent == 0)
+		return -ENXIO;			/* no hardware */
+
+        get_status ();
+        st = disk_state & (ST_NO_DISK | ST_DOOR_OPEN);
+        if ( st )
+        {
+           printk ( "GSCD: no disk or door open\n" );
+           return -ENXIO;
+        }
+                   
+/*	if (updateToc() < 0)
+		return -EIO;
+*/
+
+        #ifdef MODULE
+           MOD_INC_USE_COUNT;
+        #endif
+ 
+	return 0;
+}
+
+
+/*
+ * On close, we flush all gscd blocks from the buffer cache.
+ */
+
+static void gscd_release (struct inode * inode, struct file * file)
+{
+
+#ifdef GSCD_DEBUG
+printk ( "GSCD: release\n" );
+#endif
+
+	gscd_bn = -1;
+	sync_dev(inode->i_rdev);
+	invalidate_buffers(inode -> i_rdev);
+
+        #ifdef MODULE
+           MOD_DEC_USE_COUNT;
+        #endif
+}
+
+
+int get_status (void)
+{
+int  status;
+
+    cmd_status ();
+    status = disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01);
+     
+    if ( status == (ST_x08 | ST_x04 | ST_INVALID | ST_x01) )
+    {
+       cc_invalidate ();
+       return 1;
+    }
+    else
+    {
+       return 0;
+    }
+}
+
+
+void cc_invalidate (void)
+{
+   drv_num_read  = 0xFF;
+   f_dsk_valid   = 0xFF;
+   current_drive = 0xFF;
+   f_drv_ok      = 0xFF;
+
+   clear_Audio ();
+   
+}   
+
+void clear_Audio (void)
+{
+
+   f_AudioPlay = 0;
+   f_AudioPause = 0;
+   AudioStart_m = 0;
+   AudioStart_f = 0;
+   AudioEnd_m   = 0;
+   AudioEnd_f   = 0;
+   
+}
+
+/*
+ *   waiting ?  
+ */
+
+int wait_drv_ready (void)
+{
+int found, read;
+
+   do
+   {  
+       found = inb ( GSCDPORT(0) ); 
+       found &= 0x0f;
+       read  = inb ( GSCDPORT(0) );
+       read  &= 0x0f;
+   } while ( read != found );
+   
+#ifdef GSCD_DEBUG
+printk ( "Wait for: %d\n", read );
+#endif   
+   
+   return read;
+}
+
+void cc_Ident (char * respons)
+{
+char to_do [] = {CMD_IDENT, 0, 0};
+
+    cmd_out (TYPE_INFO, (char *)&to_do, (char *)respons, (int)0x1E );
+
+}
+
+void cc_SetSpeed (void)
+{
+char to_do [] = {CMD_SETSPEED, 0, 0};
+char dummy;
+
+    if ( speed > 0 )
+    {
+       to_do[1] = speed & 0x0F;
+       cmd_out (TYPE_INFO, (char *)&to_do, (char *)&dummy, 0);
+    }
+}
+
+
+void cc_Reset (void)
+{
+char to_do [] = {CMD_RESET, 0};
+char dummy;
+
+   cmd_out (TYPE_INFO, (char *)&to_do, (char *)&dummy, 0);
+}
+
+
+
+void cmd_status (void)
+{
+char to_do [] = {CMD_STATUS, 0};
+char dummy;
+
+   cmd_out (TYPE_INFO, (char *)&to_do, (char *)&dummy, 0);
+
+#ifdef GSCD_DEBUG
+printk ("GSCD: Status: %d\n", disk_state );
+#endif
+
+}
+
+void cmd_out ( int cmd_type, char * cmd, char * respo_buf, int respo_count )
+{
+int        result;
+
+
+       result = wait_drv_ready ();
+       if ( result != drv_mode )
+       {
+       unsigned long test_loops = 0xFFFF;
+       int           i,dummy;
+
+          outb ( curr_drv_state, GSCDPORT(0));
+          
+          /* LOCLOOP_170 */
+          do
+          {
+             result = wait_drv_ready ();
+             test_loops--;
+          } while ( (result != drv_mode) && (test_loops > 0) );
+
+          if ( result != drv_mode )
+          {
+             disk_state = ST_x08 | ST_x04 | ST_INVALID;
+             return;
+          }          
+        
+          /* ...and waiting */
+          for ( i=1,dummy=1 ; i<0xFFFF ; i++ )
+          {
+             dummy *= i;
+          }              
+       }
+
+       /* LOC_172 */    
+       /* check the unit */
+       /* and wake it up */
+       if ( cmd_unit_alive () != 0x08 )
+       {
+          /* LOC_174 */
+          /* game over for this unit */
+          disk_state = ST_x08 | ST_x04 | ST_INVALID;
+          return;
+       }
+       
+       /* LOC_176 */
+       #ifdef GSCD_DEBUG
+        printk ("LOC_176 ");
+       #endif       
+       if ( drv_mode == 0x09 )
+       {
+          /* magic... */
+          printk ("GSCD: magic ...\n");       
+          outb ( result, GSCDPORT(2));
+       }
+
+       /* write the command to the drive */
+       cmd_write_cmd (cmd);
+
+       /* LOC_178 */
+       for (;;)
+       {
+          result = wait_drv_ready ();
+          if ( result != drv_mode )
+          {
+             /* LOC_179 */
+             if ( result == 0x04 )                  /* Mode 4 */
+             {
+                /* LOC_205 */
+                #ifdef GSCD_DEBUG
+                printk ("LOC_205 ");	              
+                #endif
+                disk_state = inb ( GSCDPORT (2));
+             
+                do
+                {
+                   result = wait_drv_ready ();
+                } while ( result != drv_mode );
+                return;
+
+             }
+             else
+             {
+                if ( result == 0x06 )               /* Mode 6 */
+                {
+                   /* LOC_181 */
+                   #ifdef GSCD_DEBUG
+                    printk ("LOC_181 ");	              
+                   #endif
+
+                   if (cmd_type == TYPE_DATA)
+                   {
+                      /* read data */
+                      /* LOC_184 */
+                      if ( drv_mode == 9 )
+                      {
+                         /* read the data to the buffer (word) */
+ 
+                         /* (*(cmd+1))?(CD_FRAMESIZE/2):(CD_FRAMESIZE_RAW/2) */
+                         cmd_read_w ( respo_buf, respo_count, CD_FRAMESIZE/2 );
+                         return;
+                      } 
+                      else
+                      { 
+                         /* read the data to the buffer (byte) */
+                         
+                         /* (*(cmd+1))?(CD_FRAMESIZE):(CD_FRAMESIZE_RAW)    */
+                         cmd_read_b ( respo_buf, respo_count, CD_FRAMESIZE );
+                         return;
+                      }
+                   }
+                   else
+                   { 
+                      /* read the info to the buffer */
+                      cmd_info_in ( respo_buf, respo_count ); 
+                      return;
+                   }                  
+
+                   return;
+                }
+             }
+
+          }
+          else
+          {
+             disk_state = ST_x08 | ST_x04 | ST_INVALID;         
+             return;
+          }    
+       } /* for (;;) */
+
+
+#ifdef GSCD_DEBUG
+printk ("\n");       
+#endif    
+}
+
+
+static void cmd_write_cmd ( char *pstr )
+{
+int  i,j;
+
+    /* LOC_177 */
+    #ifdef GSCD_DEBUG
+     printk ("LOC_177 ");       
+    #endif
+       
+    /* calculate the number of parameter */
+    j = *pstr & 0x0F;
+
+    /* shift it out */
+    for ( i=0 ; i<j ; i++ )
+    {
+       outb ( *pstr, GSCDPORT(2) );
+       pstr++;
+    }
+}
+
+
+static int cmd_unit_alive ( void )
+{
+int            result;
+unsigned long  max_test_loops;
+
+
+    /* LOC_172 */
+    #ifdef GSCD_DEBUG
+     printk ("LOC_172 ");       
+    #endif
+
+    outb ( curr_drv_state, GSCDPORT(0));       
+    max_test_loops = 0xFFFF;
+     
+    do
+    {
+       result = wait_drv_ready ();
+       max_test_loops--;
+    } while ( (result != 0x08) && (max_test_loops > 0) );
+
+    return result;
+}       
+
+
+static void cmd_info_in ( char *pb, int count )
+{
+int   result;
+char  read;
+
+
+        /* read info */
+        /* LOC_182 */
+        #ifdef GSCD_DEBUG
+         printk ("LOC_182 ");				              
+        #endif
+       
+        do
+        {
+           read = inb (GSCDPORT(2)); 
+           if ( count > 0 )
+           {
+              *pb = read;
+              pb++;
+              count--;
+           }
+                         
+           /* LOC_183 */
+           do
+           {
+              result = wait_drv_ready ();
+           } while ( result == 0x0E );
+        } while ( result == 6 );                     
+
+        cmd_end ();
+        return;
+}
+
+
+static void cmd_read_b ( char *pb, int count, int size )
+{
+int  result;
+int  i;
+                     
+                     
+       /* LOC_188 */
+       /* LOC_189 */
+       #ifdef GSCD_DEBUG
+        printk ("LOC_189 ");			              
+       #endif
+
+       do 
+       {
+          do
+          {
+             result = wait_drv_ready ();
+          } while ( result != 6 || result == 0x0E );
+                         
+          if ( result != 6 )
+          {
+             cmd_end ();
+             return;
+          }                       
+          
+          #ifdef GSCD_DEBUG
+           printk ("LOC_191 ");       
+          #endif
+
+          for ( i=0 ; i< size ; i++ )
+          {
+             *pb = inb (GSCDPORT(2));
+             pb++;
+          }
+          count--;
+       } while ( count > 0 );
+       
+       cmd_end ();
+       return;
+}
+
+
+static void cmd_end (void)
+{
+int   result;
+
+
+      /* LOC_204 */
+      #ifdef GSCD_DEBUG
+       printk ("LOC_204 ");				              
+      #endif
+      
+      do
+      {
+         result = wait_drv_ready ();
+         if ( result == drv_mode )
+         {
+            return;
+         }
+      } while ( result != 4 );
+
+      /* LOC_205 */
+      #ifdef GSCD_DEBUG
+       printk ("LOC_205 ");			              
+      #endif
+       
+      disk_state = inb ( GSCDPORT (2));
+             
+      do
+      {
+         result = wait_drv_ready ();
+      } while ( result != drv_mode );
+      return;
+
+}
+
+
+static void cmd_read_w ( char *pb, int count, int size )
+{
+int  result;
+int  i;
+
+
+    #ifdef GSCD_DEBUG
+     printk ("LOC_185 ");			              
+    #endif
+ 
+    do 
+    {
+       /* LOC_185 */
+       do
+       {
+          result = wait_drv_ready ();
+       } while ( result != 6 || result == 0x0E );
+                         
+       if ( result != 6 )
+       {
+          cmd_end ();
+          return;
+       }                       
+                         
+       for ( i=0 ; i<size ; i++ )
+       {
+           /* na, hier muss ich noch mal drueber nachdenken */
+           *pb = inw(GSCDPORT(2));
+           pb++;
+        }
+        count--;
+     } while ( count > 0 );
+                    
+     cmd_end ();
+     return;
+}
+
+int find_drives (void)
+{
+int *pdrv;
+int drvnum;
+int subdrv;
+int i;
+
+    speed           = 0;
+    pdrv            = (int *)&drv_states;
+    curr_drv_state  = 0xFE;
+    subdrv          = 0;
+    drvnum          = 0;
+
+    for ( i=0 ; i<8 ; i++ )
+    { 
+       subdrv++;
+       cmd_status ();
+       disk_state &= ST_x08 | ST_x04 | ST_INVALID | ST_x01;
+       if ( disk_state != (ST_x08 | ST_x04 | ST_INVALID) )
+       {
+          /* LOC_240 */
+          *pdrv = curr_drv_state;
+          init_cd_drive (drvnum);
+          pdrv++;
+          drvnum++;
+       }
+       else
+       {
+          if ( subdrv < 2 )
+          {
+             continue;
+          }
+          else
+          {
+             subdrv = 0;
+          }
+       }   
+
+/*       curr_drv_state<<1;         <-- das geht irgendwie nicht */ 
+/* muss heissen:    curr_drv_state <<= 1; (ist ja Wert-Zuweisung) */
+         curr_drv_state *= 2;
+         curr_drv_state |= 1;
+#ifdef GSCD_DEBUG
+         printk ("DriveState: %d\n", curr_drv_state );
+#endif
+    } 
+
+    ndrives = drvnum;
+    return drvnum;
+}    
+
+void init_cd_drive ( int num )
+{
+char resp [50];
+int  i;
+
+   printk ("GSCD: init unit %d\n", num );
+   cc_Ident ((char *)&resp);
+
+   printk ("GSCD: identification: ");
+   for ( i=0 ; i<0x1E; i++ )
+   {
+      printk ( "%c", resp[i] );
+   }
+   printk ("\n");
+   
+   cc_SetSpeed ();  
+
+}    
+
+#ifdef FUTURE_WORK
+/* return_done */
+static void update_state ( void )
+{
+unsigned int AX;
+
+
+    if ( (disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) == 0 )
+    {
+       if ( disk_state == (ST_x08 | ST_x04 | ST_INVALID))
+       {
+          AX = ST_INVALID;
+       }
+  
+       if ( (disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) == 0 )
+       {
+          invalidate ();
+          f_drv_ok = 0;
+       }
+       
+       AX |= 0x8000;
+    }
+    
+    if ( disk_state & ST_PLAYING )
+    {
+       AX |= 0x200;
+    }
+    
+    AX |= 0x100;
+    /* pkt_esbx = AX; */
+
+    disk_state = 0;
+    
+}
+#endif
+
+/* Init for the Module-Version */
+int init_module (void)
+{
+long err;
+
+
+     /* call the GoldStar-init */
+     err = my_gscd_init ( );
+
+     if ( err < 0 )
+     {
+         return err;
+     }
+     else
+     {
+        printk ( "Happy GoldStar !\n" );
+        return 0;
+     }    
+}
+
+#ifdef MODULE
+void cleanup_module (void)
+{
+
+   if (MOD_IN_USE)
+   {
+      printk("GoldStar-module in use - can't remove it.\n" );
+      return;
+   }
+ 
+   if ((unregister_blkdev(MAJOR_NR, "gscd" ) == -EINVAL))
+   {
+      printk("What's that: can't unregister GoldStar-module\n" );
+      return;
+   }
+
+   release_region (gscd_port,4);
+   printk( "GoldStar-module released.\n" );
+}
+#endif
+
+
+/* Test for presence of drive and initialize it.  Called only at boot time. */
+int gscd_init (void)
+{
+   return my_gscd_init ();
+}
+
+
+/* This is the common initalisation for the GoldStar drive. */
+/* It is called at boot time AND for module init.           */
+int my_gscd_init (void)
+{
+int i;
+int result;
+
+        printk ("GSCD: version %s\n", GSCD_VERSION);
+        printk ("GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n", gscd_port);
+
+        if (check_region(gscd_port, 4)) 
+        {
+	  printk("GSCD: Init failed, I/O port (%X) already in use.\n", gscd_port);
+	  return -EIO;
+	}
+	  
+
+	/* check for card */
+	result = wait_drv_ready ();
+        if ( result == 0x09 )
+        {
+           printk ("GSCD: DMA kann ich noch nicht!\n" );
+           return -EIO;
+        }
+ 
+        if ( result == 0x0b )
+        {
+           drv_mode = result;
+           i = find_drives ();
+           if ( i == 0 )
+           {
+              printk ( "GSCD: GoldStar CD-ROM Drive is not found.\n" );
+              return -EIO;
+           }
+        }
+
+        if ( (result != 0x0b) && (result != 0x09) )
+        {
+              printk ("GSCD: GoldStar Interface Adapter does not exist or H/W error\n" );
+              return -EIO;
+        }          		            
+
+        /* reset all drives */
+        i = 0;
+        while ( drv_states[i] != 0 )
+        {
+           curr_drv_state = drv_states[i];
+           printk ( "GSCD: Reset unit %d ... ",i );
+           cc_Reset ();
+           printk ( "done\n" );
+           i++;
+        }
+
+	if (register_blkdev(MAJOR_NR, "gscd", &gscd_fops) != 0)
+	{
+		printk("GSCD: Unable to get major %d for GoldStar CD-ROM\n",
+		       MAJOR_NR);
+		return -EIO;
+	}
+
+	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	read_ahead[MAJOR_NR] = 4;
+        
+        disk_state = 0;
+        gscdPresent = 1;
+
+	request_region(gscd_port, 4, "gscd");
+
+        printk ( "GSCD: GoldStar CD-ROM Drive found.\n" );
+	return 0;
+}
+
+static void gscd_hsg2msf (long hsg, struct msf *msf)
+{
+	hsg += CD_BLOCK_OFFSET;
+	msf -> min = hsg / (CD_FRAMES*CD_SECS);
+	hsg %= CD_FRAMES*CD_SECS;
+	msf -> sec = hsg / CD_FRAMES;
+	msf -> frame = hsg % CD_FRAMES;
+
+	gscd_bin2bcd(&msf -> min);		/* convert to BCD */
+	gscd_bin2bcd(&msf -> sec);
+	gscd_bin2bcd(&msf -> frame);
+}
+ 
+
+static void gscd_bin2bcd (unsigned char *p)
+{
+int u, t;
+
+	u = *p % 10;
+	t = *p / 10;
+	*p = u | (t << 4);
+}
+
+
+#ifdef FUTURE_WOTK
+static long gscd_msf2hsg (struct msf *mp)
+{
+	return gscd_bcd2bin(mp -> frame)
+		+ gscd_bcd2bin(mp -> sec) * CD_FRAMES
+		+ gscd_bcd2bin(mp -> min) * CD_FRAMES * CD_SECS
+		- CD_BLOCK_OFFSET;
+}
+
+static int gscd_bcd2bin (unsigned char bcd)
+{
+	return (bcd >> 4) * 10 + (bcd & 0xF);
+}
+#endif
+
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this