patch-1.3.36 linux/drivers/block/optcd.c
Next file: linux/drivers/block/ramdisk.c
Previous file: linux/drivers/block/mcdx.c
Back to the patch index
Back to the overall index
- Lines: 1670
- Date:
Thu Jan 1 02:00:00 1970
- Orig file:
v1.3.35/linux/drivers/block/optcd.c
- Orig date:
Tue Oct 10 18:46:32 1995
diff -u --recursive --new-file v1.3.35/linux/drivers/block/optcd.c linux/drivers/block/optcd.c
@@ -1,1669 +0,0 @@
-/* $Id: optcd.c,v 1.3 1995/08/24 19:54:27 root Exp root $
- linux/drivers/block/optcd.c - Optics Storage 8000 AT CDROM driver
-
- Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl)
-
- Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks
- by Eberhard Moenkeberg (emoenke@gwdg.de). ISP16 detection and
- configuration by Eric van der Maarel (maarel@marin.nl), with some data
- communicated by Vadim V. Model (vadim@rbrf.msk.su).
-
- 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.
-
- History
- 14-5-95 v0.0 Plays sound tracks. No reading of data CDs yet.
- Detection of disk change doesn't work.
- 21-5-95 v0.1 First ALPHA version. CD can be mounted. The
- device major nr is borrowed from the Aztech
- driver. Speed is around 240 kb/s, as measured
- with "time dd if=/dev/cdrom of=/dev/null \
- bs=2048 count=4096".
- 24-6-95 v0.2 Reworked the #defines for the command codes
- and the like, as well as the structure of
- the hardware communication protocol, to
- reflect the "official" documentation, kindly
- supplied by C.K. Tan, Optics Storage Pte. Ltd.
- Also tidied up the state machine somewhat.
- 28-6-95 v0.3 Removed the ISP-16 interface code, as this
- should go into its own driver. The driver now
- has its own major nr.
- Disk change detection now seems to work, too.
- This version became part of the standard
- kernel as of version 1.3.7
- 24-9-95 v0.4 Re-inserted ISP-16 interface code which I
- copied from sjcd.c, with a few changes.
- Updated README.optcd. Submitted for
- inclusion in 1.3.21
- 29-9-95 v0.4a Fixed bug that prevented compilation as module
-*/
-
-#include <linux/major.h>
-#include <linux/config.h>
-
-#ifdef MODULE
-# include <linux/module.h>
-# include <linux/version.h>
-# ifndef CONFIG_MODVERSIONS
- char kernel_version[]= UTS_RELEASE;
-# endif
-#define optcd_init init_module
-#else
-# define MOD_INC_USE_COUNT
-# define MOD_DEC_USE_COUNT
-#endif
-
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/timer.h>
-#include <linux/kernel.h>
-#include <linux/cdrom.h>
-#include <linux/ioport.h>
-#include <asm/io.h>
-
-#define MAJOR_NR OPTICS_CDROM_MAJOR
-
-# include "blk.h"
-#define optcd_port optcd /* Needed for the modutils. */
-# include <linux/optcd.h>
-
-
-/* Some (Media)Magic */
-/* define types of drive the interface on an ISP16 card may be looking at */
-#define ISP16_DRIVE_X 0x00
-#define ISP16_SONY 0x02
-#define ISP16_PANASONIC0 0x02
-#define ISP16_SANYO0 0x02
-#define ISP16_MITSUMI 0x04
-#define ISP16_PANASONIC1 0x06
-#define ISP16_SANYO1 0x06
-#define ISP16_DRIVE_NOT_USED 0x08 /* not used */
-#define ISP16_DRIVE_SET_MASK 0xF1 /* don't change 0-bit or 4-7-bits*/
-/* ...for port */
-#define ISP16_DRIVE_SET_PORT 0xF8D
-/* set io parameters */
-#define ISP16_BASE_340 0x00
-#define ISP16_BASE_330 0x40
-#define ISP16_BASE_360 0x80
-#define ISP16_BASE_320 0xC0
-#define ISP16_IRQ_X 0x00
-#define ISP16_IRQ_5 0x04 /* shouldn't be used due to soundcard conflicts */
-#define ISP16_IRQ_7 0x08 /* shouldn't be used due to soundcard conflicts */
-#define ISP16_IRQ_3 0x0C
-#define ISP16_IRQ_9 0x10
-#define ISP16_IRQ_10 0x14
-#define ISP16_IRQ_11 0x18
-#define ISP16_DMA_X 0x03
-#define ISP16_DMA_3 0x00
-#define ISP16_DMA_5 0x00
-#define ISP16_DMA_6 0x01
-#define ISP16_DMA_7 0x02
-#define ISP16_IO_SET_MASK 0x20 /* don't change 5-bit */
-/* ...for port */
-#define ISP16_IO_SET_PORT 0xF8E
-/* enable the drive */
-#define ISP16_NO_IDE__ENABLE_CDROM_PORT 0xF90 /* ISP16 without IDE interface */
-#define ISP16_IDE__ENABLE_CDROM_PORT 0xF91 /* ISP16 with IDE interface */
-#define ISP16_ENABLE_CDROM 0x80 /* seven bit */
-
-/* the magic stuff */
-#define ISP16_CTRL_PORT 0xF8F
-#define ISP16_NO_IDE__CTRL 0xE2 /* ISP16 without IDE interface */
-#define ISP16_IDE__CTRL 0xE3 /* ISP16 with IDE interface */
-
-static short isp16_detect(void);
-static short isp16_no_ide__detect(void);
-static short isp16_with_ide__detect(void);
-static short isp16_config( int base, u_char drive_type, int irq, int dma );
-static short isp16_type; /* dependent on type of interface card */
-static u_char isp16_ctrl;
-static u_short isp16_enable_cdrom_port;
-
-
-static short optcd_port = OPTCD_PORTBASE;
-
-/* Read current status/data availability flags */
-inline static int optFlags(void) {
- return inb(STATUS_PORT) & FL_STDT;
-}
-
-/* Wait for status available; return TRUE on timeout */
-static int sten_low(void) {
- int no_status;
- unsigned long count = 0;
- while ((no_status = (optFlags() & FL_STEN)))
- if (++count >= BUSY_TIMEOUT)
- break;
-#ifdef DEBUG_DRIVE_IF
- if (no_status)
- printk("optcd: timeout waiting for STEN low\n");
- else
- printk("optcd: STEN low after %ld\n", count);
-#endif
- return no_status;
-}
-
-/* Wait for data available; return TRUE on timeout */
-static int dten_low(void) {
- int no_data;
- unsigned long count = 0;
- while ((no_data = (optFlags() & FL_DTEN)))
- if (++count >= BUSY_TIMEOUT)
- break;
-#ifdef DEBUG_DRIVE_IF
- if (no_data)
- printk("optcd: timeout waiting for DTEN low\n");
- else
- printk("optcd: DTEN low after %ld\n", count);
-#endif
- return no_data;
-}
-
-/* Facilities for polled waiting for status or data */
-static int sleep_timeout; /* Max amount of time still to sleep */
-static unsigned char sleep_flags; /* Flags read last time around */
-static struct wait_queue *waitq = NULL;
-static struct timer_list delay_timer = {NULL, NULL, 0, 0, NULL};
-
-/* Timer routine: wake up when either of FL_STEN or FL_DTEN goes down,
- * or when timeout expires. Otherwise wait some more.
- */
-static void sleep_timer(void) {
- if ((sleep_flags = optFlags()) != FL_STDT) {
- wake_up(&waitq);
- return;
- }
- if (--sleep_timeout <= 0) {
- wake_up(&waitq);
- return;
- }
- SET_TIMER(sleep_timer, 1);
-}
-
-/* Sleep until any of FL_STEN or FL_DTEN go down, or until timeout.
- * sleep_timeout must be set first.
- */
-static int sleep_status(void) {
-#ifdef DEBUG_DRIVE_IF
- printk("optcd: sleeping %d on status\n", sleep_timeout);
-#endif
- if (sleep_timeout <= 0) /* timeout immediately */
- return FL_STDT;
- if ((sleep_flags = optFlags()) == FL_STDT) {
- SET_TIMER(sleep_timer, 1);
- sleep_on(&waitq);
- }
-#ifdef DEBUG_DRIVE_IF
- printk("optcd: woken up with %d to go, flags %d\n",
- sleep_timeout, sleep_flags);
-#endif
- return sleep_flags;
-}
-
-/* Sleep until status available; return TRUE on timeout */
-inline static int sleep_sten_low(void) {
- int flags;
- sleep_timeout = SLEEP_TIMEOUT;
- flags = sleep_status();
-#ifdef DEBUG_DRIVE_IF
- if (!(flags & FL_DTEN))
- printk("optcd: DTEN while waiting for STEN\n");
-#endif
- return flags & FL_STEN;
-}
-
-/* Sleep until data available; return TRUE on timeout */
-inline static int sleep_dten_low(void) {
- int flags;
- sleep_timeout = SLEEP_TIMEOUT;
- flags = sleep_status();
-#ifdef DEBUG_DRIVE_IF
- if (!(flags & FL_STEN))
- printk("optcd: STEN while waiting for DTEN\n");
-#endif
- return flags & FL_DTEN;
-}
-
-/* Send command code. Return <0 indicates error */
-static int optSendCmd(int cmd) {
- unsigned char ack;
-#if defined(DEBUG_DRIVE_IF)||defined(DEBUG_COMMANDS)
- printk("optcd: executing command 0x%02x\n", cmd);
-#endif
- outb(HCON_DTS, HCON_PORT); /* Enable Suspend Data Transfer */
- outb(cmd, COMIN_PORT); /* Send command code */
- if (sten_low()) /* Wait for status available */
- return -ERR_IF_CMD_TIMEOUT;
- ack = inb(DATA_PORT); /* read command acknowledge */
-#ifdef DEBUG_DRIVE_IF
- printk("optcd: acknowledge code 0x%02x\n", ack);
-#endif
- outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */
- return ack==ST_OP_OK ? 0 : -ack;
-}
-
-/* Send command parameters. Return <0 indicates error */
-static int optSendParams(struct opt_Play_msf *params) {
- unsigned char ack;
-#if defined(DEBUG_DRIVE_IF)||defined(DEBUG_COMMANDS)
- printk("optcd: params %02x:%02x:%02x %02x:%02x:%02x\n",
- params->start.min, params->start.sec, params->start.frame,
- params->end.min, params->end.sec, params->end.frame);
-#endif
- outb(params -> start.min, COMIN_PORT);
- outb(params -> start.sec, COMIN_PORT);
- outb(params -> start.frame, COMIN_PORT);
- outb(params -> end.min, COMIN_PORT);
- outb(params -> end.sec, COMIN_PORT);
- outb(params -> end.frame, COMIN_PORT);
- if (sten_low()) /* Wait for status available */
- return -ERR_IF_CMD_TIMEOUT;
- ack = inb(DATA_PORT); /* read command acknowledge */
-#ifdef DEBUG_DRIVE_IF
- printk("optcd: acknowledge code 0x%02x\n", ack);
-#endif
- return ack==ST_PA_OK ? 0 : -ack;
-}
-
-/* Return execution status for quick response commands, i.e. busy wait.
- * Return value <0 indicates timeout.
- */
-static int optGetExecStatus(void) {
- unsigned char exec_status;
- if (sten_low()) /* Wait for status available */
- return -ERR_IF_CMD_TIMEOUT;
- exec_status = inb(DATA_PORT); /* read command execution status */
-#ifdef DEBUG_DRIVE_IF
- printk("optcd: returned execution status: 0x%02x\n", exec_status);
-#endif
- return exec_status;
-}
-
-/* Return execution status for slow commands. Only use when no data is
- * expected. Return value <0 indicates timeout.
- */
-static int optSleepTillExecStatus(void) {
- unsigned char exec_status;
- if (sleep_sten_low()) /* Wait for status available */
- return -ERR_IF_CMD_TIMEOUT;
- exec_status = inb(DATA_PORT); /* read command execution status */
-#ifdef DEBUG_DRIVE_IF
- printk("optcd: returned execution status: 0x%02x\n", exec_status);
-#endif
- return exec_status;
-}
-
-/* Fetch status that has previously been waited for. <0 means not available */
-inline static int optStatus(void) {
- unsigned char status;
- if (optFlags() & FL_STEN)
- return -ERR_IF_NOSTAT;
- status = inb(DATA_PORT);
-#ifdef DEBUG_DRIVE_IF
- printk("optcd: read status: 0x%02x\n", status);
-#endif
- return status;
-}
-
-/* Wait for extra byte of data that a command returns */
-static int optGetData(void) {
- unsigned char data;
- if (sten_low())
- return -ERR_IF_DATA_TIMEOUT;
- data = inb(DATA_PORT);
-#ifdef DEBUG_DRIVE_IF
- printk("optcd: read data: 0x%02x\n", data);
-#endif
- return data;
-}
-
-/* Read data that has previously been waited for. */
-inline static void optReadData(char *buf, int n) {
- insb(DATA_PORT, buf, n);
-}
-
-/* Flush status and data fifos */
-inline static void optFlushData(void) {
- while (optFlags() != FL_STDT)
- inb(DATA_PORT);
-}
-
-/* Write something to RESET_PORT and wait. Return TRUE upon success. */
-static int optResetDrive(void) {
- unsigned long count = 0;
- int flags;
-#ifdef DEBUG_DRIVE_IF
- printk("optcd: reset drive\n");
-#endif
- outb(0, RESET_PORT);
- while (++count < RESET_WAIT)
- inb(DATA_PORT);
- count = 0;
- while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET)
- if (++count >= BUSY_TIMEOUT)
- break;
-#ifdef DEBUG_DRIVE_IF
- if (flags == FL_RESET)
- printk("optcd: drive reset\n");
- else
- printk("optcd: reset failed\n");
-#endif
- if (flags != FL_RESET)
- return 0; /* Reset failed */
- outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */
- return 1; /* Reset succeeded */
-}
-
-
-/* Command protocol */
-
-/* Send a simple command and wait for response */
-inline static int optCmd(int cmd) {
- int ack = optSendCmd(cmd);
- if (ack < 0)
- return ack;
- if (cmd < COMFETCH) /* Quick response command */
- return optGetExecStatus();
- else /* Slow command */
- return optSleepTillExecStatus();
-}
-
-/* Send a command with parameters and wait for response */
-inline static int optPlayCmd(int cmd, struct opt_Play_msf *params) {
- int ack = optSendCmd(cmd);
- if (ack < 0)
- return ack;
- if ((ack = optSendParams(params)) < 0)
- return ack;
- return optSleepTillExecStatus();
-}
-
-/* Send a command with parameters. Don't wait for the response,
- * which consists of the data blocks read. */
-inline static int optReadCmd(int cmd, struct opt_Play_msf *params) {
- int ack = optSendCmd(cmd);
- if (ack < 0)
- return ack;
- return optSendParams(params);
-}
-
-
-/* Address conversion routines */
-
-/* Binary to BCD (2 digits) */
-inline static unsigned char bin2bcd(unsigned char p) {
-#ifdef DEBUG_CONV
- if (p > 99)
- printk("optcd: error bin2bcd %d\n", p);
-#endif
- return (p % 10) | ((p / 10) << 4);
-}
-
-/* Linear address to minute, second, frame form */
-static void hsg2msf(long hsg, struct msf *msf) {
- hsg += 150;
- msf -> min = hsg / 4500;
- hsg %= 4500;
- msf -> sec = hsg / 75;
- msf -> frame = hsg % 75;
-#ifdef DEBUG_CONV
- if (msf -> min >= 70)
- printk("optcd: Error hsg2msf address Minutes\n");
- if (msf -> sec >= 60)
- printk("optcd: Error hsg2msf address Seconds\n");
- if (msf -> frame >= 75)
- printk("optcd: Error hsg2msf address Frames\n");
-#endif
- msf -> min = bin2bcd(msf -> min); /* convert to BCD */
- msf -> sec = bin2bcd(msf -> sec);
- msf -> frame = bin2bcd(msf -> frame);
-}
-
-/* Two BCD digits to binary */
-inline static int bcd2bin(unsigned char bcd) {
- return (bcd >> 4) * 10 + (bcd & 0x0f);
-}
-
-/* Minute, second, frame address to linear address */
-static long msf2hsg(struct msf *mp) {
-#ifdef DEBUG_CONV
- if (mp -> min >= 70)
- printk("optcd: Error msf2hsg address Minutes\n");
- if (mp -> sec >= 60)
- printk("optcd: Error msf2hsg address Seconds\n");
- if (mp -> frame >= 75)
- printk("optcd: Error msf2hsg address Frames\n");
-#endif
- return bcd2bin(mp -> frame)
- + bcd2bin(mp -> sec) * 75
- + bcd2bin(mp -> min) * 4500
- - 150;
-}
-
-
-/* Drive status and table of contents */
-
-static int optAudioStatus = CDROM_AUDIO_NO_STATUS;
-static char optDiskChanged = 1;
-static char optTocUpToDate = 0;
-static struct opt_DiskInfo DiskInfo;
-static struct opt_Toc Toc[MAX_TRACKS];
-
-/* Get CDROM status, flagging completion of audio play and disk changes. */
-static int optGetStatus(void) {
- int st;
- if ((st = optCmd(COMIOCTLISTAT)) < 0)
- return st;
- if (st == 0xff)
- return -ERR_IF_NOSTAT;
- if (((st & ST_MODE_BITS) != ST_M_AUDIO) &&
- (optAudioStatus == CDROM_AUDIO_PLAY)) {
- optAudioStatus = CDROM_AUDIO_COMPLETED;
- }
- if (st & ST_DSK_CHG) {
- optDiskChanged = 1;
- optTocUpToDate = 0;
- optAudioStatus = CDROM_AUDIO_NO_STATUS;
- }
- return st;
-}
-
-/*
- * Read the current Q-channel info. Also used for reading the
- * table of contents.
- */
-static int optGetQChannelInfo(struct opt_Toc *qp) {
- int st;
-#ifdef DEBUG_TOC
- printk("optcd: starting optGetQChannelInfo\n");
-#endif
- if ((st = optGetStatus()) < 0)
- return st;
- if ((st = optCmd(COMSUBQ)) < 0)
- return st;
- if ((qp -> ctrl_addr = st = optGetData()), st < 0) return st;
- if ((qp -> track = st = optGetData()), st < 0) return st;
- if ((qp -> pointIndex = st = optGetData()), st < 0) return st;
- if ((qp -> trackTime.min = st = optGetData()), st < 0) return st;
- if ((qp -> trackTime.sec = st = optGetData()), st < 0) return st;
- if ((qp -> trackTime.frame = st = optGetData()), st < 0) return st;
- if ((st = optGetData()) < 0) return st; /* byte not used */
- if ((qp -> diskTime.min = st = optGetData()), st < 0) return st;
- if ((qp -> diskTime.sec = st = optGetData()), st < 0) return st;
- if ((qp -> diskTime.frame = st = optGetData()), st < 0) return st;
-#ifdef DEBUG_TOC
- printk("optcd: exiting optGetQChannelInfo\n");
-#endif
- return 0;
-}
-
-#define QINFO_FIRSTTRACK 0xa0
-#define QINFO_LASTTRACK 0xa1
-#define QINFO_DISKLENGTH 0xa2
-
-static int optGetDiskInfo(void) {
- int st, limit;
- unsigned char test = 0;
- struct opt_Toc qInfo;
-#ifdef DEBUG_TOC
- printk("optcd: starting optGetDiskInfo\n");
-#endif
- optDiskChanged = 0;
- if ((st = optCmd(COMLEADIN)) < 0)
- return st;
- for (limit = 300; (limit > 0) && (test != 0x0f); limit--) {
- if ((st = optGetQChannelInfo(&qInfo)) < 0)
- return st;
- switch (qInfo.pointIndex) {
- case QINFO_FIRSTTRACK:
- DiskInfo.first = bcd2bin(qInfo.diskTime.min);
-#ifdef DEBUG_TOC
- printk("optcd: got first: %d\n", DiskInfo.first);
-#endif
- test |= 0x01;
- break;
- case QINFO_LASTTRACK:
- DiskInfo.last = bcd2bin(qInfo.diskTime.min);
-#ifdef DEBUG_TOC
- printk("optcd: got last: %d\n", DiskInfo.last);
-#endif
- test |= 0x02;
- break;
- case QINFO_DISKLENGTH:
- DiskInfo.diskLength.min = qInfo.diskTime.min;
- DiskInfo.diskLength.sec = qInfo.diskTime.sec-2;
- DiskInfo.diskLength.frame = qInfo.diskTime.frame;
-#ifdef DEBUG_TOC
- printk("optcd: got length: %x:%x.%x\n",
- DiskInfo.diskLength.min,
- DiskInfo.diskLength.sec,
- DiskInfo.diskLength.frame);
-#endif
- test |= 0x04;
- break;
- default:
- if ((test & 0x01) /* Got no of first track */
- && (qInfo.pointIndex == DiskInfo.first)) {
- /* StartTime of First Track */
- DiskInfo.firstTrack.min = qInfo.diskTime.min;
- DiskInfo.firstTrack.sec = qInfo.diskTime.sec;
- DiskInfo.firstTrack.frame = qInfo.diskTime.frame;
-#ifdef DEBUG_TOC
- printk("optcd: got start: %x:%x.%x\n",
- DiskInfo.firstTrack.min,
- DiskInfo.firstTrack.sec,
- DiskInfo.firstTrack.frame);
-#endif
- test |= 0x08;
- }
- }
- }
-#ifdef DEBUG_TOC
- printk("optcd: exiting optGetDiskInfo\n");
-#endif
- if (test != 0x0f)
- return -ERR_TOC_MISSINGINFO;
- return 0;
-}
-
-static int optGetToc(void) { /* Presumes we have got DiskInfo */
- int st, count, px, limit;
- struct opt_Toc qInfo;
-#ifdef DEBUG_TOC
- int i;
- printk("optcd: starting optGetToc\n");
-#endif
- for (count = 0; count < MAX_TRACKS; count++)
- Toc[count].pointIndex = 0;
- if ((st = optCmd(COMLEADIN)) < 0)
- return st;
- st = 0;
- count = DiskInfo.last + 3;
- for (limit = 300; (limit > 0) && (count > 0); limit--) {
- if ((st = optGetQChannelInfo(&qInfo)) < 0)
- break;
- px = bcd2bin(qInfo.pointIndex);
- if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
- if (Toc[px].pointIndex == 0) {
- Toc[px] = qInfo;
- count--;
- }
- }
- Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
-#ifdef DEBUG_TOC
- printk("optcd: exiting optGetToc\n");
- for (i = 1; i <= DiskInfo.last + 1; i++)
- printk("i = %3d ctl-adr = %02x track %2d px "
- "%02x %02x:%02x.%02x %02x:%02x.%02x\n",
- i, Toc[i].ctrl_addr,
- Toc[i].track,
- Toc[i].pointIndex,
- Toc[i].trackTime.min,
- Toc[i].trackTime.sec,
- Toc[i].trackTime.frame,
- Toc[i].diskTime.min,
- Toc[i].diskTime.sec,
- Toc[i].diskTime.frame);
- for (i = 100; i < 103; i++)
- printk("i = %3d ctl-adr = %02x track %2d px "
- "%02x %02x:%02x.%02x %02x:%02x.%02x\n",
- i, Toc[i].ctrl_addr,
- Toc[i].track,
- Toc[i].pointIndex,
- Toc[i].trackTime.min,
- Toc[i].trackTime.sec,
- Toc[i].trackTime.frame,
- Toc[i].diskTime.min,
- Toc[i].diskTime.sec,
- Toc[i].diskTime.frame);
-#endif
- return count ? -ERR_TOC_MISSINGENTRY : 0;
-}
-
-static int optUpdateToc(void) {
-#ifdef DEBUG_TOC
- printk("optcd: starting optUpdateToc\n");
-#endif
- if (optTocUpToDate)
- return 0;
- if (optGetDiskInfo() < 0)
- return -EIO;
- if (optGetToc() < 0)
- return -EIO;
- optTocUpToDate = 1;
-#ifdef DEBUG_TOC
- printk("optcd: exiting optUpdateToc\n");
-#endif
- return 0;
-}
-
-
-/* Buffers */
-
-#define OPT_BUF_SIZ 16
-#define OPT_BLOCKSIZE 2048
-#define OPT_BLOCKSIZE_RAW 2336
-#define OPT_BLOCKSIZE_ALL 2646
-#define OPT_NOBUF -1
-
-/* Buffer for block size conversion. */
-static char opt_buf[OPT_BLOCKSIZE*OPT_BUF_SIZ];
-static volatile int opt_buf_bn[OPT_BUF_SIZ], opt_next_bn;
-static volatile int opt_buf_in = 0, opt_buf_out = OPT_NOBUF;
-
-inline static void opt_invalidate_buffers(void) {
- int i;
-#ifdef DEBUG_BUFFERS
- printk("optcd: executing opt_invalidate_buffers\n");
-#endif
- for (i = 0; i < OPT_BUF_SIZ; i++)
- opt_buf_bn[i] = OPT_NOBUF;
- opt_buf_out = OPT_NOBUF;
-}
-
-/*
- * Take care of the different block sizes between cdrom and Linux.
- * When Linux gets variable block sizes this will probably go away.
- */
-static void opt_transfer(void) {
-#if (defined DEBUG_BUFFERS) || (defined DEBUG_REQUEST)
- printk("optcd: executing opt_transfer\n");
-#endif
- if (!CURRENT_VALID)
- return;
- while (CURRENT -> nr_sectors) {
- int bn = CURRENT -> sector / 4;
- int i, offs, nr_sectors;
- for (i = 0; i < OPT_BUF_SIZ && opt_buf_bn[i] != bn; ++i);
-#ifdef DEBUG_REQUEST
- printk("optcd: found %d\n", i);
-#endif
- if (i >= OPT_BUF_SIZ) {
- opt_buf_out = OPT_NOBUF;
- break;
- }
- offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
- nr_sectors = 4 - (CURRENT -> sector & 3);
- if (opt_buf_out != i) {
- opt_buf_out = i;
- if (opt_buf_bn[i] != bn) {
- opt_buf_out = OPT_NOBUF;
- continue;
- }
- }
- if (nr_sectors > CURRENT -> nr_sectors)
- nr_sectors = CURRENT -> nr_sectors;
- memcpy(CURRENT -> buffer, opt_buf + offs, nr_sectors * 512);
- CURRENT -> nr_sectors -= nr_sectors;
- CURRENT -> sector += nr_sectors;
- CURRENT -> buffer += nr_sectors * 512;
- }
-}
-
-
-/* State machine for reading disk blocks */
-
-enum opt_state_e {
- OPT_S_IDLE, /* 0 */
- OPT_S_START, /* 1 */
- OPT_S_READ, /* 2 */
- OPT_S_DATA, /* 3 */
- OPT_S_STOP, /* 4 */
- OPT_S_STOPPING /* 5 */
-};
-
-static volatile enum opt_state_e opt_state = OPT_S_IDLE;
-#ifdef DEBUG_STATE
-static volatile enum opt_state_e opt_state_old = OPT_S_STOP;
-static volatile int opt_st_old = 0;
-static volatile long opt_state_n = 0;
-#endif
-
-static volatile int opt_transfer_is_active = 0;
-static volatile int opt_error = 0; /* do something with this?? */
-static int optTries; /* ibid?? */
-
-static void opt_poll(void) {
- static int optTimeout;
- static volatile int opt_read_count = 1;
- int st = 0;
- int loop_ctl = 1;
- int skip = 0;
-
- if (opt_error) {
- printk("optcd: I/O error 0x%02x\n", opt_error);
- opt_invalidate_buffers();
-#ifdef WARN_IF_READ_FAILURE
- if (optTries == 5)
- printk("optcd: read block %d failed; audio disk?\n",
- opt_next_bn);
-#endif
- if (!optTries--) {
- printk("optcd: read block %d failed; Giving up\n",
- opt_next_bn);
- if (opt_transfer_is_active) {
- optTries = 0;
- loop_ctl = 0;
- }
- if (CURRENT_VALID)
- end_request(0);
- optTries = 5;
- }
- opt_error = 0;
- opt_state = OPT_S_STOP;
- }
-
- while (loop_ctl)
- {
- loop_ctl = 0; /* each case must flip this back to 1 if we want
- to come back up here */
-#ifdef DEBUG_STATE
- if (opt_state == opt_state_old)
- opt_state_n++;
- else {
- opt_state_old = opt_state;
- if (++opt_state_n > 1)
- printk("optcd: %ld times in previous state\n",
- opt_state_n);
- printk("optcd: state %d\n", opt_state);
- opt_state_n = 0;
- }
-#endif
- switch (opt_state) {
- case OPT_S_IDLE:
- return;
- case OPT_S_START:
- if (optSendCmd(COMDRVST))
- return;
- opt_state = OPT_S_READ;
- optTimeout = 3000;
- break;
- case OPT_S_READ: {
- struct opt_Play_msf msf;
- if (!skip) {
- if ((st = optStatus()) < 0)
- break;
- if (st & ST_DSK_CHG) {
- optDiskChanged = 1;
- optTocUpToDate = 0;
- opt_invalidate_buffers();
- }
- }
- skip = 0;
- if ((st & ST_DOOR_OPEN) || (st & ST_DRVERR)) {
- optDiskChanged = 1;
- optTocUpToDate = 0;
- printk((st & ST_DOOR_OPEN)
- ? "optcd: door open\n"
- : "optcd: disk removed\n");
- if (opt_transfer_is_active) {
- opt_state = OPT_S_START;
- loop_ctl = 1;
- break;
- }
- opt_state = OPT_S_IDLE;
- while (CURRENT_VALID)
- end_request(0);
- return;
- }
- if (!CURRENT_VALID) {
- opt_state = OPT_S_STOP;
- loop_ctl = 1;
- break;
- }
- opt_next_bn = CURRENT -> sector / 4;
- hsg2msf(opt_next_bn, &msf.start);
- opt_read_count = OPT_BUF_SIZ;
- msf.end.min = 0;
- msf.end.sec = 0;
- msf.end.frame = opt_read_count;
-#ifdef DEBUG_REQUEST
- printk("optcd: reading %x:%x.%x %x:%x.%x\n",
- msf.start.min,
- msf.start.sec,
- msf.start.frame,
- msf.end.min,
- msf.end.sec,
- msf.end.frame);
- printk("optcd: opt_next_bn:%d opt_buf_in:%d opt_buf_out:%d opt_buf_bn:%d\n",
- opt_next_bn,
- opt_buf_in,
- opt_buf_out,
- opt_buf_bn[opt_buf_in]);
-#endif
- optReadCmd(COMREAD, &msf);
- opt_state = OPT_S_DATA;
- optTimeout = READ_TIMEOUT;
- break;
- }
- case OPT_S_DATA:
- st = optFlags() & (FL_STEN|FL_DTEN);
-#ifdef DEBUG_STATE
- if (st != opt_st_old) {
- opt_st_old = st;
- printk("optcd: st:%x\n", st);
- }
- if (st == FL_STEN)
- printk("timeout cnt: %d\n", optTimeout);
-#endif
- switch (st) {
- case FL_DTEN:
-#ifdef WARN_IF_READ_FAILURE
- if (optTries == 5)
- printk("optcd: read block %d failed; audio disk?\n",
- opt_next_bn);
-#endif
- if (!optTries--) {
- printk("optcd: read block %d failed; Giving up\n",
- opt_next_bn);
- if (opt_transfer_is_active) {
- optTries = 0;
- break;
- }
- if (CURRENT_VALID)
- end_request(0);
- optTries = 5;
- }
- opt_state = OPT_S_START;
- optTimeout = READ_TIMEOUT;
- loop_ctl = 1;
- case (FL_STEN|FL_DTEN):
- break;
- default:
- optTries = 5;
- if (!CURRENT_VALID && opt_buf_in == opt_buf_out) {
- opt_state = OPT_S_STOP;
- loop_ctl = 1;
- break;
- }
- if (opt_read_count<=0)
- printk("optcd: warning - try to read 0 frames\n");
- while (opt_read_count) {
- opt_buf_bn[opt_buf_in] = OPT_NOBUF;
- if (dten_low()) { /* should be no waiting here!?? */
- printk("read_count:%d CURRENT->nr_sectors:%ld opt_buf_in:%d\n",
- opt_read_count,
- CURRENT->nr_sectors,
- opt_buf_in);
- printk("opt_transfer_is_active:%x\n",
- opt_transfer_is_active);
- opt_read_count = 0;
- opt_state = OPT_S_STOP;
- loop_ctl = 1;
- end_request(0);
- break;
- }
- optReadData(opt_buf+OPT_BLOCKSIZE*opt_buf_in, OPT_BLOCKSIZE);
- opt_read_count--;
-#ifdef DEBUG_REQUEST
- printk("OPT_S_DATA; ---I've read data- read_count: %d\n",
- opt_read_count);
- printk("opt_next_bn:%d opt_buf_in:%d opt_buf_out:%d opt_buf_bn:%d\n",
- opt_next_bn,
- opt_buf_in,
- opt_buf_out,
- opt_buf_bn[opt_buf_in]);
-#endif
- opt_buf_bn[opt_buf_in] = opt_next_bn++;
- if (opt_buf_out == OPT_NOBUF)
- opt_buf_out = opt_buf_in;
- opt_buf_in = opt_buf_in + 1 ==
- OPT_BUF_SIZ ? 0 : opt_buf_in + 1;
- }
- if (!opt_transfer_is_active) {
- while (CURRENT_VALID) {
- opt_transfer();
- if (CURRENT -> nr_sectors == 0)
- end_request(1);
- else
- break;
- }
- }
-
- if (CURRENT_VALID
- && (CURRENT -> sector / 4 < opt_next_bn ||
- CURRENT -> sector / 4 >
- opt_next_bn + OPT_BUF_SIZ)) {
- opt_state = OPT_S_STOP;
- loop_ctl = 1;
- break;
- }
- optTimeout = READ_TIMEOUT;
- if (opt_read_count == 0) {
- opt_state = OPT_S_STOP;
- loop_ctl = 1;
- break;
- }
- }
- break;
- case OPT_S_STOP:
- if (opt_read_count != 0)
- printk("optcd: discard data=%x frames\n",
- opt_read_count);
- while (opt_read_count != 0) {
- optFlushData();
- opt_read_count--;
- }
- if (optSendCmd(COMDRVST))
- return;
- opt_state = OPT_S_STOPPING;
- optTimeout = 1000;
- break;
- case OPT_S_STOPPING:
- if ((st = optStatus()) < 0 && optTimeout)
- break;
- if ((st != -1) && (st & ST_DSK_CHG)) {
- optDiskChanged = 1;
- optTocUpToDate = 0;
- opt_invalidate_buffers();
- }
- if (CURRENT_VALID) {
- if (st != -1) {
- opt_state = OPT_S_READ;
- loop_ctl = 1;
- skip = 1;
- break;
- } else {
- opt_state = OPT_S_START;
- optTimeout = 1;
- }
- } else {
- opt_state = OPT_S_IDLE;
- return;
- }
- break;
- default:
- printk("optcd: invalid state %d\n", opt_state);
- return;
- } /* case */
- } /* while */
-
- if (!optTimeout--) {
- printk("optcd: timeout in state %d\n", opt_state);
- opt_state = OPT_S_STOP;
- if (optCmd(COMSTOP) < 0)
- return;
- }
-
- SET_TIMER(opt_poll, 1);
-}
-
-
-static void do_optcd_request(void) {
-#ifdef DEBUG_REQUEST
- printk("optcd: do_optcd_request(%ld+%ld)\n",
- CURRENT -> sector, CURRENT -> nr_sectors);
-#endif
- opt_transfer_is_active = 1;
- while (CURRENT_VALID) {
- if (CURRENT->bh) {
- if (!CURRENT->bh->b_lock)
- panic(DEVICE_NAME ": block not locked");
- }
- opt_transfer(); /* First try to transfer block from buffers */
- if (CURRENT -> nr_sectors == 0) {
- end_request(1);
- } else { /* Want to read a block not in buffer */
- opt_buf_out = OPT_NOBUF;
- if (opt_state == OPT_S_IDLE) {
- /* Should this block the request queue?? */
- if (optUpdateToc() < 0) {
- while (CURRENT_VALID)
- end_request(0);
- break;
- }
- /* Start state machine */
- opt_state = OPT_S_START;
- optTries = 5;
- SET_TIMER(opt_poll, 1); /* why not start right away?? */
- }
- break;
- }
- }
- opt_transfer_is_active = 0;
-#ifdef DEBUG_REQUEST
- printk("opt_next_bn:%d opt_buf_in:%d opt_buf_out:%d opt_buf_bn:%d\n",
- opt_next_bn, opt_buf_in, opt_buf_out, opt_buf_bn[opt_buf_in]);
- printk("optcd: do_optcd_request ends\n");
-#endif
-}
-
-
-/* VFS calls */
-
-static int opt_ioctl(struct inode *ip, struct file *fp,
- unsigned int cmd, unsigned long arg) {
- static struct opt_Play_msf opt_Play; /* pause position */
- int err;
-#ifdef DEBUG_VFS
- printk("optcd: starting opt_ioctl, command 0x%x\n", cmd);
-#endif
- if (!ip)
- return -EINVAL;
- if (optGetStatus() < 0)
- return -EIO;
- if ((err = optUpdateToc()) < 0)
- return err;
-
- switch (cmd) {
- case CDROMPAUSE: {
- struct opt_Toc qInfo;
-
- if (optAudioStatus != CDROM_AUDIO_PLAY)
- return -EINVAL;
- if (optGetQChannelInfo(&qInfo) < 0) {
- /* didn't get q channel info */
- optAudioStatus = CDROM_AUDIO_NO_STATUS;
- return 0;
- }
- opt_Play.start = qInfo.diskTime; /* restart point */
- if (optCmd(COMPAUSEON) < 0)
- return -EIO;
- optAudioStatus = CDROM_AUDIO_PAUSED;
- break;
- }
- case CDROMRESUME:
- if (optAudioStatus != CDROM_AUDIO_PAUSED)
- return -EINVAL;
- if (optPlayCmd(COMPLAY, &opt_Play) < 0) {
- optAudioStatus = CDROM_AUDIO_ERROR;
- return -EIO;
- }
- optAudioStatus = CDROM_AUDIO_PLAY;
- break;
- case CDROMPLAYMSF: {
- int st;
- struct cdrom_msf msf;
-
- if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof msf)))
- return st;
- memcpy_fromfs(&msf, (void *) arg, sizeof msf);
- opt_Play.start.min = bin2bcd(msf.cdmsf_min0);
- opt_Play.start.sec = bin2bcd(msf.cdmsf_sec0);
- opt_Play.start.frame = bin2bcd(msf.cdmsf_frame0);
- opt_Play.end.min = bin2bcd(msf.cdmsf_min1);
- opt_Play.end.sec = bin2bcd(msf.cdmsf_sec1);
- opt_Play.end.frame = bin2bcd(msf.cdmsf_frame1);
- if (optPlayCmd(COMPLAY, &opt_Play) < 0) {
- optAudioStatus = CDROM_AUDIO_ERROR;
- return -EIO;
- }
- optAudioStatus = CDROM_AUDIO_PLAY;
- break;
- }
- case CDROMPLAYTRKIND: {
- int st;
- struct cdrom_ti ti;
-
- if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof ti)))
- return st;
- memcpy_fromfs(&ti, (void *) arg, sizeof ti);
- if (ti.cdti_trk0 < DiskInfo.first
- || ti.cdti_trk0 > DiskInfo.last
- || ti.cdti_trk1 < ti.cdti_trk0)
- return -EINVAL;
- if (ti.cdti_trk1 > DiskInfo.last)
- ti.cdti_trk1 = DiskInfo.last;
- opt_Play.start = Toc[ti.cdti_trk0].diskTime;
- opt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
-#ifdef DEBUG_VFS
- printk("optcd: play %02x:%02x.%02x to %02x:%02x.%02x\n",
- opt_Play.start.min,
- opt_Play.start.sec,
- opt_Play.start.frame,
- opt_Play.end.min,
- opt_Play.end.sec,
- opt_Play.end.frame);
-#endif
- if (optPlayCmd(COMPLAY, &opt_Play) < 0) {
- optAudioStatus = CDROM_AUDIO_ERROR;
- return -EIO;
- }
- optAudioStatus = CDROM_AUDIO_PLAY;
- break;
- }
- case CDROMREADTOCHDR: { /* Read the table of contents header. */
- int st;
- struct cdrom_tochdr tocHdr;
-
- if ((st = verify_area(VERIFY_WRITE,(void *)arg,sizeof tocHdr)))
- return st;
- if (!optTocUpToDate)
- optGetDiskInfo();
- tocHdr.cdth_trk0 = DiskInfo.first;
- tocHdr.cdth_trk1 = DiskInfo.last;
- memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr);
- break;
- }
- case CDROMREADTOCENTRY: { /* Read a table of contents entry. */
- int st;
- struct cdrom_tocentry entry;
- struct opt_Toc *tocPtr;
-
- if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof entry)))
- return st;
- if ((st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry)))
- return st;
- memcpy_fromfs(&entry, (void *) arg, sizeof entry);
- if (!optTocUpToDate)
- optGetDiskInfo();
- if (entry.cdte_track == CDROM_LEADOUT)
- tocPtr = &Toc[DiskInfo.last + 1];
- else if (entry.cdte_track > DiskInfo.last
- || entry.cdte_track < DiskInfo.first)
- return -EINVAL;
- else
- tocPtr = &Toc[entry.cdte_track];
- entry.cdte_adr = tocPtr -> ctrl_addr;
- entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4;
- switch (entry.cdte_format) {
- case CDROM_LBA:
- entry.cdte_addr.lba = msf2hsg(&tocPtr -> diskTime);
- break;
- case CDROM_MSF:
- entry.cdte_addr.msf.minute =
- bcd2bin(tocPtr -> diskTime.min);
- entry.cdte_addr.msf.second =
- bcd2bin(tocPtr -> diskTime.sec);
- entry.cdte_addr.msf.frame =
- bcd2bin(tocPtr -> diskTime.frame);
- break;
- default:
- return -EINVAL;
- }
- memcpy_tofs((void *) arg, &entry, sizeof entry);
- break;
- }
- case CDROMSTOP:
- optCmd(COMSTOP);
- optAudioStatus = CDROM_AUDIO_NO_STATUS;
- break;
- case CDROMSTART:
- optCmd(COMCLOSE); /* What else can we do? */
- break;
- case CDROMEJECT:
- optCmd(COMUNLOCK);
- optCmd(COMOPEN);
- break;
- case CDROMVOLCTRL: {
- int st;
- struct cdrom_volctrl volctrl;
-
- if ((st = verify_area(VERIFY_READ, (void *) arg,
- sizeof(volctrl))))
- return st;
- memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
- opt_Play.start.min = 0x10;
- opt_Play.start.sec = 0x32;
- opt_Play.start.frame = volctrl.channel0;
- opt_Play.end.min = volctrl.channel1;
- opt_Play.end.sec = volctrl.channel2;
- opt_Play.end.frame = volctrl.channel3;
- if (optPlayCmd(COMCHCTRL, &opt_Play) < 0)
- return -EIO;
- break;
- }
- case CDROMSUBCHNL: { /* Get subchannel info */
- int st;
- struct cdrom_subchnl subchnl;
- struct opt_Toc qInfo;
-
- if ((st = verify_area(VERIFY_READ,
- (void *) arg, sizeof subchnl)))
- return st;
- if ((st = verify_area(VERIFY_WRITE,
- (void *) arg, sizeof subchnl)))
- return st;
- memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);
- if (optGetQChannelInfo(&qInfo) < 0)
- return -EIO;
- subchnl.cdsc_audiostatus = optAudioStatus;
- subchnl.cdsc_adr = qInfo.ctrl_addr;
- subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
- subchnl.cdsc_trk = bcd2bin(qInfo.track);
- subchnl.cdsc_ind = bcd2bin(qInfo.pointIndex);
- switch (subchnl.cdsc_format) {
- case CDROM_LBA:
- subchnl.cdsc_absaddr.lba = msf2hsg(&qInfo.diskTime);
- subchnl.cdsc_reladdr.lba = msf2hsg(&qInfo.trackTime);
- break;
- case CDROM_MSF:
- subchnl.cdsc_absaddr.msf.minute =
- bcd2bin(qInfo.diskTime.min);
- subchnl.cdsc_absaddr.msf.second =
- bcd2bin(qInfo.diskTime.sec);
- subchnl.cdsc_absaddr.msf.frame =
- bcd2bin(qInfo.diskTime.frame);
- subchnl.cdsc_reladdr.msf.minute =
- bcd2bin(qInfo.trackTime.min);
- subchnl.cdsc_reladdr.msf.second =
- bcd2bin(qInfo.trackTime.sec);
- subchnl.cdsc_reladdr.msf.frame =
- bcd2bin(qInfo.trackTime.frame);
- break;
- default:
- return -EINVAL;
- }
- memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
- break;
- }
- case CDROMREADMODE1: {
- int st;
- struct cdrom_msf msf;
- char buf[OPT_BLOCKSIZE];
-
- if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof msf)))
- return st;
- if ((st = verify_area(VERIFY_WRITE,(void *)arg,OPT_BLOCKSIZE)))
- return st;
- memcpy_fromfs(&msf, (void *) arg, sizeof msf);
- opt_Play.start.min = bin2bcd(msf.cdmsf_min0);
- opt_Play.start.sec = bin2bcd(msf.cdmsf_sec0);
- opt_Play.start.frame = bin2bcd(msf.cdmsf_frame0);
- opt_Play.end.min = 0;
- opt_Play.end.sec = 0;
- opt_Play.end.frame = 1; /* read only one frame */
- st = optReadCmd(COMREAD, &opt_Play);
-#ifdef DEBUG_VFS
- printk("optcd: COMREAD status 0x%x\n", st);
-#endif
- sleep_dten_low(); /* error checking here?? */
- optReadData(buf, OPT_BLOCKSIZE);
- memcpy_tofs((void *) arg, &buf, OPT_BLOCKSIZE);
- break;
- }
- case CDROMMULTISESSION:
- return -EINVAL; /* unluckily, not implemented yet */
-
- default:
- return -EINVAL;
- }
-#ifdef DEBUG_VFS
- printk("optcd: exiting opt_ioctl\n");
-#endif
- return 0;
-}
-
-static int optPresent = 0;
-static int opt_open_count = 0;
-
-/* Open device special file; check that a disk is in. */
-static int opt_open(struct inode *ip, struct file *fp) {
-#ifdef DEBUG_VFS
- printk("optcd: starting opt_open\n");
-#endif
- if (!optPresent)
- return -ENXIO; /* no hardware */
- if (!opt_open_count && opt_state == OPT_S_IDLE) {
- int st;
- opt_invalidate_buffers();
- if ((st = optGetStatus()) < 0)
- return -EIO;
- if (st & ST_DOOR_OPEN) {
- optCmd(COMCLOSE); /* close door */
- if ((st = optGetStatus()) < 0) /* try again */
- return -EIO;
- }
- if (st & (ST_DOOR_OPEN|ST_DRVERR)) {
- printk("optcd: no disk or door open\n");
- return -EIO;
- }
- if (optUpdateToc() < 0)
- return -EIO;
- }
- opt_open_count++;
- MOD_INC_USE_COUNT;
- optCmd(COMLOCK); /* Lock door */
-#ifdef DEBUG_VFS
- printk("optcd: exiting opt_open\n");
-#endif
- return 0;
-}
-
-/* Release device special file; flush all blocks from the buffer cache */
-static void opt_release(struct inode *ip, struct file *fp) {
-#ifdef DEBUG_VFS
- printk("optcd: executing opt_release\n");
- printk("inode: %p, inode -> i_rdev: 0x%x, file: %p\n",
- ip, ip -> i_rdev, fp);
-#endif
- if (!--opt_open_count) {
- opt_invalidate_buffers();
- sync_dev(ip -> i_rdev);
- invalidate_buffers(ip -> i_rdev);
- CLEAR_TIMER;
- optCmd(COMUNLOCK); /* Unlock door */
- }
- MOD_DEC_USE_COUNT;
-}
-
-
-/* Initialisation */
-
-static int version_ok(void) {
- char devname[100];
- int count, i, ch;
-
- if (optCmd(COMVERSION) < 0)
- return 0;
- if ((count = optGetData()) < 0)
- return 0;
- for (i = 0, ch = -1; count > 0; count--) {
- if ((ch = optGetData()) < 0)
- break;
- if (i < 99)
- devname[i++] = ch;
- }
- devname[i] = '\0';
- if (ch < 0)
- return 0;
- printk("optcd: Device %s detected\n", devname);
- return ((devname[0] == 'D')
- && (devname[1] == 'O')
- && (devname[2] == 'L')
- && (devname[3] == 'P')
- && (devname[4] == 'H')
- && (devname[5] == 'I')
- && (devname[6] == 'N'));
-}
-
-
-static struct file_operations opt_fops = {
- NULL, /* lseek - default */
- block_read, /* read - general block-dev read */
- block_write, /* write - general block-dev write */
- NULL, /* readdir - bad */
- NULL, /* select */
- opt_ioctl, /* ioctl */
- NULL, /* mmap */
- opt_open, /* open */
- opt_release, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* media change */
- NULL /* revalidate */
-};
-
-
-/* Get kernel parameter when used as a kernel driver */
-void optcd_setup(char *str, int *ints) {
- if (ints[0] > 0)
- optcd_port = ints[1];
-}
-
-/*
- * Test for presence of drive and initialize it. Called at boot time.
- */
-
-int optcd_init(void) {
- if (optcd_port <= 0) {
- printk("optcd: no Optics Storage CDROM Initialization\n");
- return -EIO;
- }
- if (check_region(optcd_port, 4)) {
- printk("optcd: conflict, I/O port 0x%x already used\n",
- optcd_port);
- return -EIO;
- }
-
- if (!check_region(ISP16_DRIVE_SET_PORT, 5)) {
- /* If someone else has'nt already reserved these ports,
- probe for an ISP16 interface card, and enable SONY mode
- with no interrupts and no DMA. (As far as I know, all optics
- drives come with a SONY interface.) */
- if ( (isp16_type=isp16_detect()) < 0 )
- printk( "No ISP16 cdrom interface found.\n" );
- else {
- u_char expected_drive;
-
- printk( "ISP16 cdrom interface (%s optional IDE) detected.\n",
- (isp16_type==2)?"with":"without" );
-
- expected_drive = (isp16_type?ISP16_SANYO1:ISP16_SANYO0);
-
- if ( isp16_config( optcd_port, ISP16_SONY, 0, 0 ) < 0 ) {
- printk( "ISP16 cdrom interface has not been properly configured.\n" );
- return -EIO;
- }
- }
- }
-
- if (!optResetDrive()) {
- printk("optcd: drive at 0x%x not ready\n", optcd_port);
- return -EIO;
- }
- if (!version_ok()) {
- printk("optcd: unknown drive detected; aborting\n");
- return -EIO;
- }
- if (optCmd(COMINITDOUBLE) < 0) {
- printk("optcd: cannot init double speed mode\n");
- return -EIO;
- }
- if (register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
- {
- printk("optcd: unable to get major %d\n", MAJOR_NR);
- return -EIO;
- }
- blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
- read_ahead[MAJOR_NR] = 4;
- request_region(optcd_port, 4, "optcd");
- optPresent = 1;
- printk("optcd: 8000 AT CDROM at 0x%x\n", optcd_port);
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void) {
- if (MOD_IN_USE) {
- printk("optcd: module in use - can't remove it.\n");
- return;
- }
- if ((unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL)) {
- printk("optcd: what's that: can't unregister\n");
- return;
- }
- release_region(optcd_port, 4);
- printk("optcd: module released.\n");
-}
-#endif MODULE
-
-
-/*
- * -- ISP16 detection and configuration
- *
- * Copyright (c) 1995, Eric van der Maarel <maarel@marin.nl>
- *
- * Version 0.5
- *
- * Detect cdrom interface on ISP16 soundcard.
- * Configure cdrom interface.
- *
- * Algorithm for the card with no IDE support option taken
- * from the CDSETUP.SYS driver for MSDOS,
- * by OPTi Computers, version 2.03.
- * Algorithm for the IDE supporting ISP16 as communicated
- * to me by Vadim Model and Leo Spiekman.
- *
- * Use, modifification or redistribution of this software is
- * allowed under the terms of the GPL.
- *
- */
-
-
-#define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p))
-#define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p))
-
-static short
-isp16_detect(void)
-{
-
- if ( !( isp16_with_ide__detect() < 0 ) )
- return(2);
- else
- return( isp16_no_ide__detect() );
-}
-
-static short
-isp16_no_ide__detect(void)
-{
- u_char ctrl;
- u_char enable_cdrom;
- u_char io;
- short i = -1;
-
- isp16_ctrl = ISP16_NO_IDE__CTRL;
- isp16_enable_cdrom_port = ISP16_NO_IDE__ENABLE_CDROM_PORT;
-
- /* read' and write' are a special read and write, respectively */
-
- /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */
- ctrl = ISP16_IN( ISP16_CTRL_PORT ) & 0xFC;
- ISP16_OUT( ISP16_CTRL_PORT, ctrl );
-
- /* read' 3,4 and 5-bit from the cdrom enable port */
- enable_cdrom = ISP16_IN( ISP16_NO_IDE__ENABLE_CDROM_PORT ) & 0x38;
-
- if ( !(enable_cdrom & 0x20) ) { /* 5-bit not set */
- /* read' last 2 bits of ISP16_IO_SET_PORT */
- io = ISP16_IN( ISP16_IO_SET_PORT ) & 0x03;
- if ( ((io&0x01)<<1) == (io&0x02) ) { /* bits are the same */
- if ( io == 0 ) { /* ...the same and 0 */
- i = 0;
- enable_cdrom |= 0x20;
- }
- else { /* ...the same and 1 */ /* my card, first time 'round */
- i = 1;
- enable_cdrom |= 0x28;
- }
- ISP16_OUT( ISP16_NO_IDE__ENABLE_CDROM_PORT, enable_cdrom );
- }
- else { /* bits are not the same */
- ISP16_OUT( ISP16_CTRL_PORT, ctrl );
- return(i); /* -> not detected: possibly incorrect conclusion */
- }
- }
- else if ( enable_cdrom == 0x20 )
- i = 0;
- else if ( enable_cdrom == 0x28 ) /* my card, already initialised */
- i = 1;
-
- ISP16_OUT( ISP16_CTRL_PORT, ctrl );
-
- return(i);
-}
-
-static short
-isp16_with_ide__detect(void)
-{
- u_char ctrl;
- u_char tmp;
-
- isp16_ctrl = ISP16_IDE__CTRL;
- isp16_enable_cdrom_port = ISP16_IDE__ENABLE_CDROM_PORT;
-
- /* read' and write' are a special read and write, respectively */
-
- /* read' ISP16_CTRL_PORT and save */
- ctrl = ISP16_IN( ISP16_CTRL_PORT );
-
- /* write' zero to the ctrl port and get response */
- ISP16_OUT( ISP16_CTRL_PORT, 0 );
- tmp = ISP16_IN( ISP16_CTRL_PORT );
-
- if ( tmp != 2 ) /* isp16 with ide option not detected */
- return(-1);
-
- /* restore ctrl port value */
- ISP16_OUT( ISP16_CTRL_PORT, ctrl );
-
- return(2);
-}
-
-static short
-isp16_config( int base, u_char drive_type, int irq, int dma )
-{
- u_char base_code;
- u_char irq_code;
- u_char dma_code;
- u_char i;
-
- if ( (drive_type == ISP16_MITSUMI) && (dma != 0) )
- printk( "Mitsumi cdrom drive has no dma support.\n" );
-
- switch (base) {
- case 0x340: base_code = ISP16_BASE_340; break;
- case 0x330: base_code = ISP16_BASE_330; break;
- case 0x360: base_code = ISP16_BASE_360; break;
- case 0x320: base_code = ISP16_BASE_320; break;
- default:
- printk( "Base address 0x%03X not supported by cdrom interface on ISP16.\n", base );
- return(-1);
- }
- switch (irq) {
- case 0: irq_code = ISP16_IRQ_X; break; /* disable irq */
- case 5: irq_code = ISP16_IRQ_5;
- printk( "Irq 5 shouldn't be used by cdrom interface on ISP16,"
- " due to possible conflicts with the soundcard.\n");
- break;
- case 7: irq_code = ISP16_IRQ_7;
- printk( "Irq 7 shouldn't be used by cdrom interface on ISP16,"
- " due to possible conflicts with the soundcard.\n");
- break;
- case 3: irq_code = ISP16_IRQ_3; break;
- case 9: irq_code = ISP16_IRQ_9; break;
- case 10: irq_code = ISP16_IRQ_10; break;
- case 11: irq_code = ISP16_IRQ_11; break;
- default:
- printk( "Irq %d not supported by cdrom interface on ISP16.\n", irq );
- return(-1);
- }
- switch (dma) {
- case 0: dma_code = ISP16_DMA_X; break; /* disable dma */
- case 1: printk( "Dma 1 cannot be used by cdrom interface on ISP16,"
- " due to conflict with the soundcard.\n");
- return(-1); break;
- case 3: dma_code = ISP16_DMA_3; break;
- case 5: dma_code = ISP16_DMA_5; break;
- case 6: dma_code = ISP16_DMA_6; break;
- case 7: dma_code = ISP16_DMA_7; break;
- default:
- printk( "Dma %d not supported by cdrom interface on ISP16.\n", dma );
- return(-1);
- }
-
- if ( drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 &&
- drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 &&
- drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI &&
- drive_type != ISP16_DRIVE_X ) {
- printk( "Drive type (code 0x%02X) not supported by cdrom"
- " interface on ISP16.\n", drive_type );
- return(-1);
- }
-
- /* set type of interface */
- i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK; /* clear some bits */
- ISP16_OUT( ISP16_DRIVE_SET_PORT, i|drive_type );
-
- /* enable cdrom on interface with ide support */
- if ( isp16_type > 1 )
- ISP16_OUT( isp16_enable_cdrom_port, ISP16_ENABLE_CDROM );
-
- /* set base address, irq and dma */
- i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK; /* keep some bits */
- ISP16_OUT( ISP16_IO_SET_PORT, i|base_code|irq_code|dma_code );
-
- return(0);
-}
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