Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
new file mode 100644
index 0000000..7eac10e
--- /dev/null
+++ b/drivers/cdrom/gscd.c
@@ -0,0 +1,1031 @@
+#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.
+	
+	--------------------------------------------------------------------
+	
+	9 November 1999 -- Make kernel-parameter implementation work with 2.3.x 
+	                   Removed init_module & cleanup_module in favor of 
+		   	   module_init & module_exit.
+			   Torben Mathiasen <tmm@image.dk>
+
+*/
+
+/* 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/module.h>
+
+#include <linux/slab.h>
+#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 <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define MAJOR_NR GOLDSTAR_CDROM_MAJOR
+#include <linux/blkdev.h>
+#include "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;
+module_param_named(gscd, gscd_port, short, 0);
+
+/* Kommt spaeter vielleicht noch mal dran ...
+ *    static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq);
+ */
+
+static void gscd_read_cmd(struct request *req);
+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(unsigned long dummy);
+static int gscd_ioctl(struct inode *, struct file *, unsigned int,
+		      unsigned long);
+static int gscd_open(struct inode *, struct file *);
+static int gscd_release(struct inode *, struct file *);
+static int check_gscd_med_chg(struct gendisk *disk);
+
+/*      GoldStar Funktionen    */
+
+static void cmd_out(int, char *, char *, int);
+static void cmd_status(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
+
+
+/*      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 timer_list gscd_timer = TIMER_INITIALIZER(NULL, 0, 0);
+static DEFINE_SPINLOCK(gscd_lock);
+static struct request_queue *gscd_queue;
+
+static struct block_device_operations gscd_fops = {
+	.owner		= THIS_MODULE,
+	.open		= gscd_open,
+	.release	= gscd_release,
+	.ioctl		= gscd_ioctl,
+	.media_changed	= check_gscd_med_chg,
+};
+
+/* 
+ * Checking if the media has been changed
+ * (not yet implemented)
+ */
+static int check_gscd_med_chg(struct gendisk *disk)
+{
+#ifdef GSCD_DEBUG
+	printk("gscd: check_med_change\n");
+#endif
+	return 0;
+}
+
+
+#ifndef MODULE
+/* Using new interface for kernel-parameters */
+
+static int __init gscd_setup(char *str)
+{
+	int ints[2];
+	(void) get_options(str, ARRAY_SIZE(ints), ints);
+
+	if (ints[0] > 0) {
+		gscd_port = ints[1];
+	}
+	return 1;
+}
+
+__setup("gscd=", gscd_setup);
+
+#endif
+
+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(struct request *req)
+{
+	while (req->nr_sectors > 0 && gscd_bn == req->sector / 4) {
+		long offs = (req->sector & 3) * 512;
+		memcpy(req->buffer, gscd_buf + offs, 512);
+		req->nr_sectors--;
+		req->sector++;
+		req->buffer += 512;
+	}
+}
+
+
+/*
+ * I/O request routine called from Linux kernel.
+ */
+
+static void do_gscd_request(request_queue_t * q)
+{
+	__do_gscd_request(0);
+}
+
+static void __do_gscd_request(unsigned long dummy)
+{
+	struct request *req;
+	unsigned int block;
+	unsigned int nsect;
+
+repeat:
+	req = elv_next_request(gscd_queue);
+	if (!req)
+		return;
+
+	block = req->sector;
+	nsect = req->nr_sectors;
+
+	if (req->sector == -1)
+		goto out;
+
+	if (req->cmd != READ) {
+		printk("GSCD: bad cmd %lu\n", rq_data_dir(req));
+		end_request(req, 0);
+		goto repeat;
+	}
+
+	gscd_transfer(req);
+
+	/* if we satisfied the request from the buffer, we're done. */
+
+	if (req->nr_sectors == 0) {
+		end_request(req, 1);
+		goto repeat;
+	}
+#ifdef GSCD_DEBUG
+	printk("GSCD: block %d, nsect %d\n", block, nsect);
+#endif
+	gscd_read_cmd(req);
+out:
+	return;
+}
+
+
+
+/*
+ * Check the result of the set-mode command.  On success, send the
+ * read-data command.
+ */
+
+static void gscd_read_cmd(struct request *req)
+{
+	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(req, 0);
+	} else {
+		if (disk_state & ST_INVALID) {
+			printk("GSCD: disk invalid\n");
+			end_request(req, 0);
+		} else {
+			gscd_bn = -1;	/* purge our buffer */
+			block = req->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 = req->sector / 4;
+			gscd_transfer(req);
+			end_request(req, 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;
+*/
+
+	return 0;
+}
+
+
+/*
+ * On close, we flush all gscd blocks from the buffer cache.
+ */
+
+static int gscd_release(struct inode *inode, struct file *file)
+{
+
+#ifdef GSCD_DEBUG
+	printk("GSCD: release\n");
+#endif
+
+	gscd_bn = -1;
+
+	return 0;
+}
+
+
+static 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;
+	}
+}
+
+
+static void cc_invalidate(void)
+{
+	drv_num_read = 0xFF;
+	f_dsk_valid = 0xFF;
+	current_drive = 0xFF;
+	f_drv_ok = 0xFF;
+
+	clear_Audio();
+
+}
+
+static void clear_Audio(void)
+{
+
+	f_AudioPlay = 0;
+	f_AudioPause = 0;
+	AudioStart_m = 0;
+	AudioStart_f = 0;
+	AudioEnd_m = 0;
+	AudioEnd_f = 0;
+
+}
+
+/*
+ *   waiting ?  
+ */
+
+static 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;
+}
+
+static void cc_Ident(char *respons)
+{
+	char to_do[] = { CMD_IDENT, 0, 0 };
+
+	cmd_out(TYPE_INFO, (char *) &to_do, (char *) respons, (int) 0x1E);
+
+}
+
+static 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);
+	}
+}
+
+static void cc_Reset(void)
+{
+	char to_do[] = { CMD_RESET, 0 };
+	char dummy;
+
+	cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
+}
+
+static 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
+
+}
+
+static 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;
+}
+
+static int __init 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;
+}
+
+static void __init 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
+
+static struct gendisk *gscd_disk;
+
+static void __exit gscd_exit(void)
+{
+	CLEAR_TIMER;
+
+	del_gendisk(gscd_disk);
+	put_disk(gscd_disk);
+	if ((unregister_blkdev(MAJOR_NR, "gscd") == -EINVAL)) {
+		printk("What's that: can't unregister GoldStar-module\n");
+		return;
+	}
+	blk_cleanup_queue(gscd_queue);
+	release_region(gscd_port, GSCD_IO_EXTENT);
+	printk(KERN_INFO "GoldStar-module released.\n");
+}
+
+/* This is the common initialisation for the GoldStar drive. */
+/* It is called at boot time AND for module init.           */
+static int __init gscd_init(void)
+{
+	int i;
+	int result;
+	int ret=0;
+
+	printk(KERN_INFO "GSCD: version %s\n", GSCD_VERSION);
+	printk(KERN_INFO
+	       "GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n",
+	       gscd_port);
+
+	if (!request_region(gscd_port, GSCD_IO_EXTENT, "gscd")) {
+		printk(KERN_WARNING "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(KERN_WARNING "GSCD: DMA kann ich noch nicht!\n");
+		ret = -EIO;
+		goto err_out1;
+	}
+
+	if (result == 0x0b) {
+		drv_mode = result;
+		i = find_drives();
+		if (i == 0) {
+			printk(KERN_WARNING "GSCD: GoldStar CD-ROM Drive is"
+			       " not found.\n");
+			ret = -EIO;
+			goto err_out1;
+		}
+	}
+
+	if ((result != 0x0b) && (result != 0x09)) {
+		printk(KERN_WARNING "GSCD: GoldStar Interface Adapter does not "
+		       "exist or H/W error\n");
+		ret = -EIO;
+		goto err_out1;
+	}
+
+	/* reset all drives */
+	i = 0;
+	while (drv_states[i] != 0) {
+		curr_drv_state = drv_states[i];
+		printk(KERN_INFO "GSCD: Reset unit %d ... ", i);
+		cc_Reset();
+		printk("done\n");
+		i++;
+	}
+
+	gscd_disk = alloc_disk(1);
+	if (!gscd_disk)
+		goto err_out1;
+	gscd_disk->major = MAJOR_NR;
+	gscd_disk->first_minor = 0;
+	gscd_disk->fops = &gscd_fops;
+	sprintf(gscd_disk->disk_name, "gscd");
+	sprintf(gscd_disk->devfs_name, "gscd");
+
+	if (register_blkdev(MAJOR_NR, "gscd")) {
+		ret = -EIO;
+		goto err_out2;
+	}
+
+	gscd_queue = blk_init_queue(do_gscd_request, &gscd_lock);
+	if (!gscd_queue) {
+		ret = -ENOMEM;
+		goto err_out3;
+	}
+
+	disk_state = 0;
+	gscdPresent = 1;
+
+	gscd_disk->queue = gscd_queue;
+	add_disk(gscd_disk);
+
+	printk(KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n");
+	return 0;
+
+err_out3:
+	unregister_blkdev(MAJOR_NR, "gscd");
+err_out2:
+	put_disk(gscd_disk);
+err_out1:
+	release_region(gscd_port, GSCD_IO_EXTENT);
+	return ret;
+}
+
+static void gscd_hsg2msf(long hsg, struct msf *msf)
+{
+	hsg += CD_MSF_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_WORK
+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_MSF_OFFSET;
+}
+
+static int gscd_bcd2bin(unsigned char bcd)
+{
+	return (bcd >> 4) * 10 + (bcd & 0xF);
+}
+#endif
+
+MODULE_AUTHOR("Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>");
+MODULE_LICENSE("GPL");
+module_init(gscd_init);
+module_exit(gscd_exit);
+MODULE_ALIAS_BLOCKDEV_MAJOR(GOLDSTAR_CDROM_MAJOR);