aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@cc.helsinki.fi>1994-01-29 12:57:42 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:30 -0400
commit0ef15e52af53204c01d894863c7bd1bf2ee86cd6 (patch)
tree1b61351d0da736c9632bd44961a027652343c239
parent5924f25a1b43d674b453dbcf9adde23d0bc8c2b2 (diff)
downloadarchive-0ef15e52af53204c01d894863c7bd1bf2ee86cd6.tar.gz
ALPHA-pl14x
-rw-r--r--Makefile2
-rw-r--r--config.in1
-rw-r--r--drivers/block/Makefile8
-rw-r--r--drivers/block/blk.h8
-rw-r--r--drivers/block/ll_rw_blk.c7
-rw-r--r--drivers/block/sbpcd.c2985
-rw-r--r--drivers/char/console.c2
-rw-r--r--drivers/char/tty_ioctl.c15
-rw-r--r--drivers/net/CONFIG44
-rw-r--r--drivers/net/README.839096
-rw-r--r--drivers/net/ne.c10
-rw-r--r--fs/isofs/inode.c10
-rw-r--r--fs/open.c1
-rw-r--r--include/linux/major.h3
-rw-r--r--include/linux/sbpcd.h473
-rw-r--r--include/linux/timer.h4
-rw-r--r--include/linux/tty.h2
-rw-r--r--init/main.c6
-rw-r--r--kernel/ksyms.S4
-rw-r--r--net/inet/ip.c71
-rw-r--r--net/inet/sock.c8
-rw-r--r--net/inet/sock.h8
-rw-r--r--net/inet/tcp.c283
-rw-r--r--net/inet/timer.c7
24 files changed, 3786 insertions, 272 deletions
diff --git a/Makefile b/Makefile
index 564ea92..85ac1c8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 0.99
PATCHLEVEL = 14
-ALPHA = w
+ALPHA = x
all: Version zImage
diff --git a/config.in b/config.in
index 1e7dc95..7867210 100644
--- a/config.in
+++ b/config.in
@@ -87,6 +87,7 @@ fi
*
bool 'Sony CDU31A CDROM driver support' CONFIG_CDU31A n
bool 'Mitsumi CDROM driver support' CONFIG_MCD n
+bool 'Matsushita/Panasonic CDROM driver support' CONFIG_SBPCD n
*
* Filesystems
*
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 253de65..bc0dfc5 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -34,6 +34,14 @@ OBJS := $(OBJS) mcd.o
SRCS := $(SRCS) mcd.c
endif
+ifdef CONFIG_SBPCD
+OBJS := $(OBJS) sbpcd.o
+SRCS := $(SRCS) sbpcd.c
+ifdef PATCHLEVEL
+CFLAGS := $(CFLAGS) -DPATCHLEVEL=$(PATCHLEVEL)
+endif
+endif #CONFIG_SBPCD
+
ifdef CONFIG_BLK_DEV_HD
OBJS := $(OBJS) hd.o
SRCS := $(SRCS) hd.c
diff --git a/drivers/block/blk.h b/drivers/block/blk.h
index 970ba4d..faa5adf 100644
--- a/drivers/block/blk.h
+++ b/drivers/block/blk.h
@@ -189,6 +189,14 @@ static void floppy_off(unsigned int nr);
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
+#elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR)
+
+#define DEVICE_NAME "Matsushita CD-ROM"
+#define DEVICE_REQUEST do_sbpcd_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
#else
#error "unknown blk device"
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 1473621..7ea4f88 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -18,6 +18,10 @@
#include "blk.h"
+#ifdef CONFIG_SBPCD
+extern u_long sbpcd_init(u_long, u_long);
+#endif CONFIG_SBPCD
+
/*
* The request-struct contains all necessary data
* to load a nr of sectors into memory
@@ -485,6 +489,9 @@ long blk_dev_init(long mem_start, long mem_end)
#ifdef CONFIG_MCD
mem_start = mcd_init(mem_start,mem_end);
#endif
+#ifdef CONFIG_SBPCD
+ mem_start = sbpcd_init(mem_start, mem_end);
+#endif CONFIG_SBPCD
if (ramdisk_size)
mem_start += rd_init(mem_start, ramdisk_size*1024);
return mem_start;
diff --git a/drivers/block/sbpcd.c b/drivers/block/sbpcd.c
index e69de29..43df7eb 100644
--- a/drivers/block/sbpcd.c
+++ b/drivers/block/sbpcd.c
@@ -0,0 +1,2985 @@
+/*
+ * sbpcd.c CD-ROM device driver for the whole family of IDE-style
+ * Kotobuki/Matsushita/Panasonic CR-5xx drives for
+ * SoundBlaster ("Pro" or "16 ASP" or compatible) cards
+ * and for "no-sound" interfaces like Lasermate and the
+ * Panasonic CI-101P.
+ *
+ * NOTE: This is release 1.0.
+ * It works with my SbPro & drive CR-521 V2.11 from 2/92
+ * and with the new CR-562-B V0.75 on a "naked" Panasonic
+ * CI-101P interface. And vice versa.
+ *
+ *
+ * VERSION HISTORY
+ *
+ * 0.1 initial release, April/May 93, after mcd.c
+ *
+ * 0.2 the "repeat:"-loop in do_sbpcd_request did not check for
+ * end-of-request_queue (resulting in kernel panic).
+ * Flow control seems stable, but throughput is not better.
+ *
+ * 0.3 interrupt locking totally eliminated (maybe "inb" and "outb"
+ * are still locking) - 0.2 made keyboard-type-ahead losses.
+ * check_sbpcd_media_change added (to use by isofs/inode.c)
+ * - but it detects almost nothing.
+ *
+ * 0.4 use MAJOR 25 definitely.
+ * Almost total re-design to support double-speed drives and
+ * "naked" (no sound) interface cards.
+ * Flow control should be exact now (tell me if not).
+ * Don't occupy the SbPro IRQ line (not needed either); will
+ * live together with Hannu Savolainen's sndkit now.
+ * Speeded up data transfer to 150 kB/sec, with help from Kai
+ * Makisara, the "provider" of the "mt" tape utility.
+ * Give "SpinUp" command if necessary.
+ * First steps to support up to 4 drives (but currently only one).
+ * Implemented audio capabilities - workman should work, xcdplayer
+ * gives some problems.
+ * This version is still consuming too much CPU time, and
+ * sleeping still has to be worked on.
+ * During "long" implied seeks, it seems possible that a
+ * ReadStatus command gets ignored. That gives the message
+ * "ResponseStatus timed out" (happens about 6 times here during
+ * a "ls -alR" of the YGGDRASIL LGX-Beta CD). Such a case is
+ * handled without data error, but it should get done better.
+ *
+ * 0.5 Free CPU during waits (again with help from Kai Makisara).
+ * Made it work together with the LILO/kernel setup standard.
+ * Included auto-probing code, as suggested by YGGDRASIL.
+ * Formal redesign to add DDI debugging.
+ * There are still flaws in IOCTL (workman with double speed drive).
+ *
+ * 1.0 Added support for all drive ids (0...3, no longer only 0)
+ * and up to 4 drives on one controller.
+ * Added "#define MANY_SESSION" for "old" multi session CDs.
+ *
+ * 1.1 Do SpinUp for new drives, too.
+ * Revised for clean compile under "old" kernels (pl9).
+ *
+ * special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine
+ * elaborated speed-up experiments (and the fabulous results!), for
+ * the "push" towards load-free wait loops, and for the extensive mail
+ * thread which brought additional hints and bug fixes.
+ *
+ *
+ * Copyright (C) 1993, 1994 Eberhard Moenkeberg <emoenke@gwdg.de>
+ * or <eberhard_moenkeberg@rollo.central.de>
+ *
+ * The FTP-home of this driver is
+ * ftp.gwdg.de:/pub/linux/cdrom/drivers/sbpcd/.
+ * I will serve tsx-11.mit.edu, sunsite.unc.edu and
+ * ftp.funet.fi, too.
+ *
+ *
+ * If you change this software, you should mail a .diff
+ * file with some description lines to emoenke.gwdg.de.
+ * I want to know about it.
+ *
+ * If you are the editor of a Linux CD, you should
+ * add sbpcd.c into 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef PATCHLEVEL
+#define PATCHLEVEL 9
+#endif
+
+#include <linux/config.h>
+#include <linux/errno.h>
+
+#if SBPCD_USE_IRQ
+#include <linux/signal.h>
+#endif SBPCD_USE_IRQ
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/cdrom.h>
+#include <linux/ioport.h>
+#include <linux/sbpcd.h>
+
+#if PATCHLEVEL>13
+#include <linux/ddi.h>
+#include <linux/major.h>
+#else
+#define DDIOCSDBG 0x9000
+#define MATSUSHITA_CDROM_MAJOR 25
+#endif
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <stdarg.h>
+
+#define MAJOR_NR MATSUSHITA_CDROM_MAJOR
+#include "blk.h"
+
+#define VERSION "1.1"
+
+#define SBPCD_DEBUG
+
+#ifndef CONFIG_SBPCD
+#error "SBPCD: \"make config\" again. Enable Matsushita/Panasonic CDROM support"
+#endif
+
+#ifndef CONFIG_ISO9660_FS
+#error "SBPCD: \"make config\" again. File system iso9660 is necessary."
+#endif
+
+/*
+ * still testing around...
+ */
+#define MANY_SESSION 0
+#define CDMKE
+#undef FUTURE
+#define WORKMAN 1 /* some testing stuff to make it better */
+
+/*==========================================================================*/
+/*==========================================================================*/
+/*
+ * auto-probing address list
+ * inspired by Adam J. Richter from Yggdrasil
+ *
+ * still not good enough - can cause a hang.
+ * example: a NE 2000 ehernet card at 300 will cause a hang probing 310.
+ * if that happens, reboot and use the LILO (kernel) command line.
+ * the conflicting possible ethernet card addresses get probed last - to
+ * minimize the hang possibilities.
+ *
+ * The SB Pro addresses get "mirrored" at 0x6xx - to avoid a type error,
+ * the 0x2xx-addresses must get checked before 0x6xx.
+ *
+ * what are other cards' default and range ???
+ * what about ESCOM PowerSound???
+ * what about HighScreen???
+ */
+static int autoprobe[] =
+{
+ CDROM_PORT, SBPRO, /* probe with user's setup first */
+ 0x230, 1, /* Soundblaster Pro and 16 (default) */
+ 0x300, 0, /* CI-101P (default), Galaxy (default), Reveal (one default) */
+ 0x250, 1, /* OmniCD default, Soundblaster Pro and 16 */
+ 0x260, 1, /* OmniCD */
+ 0x320, 0, /* Lasermate, CI-101P, Galaxy, Reveal (other default) */
+ 0x340, 0, /* Lasermate, CI-101P */
+ 0x360, 0, /* Lasermate, CI-101P */
+ 0x270, 1, /* Soundblaster 16 */
+ 0x630, 0, /* "sound card #9" (default) */
+ 0x650, 0, /* "sound card #9" */
+ 0x670, 0, /* "sound card #9" */
+ 0x690, 0, /* "sound card #9" */
+ 0x330, 0, /* Lasermate, CI-101P */
+ 0x350, 0, /* Lasermate, CI-101P */
+ 0x370, 0, /* Lasermate, CI-101P */
+ 0x290, 1, /* Soundblaster 16 */
+ 0x310, 0, /* Lasermate, CI-101P */
+};
+
+#define NUM_AUTOPROBE (sizeof(autoprobe) / sizeof(int))
+
+
+/*==========================================================================*/
+/*
+ * the forward references:
+ */
+static void sbp_read_cmd(void);
+static int sbp_data(void);
+
+/*==========================================================================*/
+
+/*
+ * pattern for printk selection:
+ *
+ * (1<<DBG_INF) necessary information
+ * (1<<DBG_IRQ) interrupt trace
+ * (1<<DBG_REA) "read" status trace
+ * (1<<DBG_CHK) "media check" trace
+ * (1<<DBG_TIM) datarate timer test
+ * (1<<DBG_INI) initialization trace
+ * (1<<DBG_TOC) tell TocEntry values
+ * (1<<DBG_IOC) ioctl trace
+ * (1<<DBG_STA) "ResponseStatus" trace
+ * (1<<DBG_ERR) "xx_ReadError" trace
+ * (1<<DBG_CMD) "cmd_out" trace
+ * (1<<DBG_WRN) give explanation before auto-probing
+ * (1<<DBG_MUL) multi session code test
+ * (1<<DBG_ID) "drive_id != 0" test code
+ * (1<<DBG_IOX) some special information
+ * (1<<DBG_DID) drive ID test
+ * (1<<DBG_RES) drive reset info
+ * (1<<DBG_SPI) SpinUp test info
+ * (1<<DBG_000) unnecessary information
+ */
+#if 1
+static int sbpcd_debug = (1<<DBG_INF) | (1<<DBG_WRN);
+#else
+static int sbpcd_debug = (1<<DBG_INF) |
+ (1<<DBG_TOC) |
+ (1<<DBG_IOX);
+#endif
+static int sbpcd_ioaddr = CDROM_PORT; /* default I/O base address */
+static int sbpro_type = SBPRO;
+static int CDo_command, CDo_reset;
+static int CDo_sel_d_i, CDo_enable;
+static int CDi_info, CDi_status, CDi_data;
+static int MIXER_addr, MIXER_data;
+static struct cdrom_msf msf;
+static struct cdrom_ti ti;
+static struct cdrom_tochdr tochdr;
+static struct cdrom_tocentry tocentry;
+static struct cdrom_subchnl SC;
+static struct cdrom_volctrl volctrl;
+char *str_sb = "SoundBlaster";
+char *str_lm = "LaserMate";
+char *type;
+
+/*==========================================================================*/
+
+#if FUTURE
+static struct wait_queue *sbp_waitq = NULL;
+#endif FUTURE
+
+/*==========================================================================*/
+
+#define SBP_BUFFER_FRAMES 4 /* driver's own read_ahead */
+
+/*==========================================================================*/
+
+static u_char drive_family[]="CR-5";
+static u_char drive_vendor[]="MATSHITA";
+
+static u_int response_count=0;
+static u_int flags_cmd_out;
+static u_char cmd_type=0;
+static u_char drvcmd[7];
+static u_char infobuf[20];
+
+static u_char timed_out=0;
+static u_int datarate= 1000000;
+static u_int maxtim16=16000000;
+static u_int maxtim04= 4000000;
+static u_int maxtim02= 2000000;
+static u_int maxtim_8= 30000;
+#if MANY_SESSION
+static u_int maxtim_data= 9000;
+#else
+static u_int maxtim_data= 3000;
+#endif MANY_SESSION
+
+/*==========================================================================*/
+
+static int ndrives=0;
+static u_char drv_pattern[4]={ 0x80, 0x80, 0x80, 0x80 }; /* auto speed */
+/* /X:... drv_pattern[0] |= (sax_n1|sax_n2); */
+/* /A:... for (i=0;i<4;i++) drv_pattern[i] |= sax_a; */
+/* /N:... ndrives=i-'0'; */
+
+/*==========================================================================*/
+/*
+ * drive space begins here (needed separate for each unit)
+ */
+static int d=0; /* DS index: drive number */
+
+static struct {
+ char drv_minor; /* minor number or -1 */
+
+ char drive_model[4];
+ char firmware_version[4];
+ u_char *sbp_buf; /* Pointer to internal data buffer,
+ space allocated during sbpcd_init() */
+ int sbp_first_frame; /* First frame in buffer */
+ int sbp_last_frame; /* Last frame in buffer */
+ int sbp_read_frames; /* Number of frames being read to buffer */
+ int sbp_current; /* Frame being currently read */
+
+ u_char drv_type;
+ u_char drv_options;
+ u_char status_byte;
+ u_char diskstate_flags;
+ u_char sense_byte;
+
+ u_char CD_changed;
+
+ u_char error_byte;
+
+ u_char f_multisession;
+ u_int lba_multi;
+
+ u_char audio_state;
+ u_int pos_audio_start;
+ u_int pos_audio_end;
+ char vol_chan0;
+ u_char vol_ctrl0;
+ char vol_chan1;
+ u_char vol_ctrl1;
+#if 000
+ char vol_chan2;
+ u_char vol_ctrl2;
+ char vol_chan3;
+ u_char vol_ctrl3;
+#endif 000
+
+ u_char SubQ_audio;
+ u_char SubQ_ctl_adr;
+ u_char SubQ_trk;
+ u_char SubQ_pnt_idx;
+ u_int SubQ_run_tot;
+ u_int SubQ_run_trk;
+ u_char SubQ_whatisthis;
+
+ u_char UPC_ctl_adr;
+ u_char UPC_buf[7];
+
+ int CDsize_blk;
+ int frame_size;
+ int CDsize_frm;
+
+ u_char xa_byte; /* 0x20: XA capabilities */
+ u_char n_first_track; /* binary */
+ u_char n_last_track; /* binary (not bcd), 0x01...0x63 */
+ u_int size_msf; /* time of whole CD, position of LeadOut track */
+ u_int size_blk;
+
+ u_char TocEnt_nixbyte; /* em */
+ u_char TocEnt_ctl_adr;
+ u_char TocEnt_number;
+ u_char TocEnt_format; /* em */
+ u_int TocEnt_address;
+ u_char ored_ctl_adr; /* to detect if CDROM contains data tracks */
+
+ struct {
+ u_char nixbyte; /* em */
+ u_char ctl_adr; /* 0x4x: data, 0x0x: audio */
+ u_char number;
+ u_char format; /* em */ /* 0x00: lba, 0x01: msf */
+ u_int address;
+ } TocBuffer[MAX_TRACKS+1]; /* last entry faked */
+
+ int in_SpinUp;
+
+} DS[4];
+
+/*
+ * drive space ends here (needed separate for each unit)
+ */
+
+/*==========================================================================*/
+/*==========================================================================*/
+/*
+ * DDI interface definitions
+ */
+#ifdef SBPCD_DEBUG
+# define DPRINTF(x) sbpcd_dprintf x
+
+void sbpcd_dprintf(int level, char *fmt, ...)
+{
+ char buff[256];
+ va_list args;
+ extern int vsprintf(char *buf, const char *fmt, va_list args);
+
+ if (! (sbpcd_debug & (1 << level))) return;
+
+ va_start(args, fmt);
+ vsprintf(buff, fmt, args);
+ va_end(args);
+ printk(buff);
+}
+
+#else
+# define DPRINTF(x) /* nothing */
+
+#endif SBPCD_DEBUG
+
+/*
+ * maintain trace bit pattern
+ */
+static int sbpcd_dbg_ioctl(unsigned long arg, int level)
+{
+ int val;
+
+ val = get_fs_long((int *) arg);
+ switch(val)
+ {
+ case 0: /* OFF */
+ sbpcd_debug = 0;
+ break;
+
+ default:
+ if (val >= 128) sbpcd_debug &= ~(1 << (val - 128));
+ else sbpcd_debug |= (1 << val);
+ }
+ return(0);
+}
+
+
+/*==========================================================================*/
+/*==========================================================================*/
+/*
+ * Wait a little while (used for polling the drive). If in initialization,
+ * setting a timeout doesn't work, so just loop for a while.
+ */
+static inline void sbp_sleep(u_int jifs)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + jifs;
+ schedule();
+}
+
+/*==========================================================================*/
+/*==========================================================================*/
+/*
+ * convert logical_block_address to m-s-f_number (3 bytes only)
+ */
+static void lba2msf(int lba, u_char *msf)
+{
+ lba += CD_BLOCK_OFFSET;
+ msf[0] = lba / (CD_SECS*CD_FRAMES);
+ lba %= CD_SECS*CD_FRAMES;
+ msf[1] = lba / CD_FRAMES;
+ msf[2] = lba % CD_FRAMES;
+}
+/*==========================================================================*/
+/*==========================================================================*/
+/*
+ * convert msf-bin to msf-bcd
+ */
+static void bin2bcdx(u_char *p) /* must work only up to 75 or 99 */
+{
+ *p=((*p/10)<<4)|(*p%10);
+}
+/*==========================================================================*/
+static u_int blk2msf(u_int blk)
+{
+ MSF msf;
+ u_int mm;
+
+ msf.c[3] = 0;
+ msf.c[2] = (blk + CD_BLOCK_OFFSET) / (CD_SECS * CD_FRAMES);
+ mm = (blk + CD_BLOCK_OFFSET) % (CD_SECS * CD_FRAMES);
+ msf.c[1] = mm / CD_FRAMES;
+ msf.c[0] = mm % CD_FRAMES;
+ return (msf.n);
+}
+/*==========================================================================*/
+static u_int make16(u_char rh, u_char rl)
+{
+ return ((rh<<8)|rl);
+}
+/*==========================================================================*/
+static u_int make32(u_int rh, u_int rl)
+{
+ return ((rh<<16)|rl);
+}
+/*==========================================================================*/
+static u_char swap_nibbles(u_char i)
+{
+ return ((i<<4)|(i>>4));
+}
+/*==========================================================================*/
+static u_char byt2bcd(u_char i)
+{
+ return (((i/10)<<4)+i%10);
+}
+/*==========================================================================*/
+static u_char bcd2bin(u_char bcd)
+{
+ return ((bcd>>4)*10+(bcd&0x0F));
+}
+/*==========================================================================*/
+static int msf2blk(int msfx)
+{
+ MSF msf;
+ int i;
+
+ msf.n=msfx;
+ i=(msf.c[2] * CD_SECS + msf.c[1]) * CD_FRAMES + msf.c[0] - CD_BLOCK_OFFSET;
+ if (i<0) return (0);
+ return (i);
+}
+/*==========================================================================*/
+/* evaluate xx_ReadError code (still mysterious) */
+static int sta2err(int sta)
+{
+ if (sta<=2) return (sta);
+ if (sta==0x05) return (-4);
+ if (sta==0x06) return (-6);
+ if (sta==0x0d) return (-6);
+ if (sta==0x0e) return (-3);
+ if (sta==0x14) return (-3);
+ if (sta==0x0c) return (-11);
+ if (sta==0x0f) return (-11);
+ if (sta==0x10) return (-11);
+ if (sta>=0x16) return (-12);
+ DS[d].CD_changed=0xFF;
+ if (sta==0x11) return (-15);
+ return (-2);
+}
+/*==========================================================================*/
+static void clr_cmdbuf(void)
+{
+ int i;
+
+ for (i=0;i<7;i++) drvcmd[i]=0;
+ cmd_type=0;
+}
+/*==========================================================================*/
+static void mark_timeout(void)
+{
+ timed_out=1;
+ DPRINTF((DBG_TIM,"SBPCD: timer stopped.\n"));
+}
+/*==========================================================================*/
+static void flush_status(void)
+{
+#ifdef CDMKE
+ int i;
+
+ if (current == task[0])
+ for (i=maxtim02;i!=0;i--) inb(CDi_status);
+ else
+ {
+ sbp_sleep(150);
+ for (i=maxtim_data;i!=0;i--) inb(CDi_status);
+ }
+#else
+ timed_out=0;
+ SET_TIMER(mark_timeout,150);
+ do { }
+ while (!timed_out);
+ CLEAR_TIMER;
+ inb(CDi_status);
+#endif CDMKE
+}
+/*==========================================================================*/
+static int CDi_stat_loop(void)
+{
+ int i,j;
+ u_long timeout;
+
+ if (current == task[0])
+ for(i=maxtim16;i!=0;i--)
+ {
+ j=inb(CDi_status);
+ if (!(j&s_not_data_ready)) return (j);
+ if (!(j&s_not_result_ready)) return (j);
+ if (!new_drive) if (j&s_attention) return (j);
+ }
+ else
+ for(timeout = jiffies + 1000, i=maxtim_data; timeout > jiffies; )
+ {
+ for ( ;i!=0;i--)
+ {
+ j=inb(CDi_status);
+ if (!(j&s_not_data_ready)) return (j);
+ if (!(j&s_not_result_ready)) return (j);
+ if (!new_drive) if (j&s_attention) return (j);
+ }
+ sbp_sleep(1);
+ i = 1;
+ }
+ return (-1);
+}
+/*==========================================================================*/
+static int ResponseInfo(void)
+{
+ int i,j, st=0;
+ u_long timeout;
+
+ if (current == task[0])
+ for (i=0;i<response_count;i++)
+ {
+ for (j=maxtim_8;j!=0;j--)
+ {
+ st=inb(CDi_status);
+ if (!(st&s_not_result_ready)) break;
+ }
+ if (j==0) return (-1);
+ infobuf[i]=inb(CDi_info);
+ }
+ else
+ {
+ for (i=0, timeout = jiffies + 100; i < response_count; i++)
+ {
+ for (j=maxtim_data; ; )
+ {
+ for ( ;j!=0;j-- )
+ {
+ st=inb(CDi_status);
+ if (!(st&s_not_result_ready)) break;
+ }
+ if (j != 0 || timeout <= jiffies) break;
+ sbp_sleep(0);
+ j = 1;
+ }
+ if (timeout <= jiffies) return (-1);
+ infobuf[i]=inb(CDi_info);
+ }
+ }
+ return (0);
+}
+/*==========================================================================*/
+static int EvaluateStatus(int st)
+{
+ if (!new_drive)
+ {
+ DS[d].status_byte=0;
+ if (st&p_caddin_old) DS[d].status_byte |= p_door_closed|p_caddy_in;
+ if (st&p_spinning) DS[d].status_byte |= p_spinning;
+ if (st&p_check) DS[d].status_byte |= p_check;
+ if (st&p_busy_old) DS[d].status_byte |= p_busy_new;
+ if (st&p_disk_ok) DS[d].status_byte |= p_disk_ok;
+ }
+ else { DS[d].status_byte=st;
+ st=p_success_old; /* for new drives: fake "successful" bit of old drives */
+ }
+ return (st);
+}
+/*==========================================================================*/
+static int ResponseStatus(void)
+{
+ int i,j;
+ u_long timeout;
+
+ DPRINTF((DBG_STA,"SBPCD: doing ResponseStatus...\n"));
+
+ if (current == task[0])
+ {
+ if (flags_cmd_out & f_respo3) j = maxtim_8;
+ else if (flags_cmd_out&f_respo2) j=maxtim16;
+ else j=maxtim04;
+ for (;j!=0;j--)
+ {
+ i=inb(CDi_status);
+ if (!(i&s_not_result_ready)) break;
+ }
+ }
+ else
+ {
+ if (flags_cmd_out & f_respo3) timeout = jiffies;
+ else if (flags_cmd_out & f_respo2) timeout = jiffies + 1600;
+ else timeout = jiffies + 400;
+ j=maxtim_8;
+ do
+ {
+ for ( ;j!=0;j--)
+ {
+ i=inb(CDi_status);
+ if (!(i&s_not_result_ready)) break;
+ }
+ if (j != 0 || timeout <= jiffies) break;
+ sbp_sleep(0);
+ j = 1;
+ }
+ while (1);
+ }
+ if (j==0)
+ { if ((flags_cmd_out & f_respo3) == 0)
+ DPRINTF((DBG_STA,"SBPCD: ResponseStatus: timeout.\n"));
+ EvaluateStatus(0);
+ return (-1);
+ }
+ i=inb(CDi_info);
+ i=EvaluateStatus(i);
+ return (i);
+}
+/*==========================================================================*/
+static void xx_ReadStatus(void)
+{
+ int i;
+
+ DPRINTF((DBG_STA,"SBPCD: giving xx_ReadStatus command\n"));
+
+ if (!new_drive) OUT(CDo_command,0x81);
+ else
+ {
+#if SBPCD_DIS_IRQ
+ cli();
+#endif SBPCD_DIS_IRQ
+ OUT(CDo_command,0x05);
+ for (i=0;i<6;i++) OUT(CDo_command,0);
+#if SBPCD_DIS_IRQ
+ sti();
+#endif SBPCD_DIS_IRQ
+ }
+}
+/*==========================================================================*/
+int xx_ReadError(void)
+{
+ int cmd_out(void);
+ int i;
+
+ clr_cmdbuf();
+ DPRINTF((DBG_ERR,"SBPCD: giving xx_ReadError command.\n"));
+ if (new_drive)
+ {
+ drvcmd[0]=0x82;
+ response_count=8;
+ flags_cmd_out=f_putcmd|f_ResponseStatus;
+ }
+ else
+ {
+ drvcmd[0]=0x82;
+ response_count=6;
+ flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus;
+ }
+ i=cmd_out();
+ DS[d].error_byte=0;
+ DPRINTF((DBG_ERR,"SBPCD: xx_ReadError: cmd_out(82) returns %d (%02X)\n",i,i));
+ if (i<0) return (i);
+ if (new_drive) i=2;
+ else i=1;
+ DS[d].error_byte=infobuf[i];
+ DPRINTF((DBG_ERR,"SBPCD: xx_ReadError: infobuf[%d] is %d (%02X)\n",i,DS[d].error_byte,DS[d].error_byte));
+ i=sta2err(infobuf[i]);
+ return (i);
+}
+/*==========================================================================*/
+int cmd_out(void)
+{
+ int i=0;
+
+ if (flags_cmd_out&f_putcmd)
+ {
+ DPRINTF((DBG_CMD,"SBPCD: cmd_out: put"));
+ for (i=0;i<7;i++) DPRINTF((DBG_CMD," %02X",drvcmd[i]));
+ DPRINTF((DBG_CMD,"\n"));
+
+#if SBPCD_DIS_IRQ
+ cli();
+#endif SBPCD_DIS_IRQ
+ for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
+#if SBPCD_DIS_IRQ
+ sti();
+#endif SBPCD_DIS_IRQ
+ }
+ if (response_count!=0)
+ {
+ if (cmd_type!=0)
+ {
+ if (sbpro_type) OUT(CDo_sel_d_i,0x01);
+ DPRINTF((DBG_INF,"SBPCD: misleaded to try ResponseData.\n"));
+ if (sbpro_type) OUT(CDo_sel_d_i,0x00);
+ }
+ else i=ResponseInfo();
+ if (i<0) return (-9);
+ }
+ if (DS[d].in_SpinUp != 0) DPRINTF((DBG_SPI,"SBPCD: to CDi_stat_loop.\n"));
+ if (flags_cmd_out&f_lopsta)
+ {
+ i=CDi_stat_loop();
+ if ((i<0)||!(i&s_attention)) return (-9);
+ }
+ if (!(flags_cmd_out&f_getsta)) goto LOC_229;
+
+LOC_228:
+ if (DS[d].in_SpinUp != 0) DPRINTF((DBG_SPI,"SBPCD: to xx_ReadStatus.\n"));
+ xx_ReadStatus();
+
+LOC_229:
+ if (flags_cmd_out&f_ResponseStatus)
+ {
+ if (DS[d].in_SpinUp != 0) DPRINTF((DBG_SPI,"SBPCD: to ResponseStatus.\n"));
+ i=ResponseStatus();
+ /* builds status_byte, returns orig. status or p_busy_new */
+ if (i<0) return (-9);
+ if (flags_cmd_out&(f_bit1|f_wait_if_busy))
+ {
+ if (!st_check)
+ {
+ if (flags_cmd_out&f_bit1) if (i&p_success_old) goto LOC_232;
+ if (!(flags_cmd_out&f_wait_if_busy)) goto LOC_228;
+ if (!st_busy) goto LOC_228;
+ }
+ }
+ }
+LOC_232:
+ if (!(flags_cmd_out&f_obey_p_check)) return (0);
+ if (!st_check) return (0);
+ if (DS[d].in_SpinUp != 0) DPRINTF((DBG_SPI,"SBPCD: to xx_ReadError.\n"));
+ i=xx_ReadError();
+ if (DS[d].in_SpinUp != 0) DPRINTF((DBG_SPI,"SBPCD: to cmd_out OK.\n"));
+ return (i);
+}
+/*==========================================================================*/
+static int xx_Seek(u_int pos, char f_blk_msf)
+{
+ int i;
+
+ clr_cmdbuf();
+ if (f_blk_msf>1) return (-3);
+ if (!new_drive)
+ {
+ if (f_blk_msf==1) pos=msf2blk(pos);
+ drvcmd[2]=(pos>>16)&0x00FF;
+ drvcmd[3]=(pos>>8)&0x00FF;
+ drvcmd[4]=pos&0x00FF;
+ flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta |
+ f_ResponseStatus | f_obey_p_check | f_bit1;
+ }
+ else
+ {
+ if (f_blk_msf==0) pos=blk2msf(pos);
+ drvcmd[1]=(pos>>16)&0x00FF;
+ drvcmd[2]=(pos>>8)&0x00FF;
+ drvcmd[3]=pos&0x00FF;
+ flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
+ }
+ drvcmd[0]=0x01;
+ response_count=0;
+ i=cmd_out();
+ return (i);
+}
+/*==========================================================================*/
+static int xx_SpinUp(void)
+{
+ int i;
+
+ DPRINTF((DBG_SPI,"SBPCD: SpinUp.\n"));
+ DS[d].in_SpinUp = 1;
+ clr_cmdbuf();
+ if (!new_drive)
+ {
+ drvcmd[0]=0x05;
+ flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
+ }
+ else
+ {
+ drvcmd[0]=0x02;
+ flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
+ }
+ response_count=0;
+ i=cmd_out();
+ DS[d].in_SpinUp = 0;
+ return (i);
+}
+/*==========================================================================*/
+static int yy_SpinDown(void)
+{
+ int i;
+
+ if (!new_drive) return (-3);
+ clr_cmdbuf();
+ drvcmd[0]=0x06;
+ flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
+ response_count=0;
+ i=cmd_out();
+ return (i);
+}
+/*==========================================================================*/
+static int yy_SetSpeed(u_char speed, u_char x1, u_char x2)
+{
+ int i;
+
+ if (!new_drive) return (-3);
+ clr_cmdbuf();
+ drvcmd[0]=0x09;
+ drvcmd[1]=0x03;
+ drvcmd[2]=speed;
+ drvcmd[3]=x1;
+ drvcmd[4]=x2;
+ flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+ response_count=0;
+ i=cmd_out();
+ return (i);
+}
+/*==========================================================================*/
+static int xx_SetVolume(void)
+{
+ int i;
+ u_char channel0,channel1,volume0,volume1;
+ u_char control0,value0,control1,value1;
+
+ DS[d].diskstate_flags &= ~volume_bit;
+ clr_cmdbuf();
+ channel0=DS[d].vol_chan0;
+ volume0=DS[d].vol_ctrl0;
+ channel1=control1=DS[d].vol_chan1;
+ volume1=value1=DS[d].vol_ctrl1;
+ control0=value0=0;
+
+ if (((DS[d].drv_options&sax_a)!=0)&&(DS[d].drv_type>=drv_211))
+ {
+ if ((volume0!=0)&&(volume1==0))
+ {
+ volume1=volume0;
+ channel1=channel0;
+ }
+ else if ((volume0==0)&&(volume1!=0))
+ {
+ volume0=volume1;
+ channel0=channel1;
+ }
+ }
+ if (channel0>1)
+ {
+ channel0=0;
+ volume0=0;
+ }
+ if (channel1>1)
+ {
+ channel1=1;
+ volume1=0;
+ }
+
+ if (new_drive)
+ {
+ control0=channel0+1;
+ control1=channel1+1;
+ value0=(volume0>volume1)?volume0:volume1;
+ value1=value0;
+ if (volume0==0) control0=0;
+ if (volume1==0) control1=0;
+ drvcmd[0]=0x09;
+ drvcmd[1]=0x05;
+ drvcmd[3]=control0;
+ drvcmd[4]=value0;
+ drvcmd[5]=control1;
+ drvcmd[6]=value1;
+ flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+ }
+ else
+ {
+ if (DS[d].drv_type>=drv_300)
+ {
+ control0=volume0&0xFC;
+ value0=volume1&0xFC;
+ if ((volume0!=0)&&(volume0<4)) control0 |= 0x04;
+ if ((volume1!=0)&&(volume1<4)) value0 |= 0x04;
+ if (channel0!=0) control0 |= 0x01;
+ if (channel1==1) value0 |= 0x01;
+ }
+ else
+ {
+ value0=(volume0>volume1)?volume0:volume1;
+ if (DS[d].drv_type<drv_211)
+ {
+ if (channel0!=0)
+ {
+ i=channel1;
+ channel1=channel0;
+ channel0=i;
+ i=volume1;
+ volume1=volume0;
+ volume0=i;
+ }
+ if (channel0==channel1)
+ {
+ if (channel0==0)
+ {
+ channel1=1;
+ volume1=0;
+ volume0=value0;
+ }
+ else
+ {
+ channel0=0;
+ volume0=0;
+ volume1=value0;
+ }
+ }
+ }
+
+ if ((volume0!=0)&&(volume1!=0))
+ {
+ if (volume0==0xFF) volume1=0xFF;
+ else if (volume1==0xFF) volume0=0xFF;
+ }
+ else if (DS[d].drv_type<drv_201) volume0=volume1=value0;
+
+ if (DS[d].drv_type>=drv_201)
+ {
+ if (volume0==0) control0 |= 0x80;
+ if (volume1==0) control0 |= 0x40;
+ }
+ if (DS[d].drv_type>=drv_211)
+ {
+ if (channel0!=0) control0 |= 0x20;
+ if (channel1!=1) control0 |= 0x10;
+ }
+ }
+ drvcmd[0]=0x84;
+ drvcmd[1]=0x83;
+ drvcmd[4]=control0;
+ drvcmd[5]=value0;
+ flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+ }
+
+ response_count=0;
+ i=cmd_out();
+ if (i>0) return (i);
+ DS[d].diskstate_flags |= volume_bit;
+ return (0);
+}
+/*==========================================================================*/
+static int GetStatus(void)
+{
+ int i;
+
+ flags_cmd_out=f_getsta|f_ResponseStatus|f_obey_p_check;
+ response_count=0;
+ cmd_type=0;
+ i=cmd_out();
+ return (i);
+}
+/*==========================================================================*/
+static int xy_DriveReset(void)
+{
+ int i;
+
+ DPRINTF((DBG_RES,"SBPCD: xy_DriveReset called.\n"));
+ if (!new_drive) OUT(CDo_reset,0x00);
+ else
+ {
+ clr_cmdbuf();
+ drvcmd[0]=0x0A;
+ flags_cmd_out=f_putcmd;
+ response_count=0;
+ i=cmd_out();
+ }
+ flush_status();
+ i=GetStatus();
+ if (i>=0) return -1;
+ if (DS[d].error_byte!=aud_12) return -1;
+ return (0);
+}
+/*==========================================================================*/
+static int SetSpeed(void)
+{
+ int i, speed;
+
+ if (!(DS[d].drv_options&(speed_auto|speed_300|speed_150))) return (0);
+ speed=0x80;
+ if (!(DS[d].drv_options&speed_auto))
+ {
+ speed |= 0x40;
+ if (!(DS[d].drv_options&speed_300)) speed=0;
+ }
+ i=yy_SetSpeed(speed,0,0);
+ return (i);
+}
+/*==========================================================================*/
+static int DriveReset(void)
+{
+ int i;
+
+ i=xy_DriveReset();
+ if (i<0) return (-2);
+ do
+ {
+ i=GetStatus();
+ if ((i<0)&&(i!=-15)) return (-2); /* i!=-15 is from sta2err */
+ if (!st_caddy_in) break;
+ }
+ while (!st_diskok);
+ DS[d].CD_changed=1;
+ i=SetSpeed();
+ if (i<0) return (-2);
+ return (0);
+}
+/*==========================================================================*/
+static int xx_Pause_Resume(int pau_res)
+{
+ int i;
+
+ clr_cmdbuf();
+ if (new_drive)
+ {
+ drvcmd[0]=0x0D;
+ flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
+ }
+ else
+ {
+ drvcmd[0]=0x8D;
+ flags_cmd_out=f_putcmd|f_respo2|f_getsta|f_ResponseStatus|f_obey_p_check;
+ }
+ if (pau_res!=1) drvcmd[1]=0x80;
+ response_count=0;
+ i=cmd_out();
+ return (i);
+}
+/*==========================================================================*/
+#if 000
+static int yy_LockDoor(char lock)
+{
+ int i;
+
+ if (!new_drive) return (-3);
+ clr_cmdbuf();
+ drvcmd[0]=0x0C;
+ if (lock==1) drvcmd[1]=0x01;
+ flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+ response_count=0;
+ i=cmd_out();
+ return (i);
+}
+#endif 000
+/*==========================================================================*/
+static int xx_ReadSubQ(void)
+{
+ int i,j;
+
+ DS[d].diskstate_flags &= ~subq_bit;
+ clr_cmdbuf();
+ if (new_drive)
+ {
+ drvcmd[0]=0x87;
+ flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+ response_count=11;
+ }
+ else
+ {
+ drvcmd[0]=0x89;
+ drvcmd[1]=0x02;
+ flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+ response_count=13;
+ }
+ for (j=0;j<255;j++)
+ {
+ i=cmd_out();
+ if (i<0) return (i);
+ if (infobuf[0]!=0) break;
+ if (!st_spinning)
+ {
+ DS[d].SubQ_ctl_adr=DS[d].SubQ_trk=DS[d].SubQ_pnt_idx=DS[d].SubQ_whatisthis=0;
+ DS[d].SubQ_run_tot=DS[d].SubQ_run_trk=0;
+ return (0);
+ }
+ }
+ DS[d].SubQ_audio=infobuf[0];
+ DS[d].SubQ_ctl_adr=swap_nibbles(infobuf[1]);
+ DS[d].SubQ_trk=byt2bcd(infobuf[2]);
+ DS[d].SubQ_pnt_idx=byt2bcd(infobuf[3]);
+ i=4;
+ if (!new_drive) i=5;
+ DS[d].SubQ_run_tot=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */
+ i=7;
+ if (!new_drive) i=9;
+ DS[d].SubQ_run_trk=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */
+ DS[d].SubQ_whatisthis=infobuf[i+3];
+ DS[d].diskstate_flags |= subq_bit;
+ return (0);
+}
+/*==========================================================================*/
+static int xx_ModeSense(void)
+{
+ int i;
+
+ DS[d].diskstate_flags &= ~frame_size_bit;
+ clr_cmdbuf();
+ if (new_drive)
+ {
+ drvcmd[0]=0x84;
+ drvcmd[1]=0x00;
+ flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+ response_count=5;
+ }
+ else
+ {
+ drvcmd[0]=0x85;
+ drvcmd[1]=0x00;
+ flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+ response_count=2;
+ }
+ i=cmd_out();
+ if (i<0) return (i);
+ i=0;
+ if (new_drive) DS[d].sense_byte=infobuf[i++];
+ DS[d].frame_size=make16(infobuf[i],infobuf[i+1]);
+ DS[d].diskstate_flags |= frame_size_bit;
+ return (0);
+}
+/*==========================================================================*/
+#if 0000
+static int xx_TellVolume(void)
+{
+ int i;
+ u_char switches;
+ u_char chan0,vol0,chan1,vol1;
+
+ DS[d].diskstate_flags &= ~volume_bit;
+ clr_cmdbuf();
+ if (new_drive)
+ {
+ drvcmd[0]=0x84;
+ drvcmd[1]=0x05;
+ response_count=5;
+ flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+ }
+ else
+ {
+ drvcmd[0]=0x85;
+ drvcmd[1]=0x03;
+ response_count=2;
+ flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+ }
+ i=cmd_out();
+ if (i<0) return (i);
+ if (new_drive)
+ {
+ chan0=infobuf[1]&0x0F;
+ vol0=infobuf[2];
+ chan1=infobuf[3]&0x0F;
+ vol1=infobuf[4];
+ if (chan0==0)
+ {
+ chan0=1;
+ vol0=0;
+ }
+ if (chan1==0)
+ {
+ chan1=2;
+ vol1=0;
+ }
+ chan0 >>= 1;
+ chan1 >>= 1;
+ }
+ else
+ {
+ chan0=0;
+ chan1=1;
+ vol0=vol1=infobuf[1];
+ if (DS[d].drv_type>=drv_201)
+ {
+ if (DS[d].drv_type<drv_300)
+ {
+ switches=infobuf[0];
+ if ((switches&0x80)!=0) vol0=0;
+ if ((switches&0x40)!=0) vol1=0;
+ if (DS[d].drv_type>=drv_211)
+ {
+ if ((switches&0x20)!=0) chan0=1;
+ if ((switches&0x10)!=0) chan1=0;
+ }
+ }
+ else
+ {
+ vol0=infobuf[0];
+ if ((vol0&0x01)!=0) chan0=1;
+ if ((vol1&0x01)==0) chan1=0;
+ vol0 &= 0xFC;
+ vol1 &= 0xFC;
+ if (vol0!=0) vol0 += 3;
+ if (vol1!=0) vol1 += 3;
+ }
+ }
+ }
+ DS[d].vol_chan0=chan0;
+ DS[d].vol_ctrl0=vol0;
+ DS[d].vol_chan1=chan1;
+ DS[d].vol_ctrl1=vol1;
+ DS[d].vol_chan2=2;
+ DS[d].vol_ctrl2=0xFF;
+ DS[d].vol_chan3=3;
+ DS[d].vol_ctrl3=0xFF;
+ DS[d].diskstate_flags |= volume_bit;
+ return (0);
+}
+#endif
+/*==========================================================================*/
+static int xx_ReadCapacity(void)
+{
+ int i;
+
+ DS[d].diskstate_flags &= ~cd_size_bit;
+ clr_cmdbuf();
+ if (new_drive)
+ {
+ drvcmd[0]=0x85;
+ flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+ }
+ else
+ {
+ drvcmd[0]=0x88;
+ flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+ }
+ response_count=5;
+ i=cmd_out();
+ if (i<0) return (i);
+ DS[d].CDsize_blk=make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2]));
+ if (new_drive) DS[d].CDsize_blk=msf2blk(DS[d].CDsize_blk);
+ DS[d].CDsize_frm = (DS[d].CDsize_blk * make16(infobuf[3],infobuf[4])) / CD_FRAMESIZE;
+ DS[d].CDsize_blk += 151;
+ DS[d].diskstate_flags |= cd_size_bit;
+ return (0);
+}
+/*==========================================================================*/
+static int xx_ReadTocDescr(void)
+{
+ int i;
+
+ DS[d].diskstate_flags &= ~toc_bit;
+ clr_cmdbuf();
+ if (new_drive)
+ {
+ drvcmd[0]=0x8B;
+ flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+ }
+ else
+ {
+ drvcmd[0]=0x8B;
+ flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+ }
+ response_count=6;
+ i=cmd_out();
+ if (i<0) return (i);
+ DS[d].xa_byte=infobuf[0];
+ DS[d].n_first_track=infobuf[1];
+ DS[d].n_last_track=infobuf[2];
+ DS[d].size_msf=make32(make16(0,infobuf[3]),make16(infobuf[4],infobuf[5]));
+ DS[d].size_blk=msf2blk(DS[d].size_msf);
+ DS[d].diskstate_flags |= toc_bit;
+ DPRINTF((DBG_TOC,"SBPCD: TocDesc: %02X %02X %02X %08X\n",
+ DS[d].xa_byte,DS[d].n_first_track,DS[d].n_last_track,DS[d].size_msf));
+ return (0);
+}
+/*==========================================================================*/
+static int xx_ReadTocEntry(int num)
+{
+ int i;
+
+ clr_cmdbuf();
+ if (new_drive)
+ {
+ drvcmd[0]=0x8C;
+ flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+ }
+ else
+ {
+ drvcmd[0]=0x8C;
+ drvcmd[1]=0x02;
+ flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+ }
+ drvcmd[2]=num;
+ response_count=8;
+ i=cmd_out();
+ if (i<0) return (i);
+ DS[d].TocEnt_nixbyte=infobuf[0];
+ DS[d].TocEnt_ctl_adr=swap_nibbles(infobuf[1]);
+ DS[d].TocEnt_number=infobuf[2];
+ DS[d].TocEnt_format=infobuf[3];
+ if (new_drive) i=4;
+ else i=5;
+ DS[d].TocEnt_address=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2]));
+ DPRINTF((DBG_TOC,"SBPCD: TocEntry: %02X %02X %02X %02X %08X\n",
+ DS[d].TocEnt_nixbyte,DS[d].TocEnt_ctl_adr,DS[d].TocEnt_number,
+ DS[d].TocEnt_format,DS[d].TocEnt_address));
+ return (0);
+}
+/*==========================================================================*/
+static int xx_ReadPacket(void)
+{
+ int i;
+
+ clr_cmdbuf();
+ drvcmd[0]=0x8E;
+ drvcmd[1]=response_count;
+ flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+ i=cmd_out();
+ return (i);
+}
+/*==========================================================================*/
+static int convert_UPC(u_char *p)
+{
+ int i;
+
+ p++;
+ if (!new_drive) p[13]=0;
+ for (i=0;i<7;i++)
+ {
+ if (new_drive) DS[d].UPC_buf[i]=swap_nibbles(*p++);
+ else
+ {
+ DS[d].UPC_buf[i]=((*p++)<<4)&0xFF;
+ DS[d].UPC_buf[i] |= *p++;
+ }
+ }
+ DS[d].UPC_buf[6] &= 0xF0;
+ return (0);
+}
+/*==========================================================================*/
+static int xx_ReadUPC(void)
+{
+ int i;
+
+ DS[d].diskstate_flags &= ~upc_bit;
+ clr_cmdbuf();
+ if (new_drive)
+ {
+ drvcmd[0]=0x88;
+ response_count=8;
+ flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+ }
+ else
+ {
+ drvcmd[0]=0x08;
+ response_count=0;
+ flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
+ }
+ i=cmd_out();
+ if (i<0) return (i);
+ if (!new_drive)
+ {
+ response_count=16;
+ i=xx_ReadPacket();
+ if (i<0) return (i);
+ }
+ DS[d].UPC_ctl_adr=0;
+ if (new_drive) i=0;
+ else i=2;
+ if ((infobuf[i]&0x80)!=0)
+ {
+ convert_UPC(&infobuf[i]);
+ DS[d].UPC_ctl_adr &= 0xF0;
+ DS[d].UPC_ctl_adr |= 0x02;
+ }
+ DS[d].diskstate_flags |= upc_bit;
+ return (0);
+}
+/*==========================================================================*/
+static int yy_CheckMultiSession(void)
+{
+ int i;
+
+ DS[d].diskstate_flags &= ~multisession_bit;
+ DS[d].f_multisession=0;
+ clr_cmdbuf();
+ if (new_drive)
+ {
+ drvcmd[0]=0x8D;
+ response_count=6;
+ flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+ i=cmd_out();
+ if (i<0) return (i);
+ if ((infobuf[0]&0x80)!=0)
+ {
+ DPRINTF((DBG_MUL,"SBPCD: MultiSession CD detected: %02X %02X %02X %02X %02X %02X\n",
+ infobuf[0], infobuf[1], infobuf[2],
+ infobuf[3], infobuf[4], infobuf[5]));
+ DS[d].f_multisession=1;
+ DS[d].lba_multi=msf2blk(make32(make16(0,infobuf[1]),
+ make16(infobuf[2],infobuf[3])));
+ }
+ }
+ DS[d].diskstate_flags |= multisession_bit;
+ return (0);
+}
+/*==========================================================================*/
+static void check_datarate(void)
+{
+#ifdef CDMKE
+ int i=0;
+
+ timed_out=0;
+ datarate=0;
+
+ /* set a timer to make (timed_out!=0) after 1.1 seconds */
+
+ DPRINTF((DBG_TIM,"SBPCD: timer started (110).\n"));
+ sti(); /* to avoid possible "printf" bug */
+
+ SET_TIMER(mark_timeout,110);
+ do
+ {
+ i=inb(CDi_status);
+ datarate++;
+
+#if 00000
+ if (datarate>0x0FFFFFFF) break;
+#endif 00000
+
+ }
+ while (!timed_out); /* originally looping for 1.1 seconds */
+ CLEAR_TIMER;
+ DPRINTF((DBG_TIM,"SBPCD: datarate: %d\n", datarate));
+ if (datarate<65536) datarate=65536;
+
+ maxtim16=datarate*16;
+ maxtim04=datarate*4;
+ maxtim02=datarate*2;
+ maxtim_8=datarate/32;
+#if MANY_SESSION
+ maxtim_data=datarate/100;
+#else
+ maxtim_data=datarate/300;
+#endif MANY_SESSION
+ DPRINTF((DBG_TIM,"SBPCD: maxtim_8 %d, maxtim_data %d.\n",
+ maxtim_8, maxtim_data));
+#endif CDMKE
+}
+/*==========================================================================*/
+static int check_version(void)
+{
+ int i, j;
+
+ /* clear any pending error state */
+ clr_cmdbuf();
+ drvcmd[0]=0x82;
+ response_count=9;
+ flags_cmd_out=f_putcmd;
+ cmd_out();
+
+ /* read drive version */
+ clr_cmdbuf();
+ for (i=0;i<12;i++) infobuf[i]=0;
+ drvcmd[0]=0x83;
+ response_count=12;
+ flags_cmd_out=f_putcmd;
+ i=cmd_out();
+ if (i<0) DPRINTF((DBG_INI,"SBPCD: cmd_83 returns %d\n",i));
+
+ DPRINTF((DBG_INI,"SBPCD: infobuf = \""));
+ for (i=0;i<12;i++) DPRINTF((DBG_INI,"%c",infobuf[i]));
+ DPRINTF((DBG_INI,"\"\n"));
+
+ for (i=0;i<4;i++) if (infobuf[i]!=drive_family[i]) break;
+ if (i==4)
+ {
+ DS[d].drive_model[0]=infobuf[i++];
+ DS[d].drive_model[1]=infobuf[i++];
+ DS[d].drive_model[2]='-';
+ DS[d].drive_model[3]='x';
+ DS[d].drv_type=drv_new;
+ }
+ else
+ {
+ for (i=0;i<8;i++) if (infobuf[i]!=drive_vendor[i]) break;
+ if (i!=8) return (-1);
+ DS[d].drive_model[0]='2';
+ DS[d].drive_model[1]='x';
+ DS[d].drive_model[2]='-';
+ DS[d].drive_model[3]='x';
+ DS[d].drv_type=drv_old;
+ }
+ for (j=0;j<4;j++) DS[d].firmware_version[j]=infobuf[i+j];
+ j = (DS[d].firmware_version[0] & 0x0F) * 100 +
+ (DS[d].firmware_version[2] & 0x0F) *10 +
+ (DS[d].firmware_version[3] & 0x0F);
+ if (new_drive)
+ {
+ if (j<100) DS[d].drv_type=drv_099;
+ else DS[d].drv_type=drv_100;
+ }
+ else if (j<200) DS[d].drv_type=drv_199;
+ else if (j<201) DS[d].drv_type=drv_200;
+ else if (j<210) DS[d].drv_type=drv_201;
+ else if (j<211) DS[d].drv_type=drv_210;
+ else if (j<300) DS[d].drv_type=drv_211;
+ else DS[d].drv_type=drv_300;
+ return (0);
+}
+/*==========================================================================*/
+static int switch_drive(int num)
+{
+ int i;
+
+ d=num;
+
+ i=num;
+ if (sbpro_type) i=(i&0x01)<<1|(i&0x02)>>1;
+ OUT(CDo_enable,i);
+ DPRINTF((DBG_DID,"SBPCD: switch_drive: drive %d activated.\n",DS[d].drv_minor));
+ return (0);
+}
+/*==========================================================================*/
+/*
+ * probe for the presence of drives on the selected controller
+ */
+static int check_drives(void)
+{
+ int i, j;
+ char *printk_header="";
+
+ DPRINTF((DBG_INI,"SBPCD: check_drives entered.\n"));
+
+ ndrives=0;
+ for (j=0;j<NR_SBPCD;j++)
+ {
+ DS[j].drv_minor=j;
+ switch_drive(j);
+ DPRINTF((DBG_ID,"SBPCD: check_drives: drive %d activated.\n",j));
+ i=check_version();
+ DPRINTF((DBG_ID,"SBPCD: check_version returns %d.\n",i));
+ if (i>=0)
+ {
+ ndrives++;
+ DS[d].drv_options=drv_pattern[j];
+ if (!new_drive) DS[d].drv_options&=~(speed_auto|speed_300|speed_150);
+ printk("%sDrive %d: %s%.4s (%.4s)\n", printk_header,
+ DS[d].drv_minor,
+ drive_family,
+ DS[d].drive_model,
+ DS[d].firmware_version);
+ printk_header=" - ";
+ }
+ else DS[d].drv_minor=-1;
+ }
+ if (ndrives==0) return (-1);
+ return (0);
+}
+/*==========================================================================*/
+#if 000
+static void timewait(void)
+{
+ int i;
+ for (i=0; i<65500; i++);
+}
+#endif 000
+/*==========================================================================*/
+#if FUTURE
+/*
+ * obtain if requested service disturbs current audio state
+ */
+static int obey_audio_state(u_char audio_state, u_char func,u_char subfunc)
+{
+ switch (audio_state) /* audio status from controller */
+ {
+ case aud_11: /* "audio play in progress" */
+ case audx11:
+ switch (func) /* DOS command code */
+ {
+ case cmd_07: /* input flush */
+ case cmd_0d: /* open device */
+ case cmd_0e: /* close device */
+ case cmd_0c: /* ioctl output */
+ return (1);
+ case cmd_03: /* ioctl input */
+ switch (subfunc)
+ /* DOS ioctl input subfunction */
+ {
+ case cxi_00:
+ case cxi_06:
+ case cxi_09:
+ return (1);
+ default:
+ return (ERROR15);
+ }
+ return (1);
+ default:
+ return (ERROR15);
+ }
+ return (1);
+ case aud_12: /* "audio play paused" */
+ case audx12:
+ return (1);
+ default:
+ return (2);
+ }
+}
+#endif FUTURE
+/*==========================================================================*/
+/* allowed is only
+ * ioctl_o, flush_input, open_device, close_device,
+ * tell_address, tell_volume, tell_capabiliti,
+ * tell_framesize, tell_CD_changed, tell_audio_posi
+ */
+static int check_allowed1(u_char func1, u_char func2)
+{
+#if 000
+ if (func1==ioctl_o) return (0);
+ if (func1==read_long) return (-1);
+ if (func1==read_long_prefetch) return (-1);
+ if (func1==seek) return (-1);
+ if (func1==audio_play) return (-1);
+ if (func1==audio_pause) return (-1);
+ if (func1==audio_resume) return (-1);
+ if (func1!=ioctl_i) return (0);
+ if (func2==tell_SubQ_run_tot) return (-1);
+ if (func2==tell_cdsize) return (-1);
+ if (func2==tell_TocDescrip) return (-1);
+ if (func2==tell_TocEntry) return (-1);
+ if (func2==tell_subQ_info) return (-1);
+ if (new_drive) if (func2==tell_SubChanInfo) return (-1);
+ if (func2==tell_UPC) return (-1);
+#else
+ return (0);
+#endif 000
+}
+/*==========================================================================*/
+static int check_allowed2(u_char func1, u_char func2)
+{
+#if 000
+ if (func1==read_long) return (-1);
+ if (func1==read_long_prefetch) return (-1);
+ if (func1==seek) return (-1);
+ if (func1==audio_play) return (-1);
+ if (func1!=ioctl_o) return (0);
+ if (new_drive)
+ {
+ if (func2==EjectDisk) return (-1);
+ if (func2==CloseTray) return (-1);
+ }
+#else
+ return (0);
+#endif 000
+}
+/*==========================================================================*/
+static int check_allowed3(u_char func1, u_char func2)
+{
+#if 000
+ if (func1==ioctl_i)
+ {
+ if (func2==tell_address) return (0);
+ if (func2==tell_capabiliti) return (0);
+ if (func2==tell_CD_changed) return (0);
+ if (!new_drive) if (func2==tell_SubChanInfo) return (0);
+ return (-1);
+ }
+ if (func1==ioctl_o)
+ {
+ if (func2==DriveReset) return (0);
+ if (!new_drive)
+ {
+ if (func2==EjectDisk) return (0);
+ if (func2==LockDoor) return (0);
+ if (func2==CloseTray) return (0);
+ }
+ return (-1);
+ }
+ if (func1==flush_input) return (-1);
+ if (func1==read_long) return (-1);
+ if (func1==read_long_prefetch) return (-1);
+ if (func1==seek) return (-1);
+ if (func1==audio_play) return (-1);
+ if (func1==audio_pause) return (-1);
+ if (func1==audio_resume) return (-1);
+#else
+ return (0);
+#endif 000
+}
+/*==========================================================================*/
+static int seek_pos_audio_end(void)
+{
+ int i;
+
+ i=msf2blk(DS[d].pos_audio_end)-1;
+ if (i<0) return (-1);
+ i=xx_Seek(i,0);
+ return (i);
+}
+/*==========================================================================*/
+static int ReadToC(void)
+{
+ int i, j;
+ DS[d].diskstate_flags &= ~toc_bit;
+ DS[d].ored_ctl_adr=0;
+ for (j=DS[d].n_first_track;j<=DS[d].n_last_track;j++)
+ {
+ i=xx_ReadTocEntry(j);
+ if (i<0) return (i);
+ DS[d].TocBuffer[j].nixbyte=DS[d].TocEnt_nixbyte;
+ DS[d].TocBuffer[j].ctl_adr=DS[d].TocEnt_ctl_adr;
+ DS[d].TocBuffer[j].number=DS[d].TocEnt_number;
+ DS[d].TocBuffer[j].format=DS[d].TocEnt_format;
+ DS[d].TocBuffer[j].address=DS[d].TocEnt_address;
+ DS[d].ored_ctl_adr |= DS[d].TocEnt_ctl_adr;
+ }
+/* fake entry for LeadOut Track */
+ DS[d].TocBuffer[j].nixbyte=0;
+ DS[d].TocBuffer[j].ctl_adr=0;
+ DS[d].TocBuffer[j].number=0;
+ DS[d].TocBuffer[j].format=0;
+ DS[d].TocBuffer[j].address=DS[d].size_msf;
+
+ DS[d].diskstate_flags |= toc_bit;
+ return (0);
+}
+/*==========================================================================*/
+static int DiskInfo(void)
+{
+ int i;
+
+ i=SetSpeed();
+ if (i<0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: DiskInfo: first SetSpeed returns %d\n", i));
+ i=SetSpeed();
+ if (i<0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: DiskInfo: second SetSpeed returns %d\n", i));
+ return (i);
+ }
+ }
+ i=xx_ModeSense();
+ if (i<0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: DiskInfo: first xx_ModeSense returns %d\n", i));
+ i=xx_ModeSense();
+ if (i<0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: DiskInfo: second xx_ModeSense returns %d\n", i));
+ return (i);
+ }
+ return (i);
+ }
+ i=xx_ReadCapacity();
+ if (i<0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: DiskInfo: first ReadCapacity returns %d\n", i));
+ i=xx_ReadCapacity();
+ if (i<0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: DiskInfo: second ReadCapacity returns %d\n", i));
+ return (i);
+ }
+ return (i);
+ }
+ i=xx_ReadTocDescr();
+ if (i<0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: DiskInfo: ReadTocDescr returns %d\n", i));
+ return (i);
+ }
+ i=ReadToC();
+ if (i<0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: DiskInfo: ReadToC returns %d\n", i));
+ return (i);
+ }
+ i=yy_CheckMultiSession();
+ if (i<0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: DiskInfo: yy_CheckMultiSession returns %d\n", i));
+ return (i);
+ }
+ i=xx_ReadTocEntry(DS[d].n_first_track);
+ if (i<0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: DiskInfo: xx_ReadTocEntry(1) returns %d\n", i));
+ return (i);
+ }
+ i=xx_ReadUPC();
+ if (i<0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: DiskInfo: xx_ReadUPC returns %d\n", i));
+ return (i);
+ }
+ return (0);
+}
+/*==========================================================================*/
+/*
+ * called always if driver gets entered
+ * returns 0 or ERROR2 or ERROR15
+ */
+static int prepare(u_char func, u_char subfunc)
+{
+ int i;
+
+ if (!new_drive)
+ {
+ i=inb(CDi_status);
+ if (i&s_attention) GetStatus();
+ }
+ else GetStatus();
+ if (DS[d].CD_changed==0xFF)
+ {
+#if MANY_SESSION
+#else
+ DS[d].diskstate_flags=0;
+#endif MANY_SESSION
+ DS[d].audio_state=0;
+ if (!st_diskok)
+ {
+ i=check_allowed1(func,subfunc);
+ if (i<0) return (-2);
+ }
+ else
+ {
+ i=check_allowed3(func,subfunc);
+ if (i<0)
+ {
+ DS[d].CD_changed=1;
+ return (-15);
+ }
+ }
+ }
+ else
+ {
+ if (!st_diskok)
+ {
+#if MANY_SESSION
+#else
+ DS[d].diskstate_flags=0;
+#endif MANY_SESSION
+ DS[d].audio_state=0;
+ i=check_allowed1(func,subfunc);
+ if (i<0) return (-2);
+ }
+ else
+ {
+ if (st_busy)
+ {
+ if (DS[d].audio_state!=audio_pausing)
+ {
+ i=check_allowed2(func,subfunc);
+ if (i<0) return (-2);
+ }
+ }
+ else
+ {
+ if (DS[d].audio_state==audio_playing) seek_pos_audio_end();
+ DS[d].audio_state=0;
+ }
+ if (!frame_size_valid)
+ {
+ i=DiskInfo();
+ if (i<0)
+ {
+#if MANY_SESSION
+#else
+ DS[d].diskstate_flags=0;
+#endif MANY_SESSION
+ DS[d].audio_state=0;
+ i=check_allowed1(func,subfunc);
+ if (i<0) return (-2);
+ }
+ }
+ }
+ }
+ return (0);
+}
+/*==========================================================================*/
+static int xx_PlayAudioMSF(int pos_audio_start,int pos_audio_end)
+{
+ int i;
+
+ if (DS[d].audio_state==audio_playing) return (-EINVAL);
+ clr_cmdbuf();
+ if (new_drive)
+ {
+ drvcmd[0]=0x0E;
+ flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus |
+ f_obey_p_check | f_wait_if_busy;
+ }
+ else
+ {
+ drvcmd[0]=0x0B;
+ flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta |
+ f_ResponseStatus | f_obey_p_check | f_wait_if_busy;
+ }
+ drvcmd[1]=(pos_audio_start>>16)&0x00FF;
+ drvcmd[2]=(pos_audio_start>>8)&0x00FF;
+ drvcmd[3]=pos_audio_start&0x00FF;
+ drvcmd[4]=(pos_audio_end>>16)&0x00FF;
+ drvcmd[5]=(pos_audio_end>>8)&0x00FF;
+ drvcmd[6]=pos_audio_end&0x00FF;
+ response_count=0;
+ i=cmd_out();
+ return (i);
+}
+/*==========================================================================*/
+/*==========================================================================*/
+
+/*==========================================================================*/
+/*==========================================================================*/
+/*
+ * ioctl support, adopted from scsi/sr_ioctl.c and mcd.c
+ */
+static int sbpcd_ioctl(struct inode *inode,struct file *file,
+ u_int cmd, u_long arg)
+{
+ int i, st;
+
+ DPRINTF((DBG_IOC,"SBPCD: ioctl(%d, 0x%08lX, 0x%08lX)\n",
+ MINOR(inode->i_rdev), cmd, arg));
+ if (!inode) return (-EINVAL);
+ st=GetStatus();
+ if (st<0) return (-EIO);
+
+ if (!toc_valid)
+ {
+ i=DiskInfo();
+ if (i<0) return (-EIO); /* error reading TOC */
+ }
+
+ i=MINOR(inode->i_rdev);
+ if ( (i<0) || (i>=NR_SBPCD) )
+ {
+ DPRINTF((DBG_INF,"SBPCD: ioctl: bad device: %d\n", i));
+ return (-ENODEV); /* no such drive */
+ }
+ switch_drive(i);
+
+
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: device %d, request %04X\n",i,cmd));
+ switch (cmd) /* Sun-compatible */
+ {
+ case DDIOCSDBG: /* DDI Debug */
+ if (! suser()) return (-EPERM);
+ i = verify_area(VERIFY_READ, (int *) arg, sizeof(int));
+ if (i>=0) i=sbpcd_dbg_ioctl(arg,1);
+ return (i);
+
+ case CDROMPAUSE: /* Pause the drive */
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMPAUSE entered.\n"));
+ /* pause the drive unit when it is currently in PLAY mode, */
+ /* or reset the starting and ending locations when in PAUSED mode. */
+ /* If applicable, at the next stopping point it reaches */
+ /* the drive will discontinue playing. */
+ switch (DS[d].audio_state)
+ {
+ case audio_playing:
+ i=xx_Pause_Resume(1);
+ if (i<0) return (-EIO);
+ DS[d].audio_state=audio_pausing;
+ i=xx_ReadSubQ();
+ if (i<0) return (-EIO);
+ DS[d].pos_audio_start=DS[d].SubQ_run_tot;
+ return (0);
+ case audio_pausing:
+ i=xx_Seek(DS[d].pos_audio_start,1);
+ if (i<0) return (-EIO);
+ return (0);
+ default:
+ return (-EINVAL);
+ }
+
+ case CDROMRESUME: /* resume paused audio play */
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMRESUME entered.\n"));
+ /* resume playing audio tracks when a previous PLAY AUDIO call has */
+ /* been paused with a PAUSE command. */
+ /* It will resume playing from the location saved in SubQ_run_tot. */
+ if (DS[d].audio_state!=audio_pausing) return -EINVAL;
+ i=xx_Pause_Resume(3);
+ if (i<0) return (-EIO);
+ DS[d].audio_state=audio_playing;
+ return (0);
+
+ case CDROMPLAYMSF:
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMPLAYMSF entered.\n"));
+#if WORKMAN
+ if (DS[d].audio_state==audio_playing)
+ {
+ i=xx_Pause_Resume(1);
+ if (i<0) return (-EIO);
+ i=xx_ReadSubQ();
+ if (i<0) return (-EIO);
+ DS[d].pos_audio_start=DS[d].SubQ_run_tot;
+ i=xx_Seek(DS[d].pos_audio_start,1);
+ }
+#else
+ if (DS[d].audio_state==audio_playing) return (-EINVAL);
+#endif
+ st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_msf));
+ if (st) return (st);
+ memcpy_fromfs(&msf, (void *) arg, sizeof(struct cdrom_msf));
+ /* values come as msf-bin */
+ DS[d].pos_audio_start = (msf.cdmsf_min0<<16) |
+ (msf.cdmsf_sec0<<8) |
+ msf.cdmsf_frame0;
+ DS[d].pos_audio_end = (msf.cdmsf_min1<<16) |
+ (msf.cdmsf_sec1<<8) |
+ msf.cdmsf_frame1;
+ DPRINTF((DBG_IOX,"SBPCD: ioctl: CDROMPLAYMSF %08X %08X\n",
+ DS[d].pos_audio_start,DS[d].pos_audio_end));
+ i=xx_PlayAudioMSF(DS[d].pos_audio_start,DS[d].pos_audio_end);
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: xx_PlayAudioMSF returns %d\n",i));
+#if 0
+ if (i<0) return (-EIO);
+#endif 0
+ DS[d].audio_state=audio_playing;
+ return (0);
+
+ case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMPLAYTRKIND entered.\n"));
+ if (DS[d].audio_state==audio_playing)
+ {
+ DPRINTF((DBG_IOX,"SBPCD: CDROMPLAYTRKIND: already audio_playing.\n"));
+ return (0);
+ return (-EINVAL);
+ }
+ st=verify_area(VERIFY_READ,(void *) arg,sizeof(struct cdrom_ti));
+ if (st<0)
+ {
+ DPRINTF((DBG_IOX,"SBPCD: CDROMPLAYTRKIND: verify_area error.\n"));
+ return (st);
+ }
+ memcpy_fromfs(&ti,(void *) arg,sizeof(struct cdrom_ti));
+ DPRINTF((DBG_IOX,"SBPCD: ioctl: trk0: %d, ind0: %d, trk1:%d, ind1:%d\n",
+ ti.cdti_trk0,ti.cdti_ind0,ti.cdti_trk1,ti.cdti_ind1));
+ if (ti.cdti_trk0<DS[d].n_first_track) return (-EINVAL);
+ if (ti.cdti_trk0>DS[d].n_last_track) return (-EINVAL);
+ if (ti.cdti_trk1<ti.cdti_trk0) ti.cdti_trk1=ti.cdti_trk0;
+ if (ti.cdti_trk1>DS[d].n_last_track) ti.cdti_trk1=DS[d].n_last_track;
+ DS[d].pos_audio_start=DS[d].TocBuffer[ti.cdti_trk0].address;
+ DS[d].pos_audio_end=DS[d].TocBuffer[ti.cdti_trk1+1].address;
+ i=xx_PlayAudioMSF(DS[d].pos_audio_start,DS[d].pos_audio_end);
+#if 0
+ if (i<0) return (-EIO);
+#endif 0
+ DS[d].audio_state=audio_playing;
+ return (0);
+
+ case CDROMREADTOCHDR: /* Read the table of contents header */
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADTOCHDR entered.\n"));
+ tochdr.cdth_trk0=DS[d].n_first_track;
+ tochdr.cdth_trk1=DS[d].n_last_track;
+ st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_tochdr));
+ if (st) return (st);
+ memcpy_tofs((void *) arg, &tochdr, sizeof(struct cdrom_tochdr));
+ return (0);
+
+ case CDROMREADTOCENTRY: /* Read an entry in the table of contents */
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADTOCENTRY entered.\n"));
+ st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_tocentry));
+ if (st) return (st);
+ memcpy_fromfs(&tocentry, (void *) arg, sizeof(struct cdrom_tocentry));
+ i=tocentry.cdte_track;
+ if (i==CDROM_LEADOUT) i=DS[d].n_last_track+1;
+ else if (i<DS[d].n_first_track||i>DS[d].n_last_track) return (-EINVAL);
+ tocentry.cdte_adr=DS[d].TocBuffer[i].ctl_adr&0x0F;
+ tocentry.cdte_ctrl=(DS[d].TocBuffer[i].ctl_adr>>4)&0x0F;
+ tocentry.cdte_datamode=DS[d].TocBuffer[i].format;
+ if (tocentry.cdte_format==CDROM_MSF) /* MSF-bin required */
+ { tocentry.cdte_addr.msf.minute=(DS[d].TocBuffer[i].address>>16)&0x00FF;
+ tocentry.cdte_addr.msf.second=(DS[d].TocBuffer[i].address>>8)&0x00FF;
+ tocentry.cdte_addr.msf.frame=DS[d].TocBuffer[i].address&0x00FF;
+ }
+ else if (tocentry.cdte_format==CDROM_LBA) /* blk required */
+ tocentry.cdte_addr.lba=msf2blk(DS[d].TocBuffer[i].address);
+ else return (-EINVAL);
+ st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_tocentry));
+ if (st) return (st);
+ memcpy_tofs((void *) arg, &tocentry, sizeof(struct cdrom_tocentry));
+ return (0);
+
+ case CDROMSTOP: /* Spin down the drive */
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMSTOP entered.\n"));
+ i=DriveReset();
+#if WORKMAN
+ DS[d].CD_changed=0xFF;
+ DS[d].diskstate_flags=0;
+#endif WORKMAN
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: DriveReset returns %d\n",i));
+ DS[d].audio_state=0;
+ i=DiskInfo();
+ return (0);
+
+ case CDROMSTART: /* Spin up the drive */
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMSTART entered.\n"));
+ i=xx_SpinUp();
+ DS[d].audio_state=0;
+ return (0);
+
+ case CDROMEJECT:
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMEJECT entered.\n"));
+ if (!new_drive) return (0);
+#if WORKMAN
+ DS[d].CD_changed=0xFF;
+ DS[d].diskstate_flags=0;
+#endif WORKMAN
+ i=yy_SpinDown();
+ if (i<0) return (-EIO);
+ DS[d].audio_state=0;
+ return (0);
+
+ case CDROMVOLCTRL: /* Volume control */
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMVOLCTRL entered.\n"));
+ st=verify_area(VERIFY_READ,(void *) arg,sizeof(volctrl));
+ if (st) return (st);
+ memcpy_fromfs(&volctrl,(char *) arg,sizeof(volctrl));
+ DS[d].vol_chan0=0;
+ DS[d].vol_ctrl0=volctrl.channel0;
+ DS[d].vol_chan1=1;
+ DS[d].vol_ctrl1=volctrl.channel1;
+ i=xx_SetVolume();
+ return (0);
+
+ case CDROMSUBCHNL: /* Get subchannel info */
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMSUBCHNL entered.\n"));
+ if ((st_spinning)||(!subq_valid)) { i=xx_ReadSubQ();
+ if (i<0) return (-EIO);
+ }
+ st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl));
+ if (st) return (st);
+ memcpy_fromfs(&SC, (void *) arg, sizeof(struct cdrom_subchnl));
+ if (DS[d].SubQ_audio==0x80) DS[d].SubQ_audio=CDROM_AUDIO_NO_STATUS;
+ SC.cdsc_audiostatus=DS[d].SubQ_audio;
+ SC.cdsc_adr=DS[d].SubQ_ctl_adr;
+ SC.cdsc_ctrl=DS[d].SubQ_ctl_adr>>4;
+ SC.cdsc_trk=bcd2bin(DS[d].SubQ_trk);
+ SC.cdsc_ind=bcd2bin(DS[d].SubQ_pnt_idx);
+ if (SC.cdsc_format==CDROM_LBA)
+ {
+ SC.cdsc_absaddr.lba=msf2blk(DS[d].SubQ_run_tot);
+ SC.cdsc_reladdr.lba=msf2blk(DS[d].SubQ_run_trk);
+ }
+ else /* not only if (SC.cdsc_format==CDROM_MSF) */
+ {
+ SC.cdsc_absaddr.msf.minute=(DS[d].SubQ_run_tot>>16)&0x00FF;
+ SC.cdsc_absaddr.msf.second=(DS[d].SubQ_run_tot>>8)&0x00FF;
+ SC.cdsc_absaddr.msf.frame=DS[d].SubQ_run_tot&0x00FF;
+ SC.cdsc_reladdr.msf.minute=(DS[d].SubQ_run_trk>>16)&0x00FF;
+ SC.cdsc_reladdr.msf.second=(DS[d].SubQ_run_trk>>8)&0x00FF;
+ SC.cdsc_reladdr.msf.frame=DS[d].SubQ_run_trk&0x00FF;
+ }
+ memcpy_tofs((void *) arg, &SC, sizeof(struct cdrom_subchnl));
+ DPRINTF((DBG_IOC,"SBPCD: CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X\n",
+ SC.cdsc_format,SC.cdsc_audiostatus,
+ SC.cdsc_adr,SC.cdsc_ctrl,
+ SC.cdsc_trk,SC.cdsc_ind,
+ SC.cdsc_absaddr,SC.cdsc_reladdr));
+ return (0);
+
+ case CDROMREADMODE2:
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE2 requested.\n"));
+ return (-EINVAL);
+
+ case CDROMREADMODE1:
+ DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE1 requested.\n"));
+ return (-EINVAL);
+
+ default:
+ DPRINTF((DBG_IOX,"SBPCD: ioctl: unknown function request %04X\n", cmd));
+ return (-EINVAL);
+ } /* end switch(cmd) */
+}
+/*==========================================================================*/
+/*
+ * Take care of the different block sizes between cdrom and Linux.
+ * When Linux gets variable block sizes this will probably go away.
+ */
+static void sbp_transfer(void)
+{
+ long offs;
+
+ while ( (CURRENT->nr_sectors > 0) &&
+ (CURRENT->sector/4 >= DS[d].sbp_first_frame) &&
+ (CURRENT->sector/4 <= DS[d].sbp_last_frame) )
+ {
+ offs = (CURRENT->sector - DS[d].sbp_first_frame * 4) * 512;
+ memcpy(CURRENT->buffer, DS[d].sbp_buf + offs, 512);
+ CURRENT->nr_sectors--;
+ CURRENT->sector++;
+ CURRENT->buffer += 512;
+ }
+}
+/*==========================================================================*/
+/*
+ * We seem to get never an interrupt.
+ */
+#if SBPCD_USE_IRQ
+static void sbpcd_interrupt(int unused)
+{
+ int st;
+
+ st = inb(CDi_status) & 0xFF;
+ DPRINTF((DBG_IRQ,"SBPCD: INTERRUPT received - CDi_status=%02X\n", st));
+}
+#endif SBPCD_USE_IRQ
+/*==========================================================================*/
+/*
+ * Called from the timer to check the results of the get-status cmd.
+ */
+static int sbp_status(void)
+{
+ int st;
+
+ st=ResponseStatus();
+ if (st<0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: sbp_status: timeout.\n"));
+ return (0);
+ }
+
+ if (!st_spinning) DPRINTF((DBG_SPI,"SBPCD: motor got off - ignoring.\n"));
+
+ if (st_check)
+ {
+ DPRINTF((DBG_INF,"SBPCD: st_check detected - retrying.\n"));
+ return (0);
+ }
+ if (!st_door_closed)
+ {
+ DPRINTF((DBG_INF,"SBPCD: door is open - retrying.\n"));
+ return (0);
+ }
+ if (!st_caddy_in)
+ {
+ DPRINTF((DBG_INF,"SBPCD: disk removed - retrying.\n"));
+ return (0);
+ }
+ if (!st_diskok)
+ {
+ DPRINTF((DBG_INF,"SBPCD: !st_diskok detected - retrying.\n"));
+ return (0);
+ }
+ if (st_busy)
+ {
+ DPRINTF((DBG_INF,"SBPCD: st_busy detected - retrying.\n"));
+ return (0);
+ }
+ return (1);
+}
+/*==========================================================================*/
+/*
+ * I/O request routine, called from Linux kernel.
+ */
+static void do_sbpcd_request(void)
+{
+ u_int block;
+ int dev;
+ u_int nsect;
+ int i, status_tries, data_tries;
+
+request_loop:
+
+ sti();
+
+ if ((CURRENT==NULL)||(CURRENT->dev<0)) return;
+ if (CURRENT -> sector == -1) return;
+
+ dev = MINOR(CURRENT->dev);
+ if ( (dev<0) || (dev>=NR_SBPCD) )
+ {
+ DPRINTF((DBG_INF,"SBPCD: do_request: bad device: %d\n", dev));
+ return;
+ }
+ switch_drive(dev);
+
+ INIT_REQUEST;
+ block = CURRENT->sector;
+ nsect = CURRENT->nr_sectors;
+
+ if (CURRENT->cmd != READ)
+ {
+ DPRINTF((DBG_INF,"SBPCD: bad cmd %d\n", CURRENT->cmd));
+ end_request(0);
+ goto request_loop;
+ }
+
+ DPRINTF((DBG_MUL,"SBPCD: read LBA %d\n", block/4));
+ sbp_transfer();
+
+ /* if we satisfied the request from the buffer, we're done. */
+
+ if (CURRENT->nr_sectors == 0)
+ {
+ end_request(1);
+ goto request_loop;
+ }
+
+ i=prepare(0,0); /* at moment not really a hassle check, but ... */
+ if (i!=0) DPRINTF((DBG_INF,"SBPCD: \"prepare\" tells error %d -- ignored\n", i));
+
+ if (!st_spinning) xx_SpinUp();
+
+ for (data_tries=3; data_tries > 0; data_tries--)
+ {
+ for (status_tries=3; status_tries > 0; status_tries--)
+ {
+ flags_cmd_out |= f_respo3;
+ xx_ReadStatus();
+ if (sbp_status() != 0) break;
+ sbp_sleep(1); /* wait a bit, try again */
+ }
+ if (status_tries == 0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: sbp_status: failed after 3 tries\n"));
+ break;
+ }
+
+ sbp_read_cmd();
+ sbp_sleep(0);
+ if (sbp_data() != 0)
+ {
+ end_request(1);
+ goto request_loop;
+ }
+ }
+
+ end_request(0);
+ sbp_sleep(10); /* wait a bit, try again */
+ goto request_loop;
+}
+/*==========================================================================*/
+/*
+ * build and send the READ command.
+ * Maybe it would be better to "set mode1" before ...
+ */
+static void sbp_read_cmd(void)
+{
+ int i;
+ int block;
+
+ DS[d].sbp_first_frame=DS[d].sbp_last_frame=-1; /* purge buffer */
+ block=CURRENT->sector/4;
+
+ if (new_drive)
+ {
+#if MANY_SESSION
+ DPRINTF((DBG_MUL,"SBPCD: read MSF %08X\n", blk2msf(block)));
+ if ( (DS[d].f_multisession) && (multisession_valid) )
+ {
+ DPRINTF((DBG_MUL,"SBPCD: MultiSession: use %08X for %08X (msf)\n",
+ blk2msf(DS[d].lba_multi+block),
+ blk2msf(block)));
+ block=DS[d].lba_multi+block;
+ }
+#else
+ if ( (block==166) && (DS[d].f_multisession) && (multisession_valid) )
+ {
+ DPRINTF((DBG_MUL,"SBPCD: MultiSession: use %08X for %08X (msf)\n",
+ blk2msf(DS[d].lba_multi+16),
+ blk2msf(block)));
+ block=DS[d].lba_multi+16;
+ }
+#endif MANY_SESSION
+ }
+
+ if (block+SBP_BUFFER_FRAMES <= DS[d].CDsize_frm)
+ DS[d].sbp_read_frames = SBP_BUFFER_FRAMES;
+ else
+ {
+ DS[d].sbp_read_frames=DS[d].CDsize_frm-block;
+ /* avoid reading past end of data */
+ if (DS[d].sbp_read_frames < 1)
+ {
+ DPRINTF((DBG_INF,"SBPCD: requested frame %d, CD size %d ???\n",
+ block, DS[d].CDsize_frm));
+ DS[d].sbp_read_frames=1;
+ }
+ }
+ DS[d].sbp_current = 0;
+
+ flags_cmd_out = f_putcmd |
+ f_respo2 |
+ f_ResponseStatus |
+ f_obey_p_check;
+
+ if (!new_drive)
+ {
+ if (DS[d].drv_type>=drv_201)
+ {
+ lba2msf(block,&drvcmd[1]); /* msf-bcd format required */
+ bin2bcdx(&drvcmd[1]);
+ bin2bcdx(&drvcmd[2]);
+ bin2bcdx(&drvcmd[3]);
+ }
+ else
+ {
+ drvcmd[1]=(block>>16)&0x000000ff;
+ drvcmd[2]=(block>>8)&0x000000ff;
+ drvcmd[3]=block&0x000000ff;
+ }
+ drvcmd[4]=0;
+ drvcmd[5]=DS[d].sbp_read_frames;
+ drvcmd[6]=(DS[d].drv_type<drv_201)?0:2; /* flag "lba or msf-bcd format" */
+ drvcmd[0]=0x02; /* "read frames" command for old drives */
+ flags_cmd_out |= f_lopsta|f_getsta|f_bit1;
+ }
+ else /* if new_drive */
+ {
+ lba2msf(block,&drvcmd[1]); /* msf-bin format required */
+ drvcmd[4]=0;
+ drvcmd[5]=0;
+ drvcmd[6]=DS[d].sbp_read_frames;
+ drvcmd[0]=0x10; /* "read frames" command for new drives */
+ }
+#if SBPCD_DIS_IRQ
+ cli();
+#endif SBPCD_DIS_IRQ
+ for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
+#if SBPCD_DIS_IRQ
+ sti();
+#endif SBPCD_DIS_IRQ
+
+ return;
+}
+/*==========================================================================*/
+/*
+ * Check the completion of the read-data command. On success, read
+ * the SBP_BUFFER_FRAMES * 2048 bytes of data from the disk into buffer.
+ */
+static int sbp_data(void)
+{
+ int i=0, j=0, frame;
+ u_int try=0;
+ u_long timeout;
+ u_char *p;
+ u_int data_tries = 0;
+ u_int data_waits = 0;
+ u_int data_retrying = 0;
+ int error_flag;
+
+ error_flag=0;
+
+ for (frame=DS[d].sbp_current;frame<DS[d].sbp_read_frames&&!error_flag; frame++)
+ {
+#if SBPCD_DIS_IRQ
+ cli();
+#endif SBPCD_DIS_IRQ
+ try=maxtim_data;
+ for (timeout=jiffies+100; ; )
+ {
+ for ( ; try!=0;try--)
+ {
+ j=inb(CDi_status);
+ if (!(j&s_not_data_ready)) break;
+ if (!(j&s_not_result_ready)) break;
+ if (!new_drive) if (j&s_attention) break;
+ }
+ if (try != 0 || timeout <= jiffies) break;
+ if (data_retrying == 0) data_waits++;
+ data_retrying = 1;
+ sbp_sleep(1);
+ try = 1;
+ }
+ if (try==0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: sbp_data: CDi_status timeout.\n"));
+ error_flag++;
+ break;
+ }
+
+ if (j&s_not_data_ready)
+ {
+ if ((DS[d].ored_ctl_adr&0x40)==0)
+ DPRINTF((DBG_INF,"SBPCD: CD contains no data tracks.\n"));
+ else DPRINTF((DBG_INF,"SBPCD: sbp_data: DATA_READY timeout.\n"));
+ error_flag++;
+ break;
+ }
+
+#if SBPCD_DIS_IRQ
+ sti();
+#endif SBPCD_DIS_IRQ
+
+ CLEAR_TIMER;
+ error_flag=0;
+ p = DS[d].sbp_buf + frame * CD_FRAMESIZE;
+
+ if (sbpro_type) OUT(CDo_sel_d_i,0x01);
+ READ_DATA(CDi_data, p, CD_FRAMESIZE);
+ if (sbpro_type) OUT(CDo_sel_d_i,0x00);
+ DS[d].sbp_current++;
+
+ data_tries++;
+ data_retrying = 0;
+ if (data_tries >= 1000)
+ {
+ DPRINTF((DBG_INF,"SBPCD: info: %d waits in %d frames.\n",
+ data_waits, data_tries));
+ data_waits = data_tries = 0;
+ }
+ }
+#if SBPCD_DIS_IRQ
+ sti();
+#endif SBPCD_DIS_IRQ
+
+ if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
+ {
+ DPRINTF((DBG_INF,"SBPCD: read aborted by drive\n"));
+ i=DriveReset(); /* ugly fix to prevent a hang */
+ return (0);
+ }
+
+ if (!new_drive)
+ {
+#if SBPCD_DIS_IRQ
+ cli();
+#endif SBPCD_DIS_IRQ
+ i=maxtim_data;
+ for (timeout=jiffies+100; timeout > jiffies; timeout--)
+ {
+ for ( ;i!=0;i--)
+ {
+ j=inb(CDi_status);
+ if (!(j&s_not_data_ready)) break;
+ if (!(j&s_not_result_ready)) break;
+ if (j&s_attention) break;
+ }
+ if (i != 0 || timeout <= jiffies) break;
+ sbp_sleep(0);
+ i = 1;
+ }
+ if (i==0) { DPRINTF((DBG_INF,"SBPCD: STATUS TIMEOUT AFTER READ")); }
+ if (!(j&s_attention))
+ {
+ DPRINTF((DBG_INF,"SBPCD: sbp_data: timeout waiting DRV_ATTN - retrying\n"));
+ i=DriveReset(); /* ugly fix to prevent a hang */
+#if SBPCD_DIS_IRQ
+ sti();
+#endif SBPCD_DIS_IRQ
+ return (0);
+ }
+#if SBPCD_DIS_IRQ
+ sti();
+#endif SBPCD_DIS_IRQ
+ }
+
+ do
+ {
+ if (!new_drive) xx_ReadStatus();
+ i=ResponseStatus(); /* builds status_byte, returns orig. status (old) or faked p_success_old (new) */
+ if (i<0) { DPRINTF((DBG_INF,"SBPCD: xx_ReadStatus error after read: %02X\n",
+ DS[d].status_byte));
+ return (0);
+ }
+ }
+ while ((!new_drive)&&(!st_check)&&(!(i&p_success_old)));
+ if (st_check)
+ {
+ i=xx_ReadError();
+ DPRINTF((DBG_INF,"SBPCD: xx_ReadError was necessary after read: %02X\n",i));
+ return (0);
+ }
+
+ DS[d].sbp_first_frame = CURRENT -> sector / 4;
+ DS[d].sbp_last_frame = DS[d].sbp_first_frame + DS[d].sbp_read_frames - 1;
+ sbp_transfer();
+ return (1);
+}
+/*==========================================================================*/
+/*==========================================================================*/
+/*
+ * Open the device special file. Check that a disk is in. Read TOC.
+ */
+int sbpcd_open(struct inode *ip, struct file *fp)
+{
+ int i;
+
+ if (ndrives==0) return (-ENXIO); /* no hardware */
+
+ i = MINOR(ip->i_rdev);
+ if ( (i<0) || (i>=NR_SBPCD) )
+ {
+ DPRINTF((DBG_INF,"SBPCD: open: bad device: %d\n", i));
+ return (-ENODEV); /* no such drive */
+ }
+ switch_drive(i);
+
+ if (!st_spinning) xx_SpinUp();
+
+ flags_cmd_out |= f_respo2;
+ xx_ReadStatus(); /* command: give 1-byte status */
+ i=ResponseStatus();
+ if (i<0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: sbpcd_open: xx_ReadStatus timed out\n"));
+ return (-EIO); /* drive doesn't respond */
+ }
+ DPRINTF((DBG_STA,"SBPCD: sbpcd_open: status %02X\n", DS[d].status_byte));
+ if (!st_door_closed||!st_caddy_in)
+ {
+ DPRINTF((DBG_INF,"SBPCD: sbpcd_open: no disk in drive\n"));
+ return (-EIO);
+ }
+
+/*
+ * we could try to keep an "open" counter here and lock the door if 0->1.
+ * not done yet.
+ */
+
+
+ if (!st_spinning) xx_SpinUp();
+
+ i=DiskInfo();
+ if ((DS[d].ored_ctl_adr&0x40)==0)
+ DPRINTF((DBG_INF,"SBPCD: CD contains no data tracks.\n"));
+ return (0);
+}
+/*==========================================================================*/
+/*
+ * On close, we flush all sbp blocks from the buffer cache.
+ */
+static void sbpcd_release(struct inode * ip, struct file * file)
+{
+ int i;
+/*
+ * we could try to count down an "open" counter here
+ * and unlock the door if zero.
+ * not done yet.
+ */
+
+ i = MINOR(ip->i_rdev);
+ if ( (i<0) || (i>=NR_SBPCD) )
+ {
+ DPRINTF((DBG_INF,"SBPCD: release: bad device: %d\n", i));
+ return;
+ }
+ switch_drive(i);
+
+ DS[d].sbp_first_frame=DS[d].sbp_last_frame=-1;
+ sync_dev(ip->i_rdev); /* nonsense if read only device? */
+ invalidate_buffers(ip->i_rdev);
+ DS[d].diskstate_flags &= ~cd_size_bit;
+}
+/*==========================================================================*/
+/*
+ *
+ */
+static struct file_operations sbpcd_fops =
+{
+ NULL, /* lseek - default */
+ block_read, /* read - general block-dev read */
+ block_write, /* write - general block-dev write */
+ NULL, /* readdir - bad */
+ NULL, /* select */
+ sbpcd_ioctl, /* ioctl */
+ NULL, /* mmap */
+ sbpcd_open, /* open */
+ sbpcd_release /* release */
+};
+/*==========================================================================*/
+/*
+ * SBP interrupt descriptor
+ */
+#if SBPCD_USE_IRQ
+static struct sigaction sbpcd_sigaction =
+{
+ sbpcd_interrupt,
+ 0,
+ SA_INTERRUPT,
+ NULL
+};
+#endif SBPCD_USE_IRQ
+/*==========================================================================*/
+/*
+ * accept "kernel command line" parameters
+ * (suggested by Peter MacDonald with SLS 1.03)
+ *
+ * use: tell LILO:
+ * sbpcd=0x230,SoundBlaster
+ * or
+ * sbpcd=0x300,LaserMate
+ *
+ * (upper/lower case sensitive here!!!).
+ *
+ * the address value has to be the TRUE CDROM PORT ADDRESS -
+ * not the soundcard base address.
+ *
+ */
+void sbpcd_setup(char *s, int *p)
+{
+ DPRINTF((DBG_INI,"SBPCD: sbpcd_setup called with %04X,%s\n",p[1], s));
+ if (!strcmp(s,str_sb)) sbpro_type=1;
+ else sbpro_type=0;
+ if (p[0]>0) sbpcd_ioaddr=p[1];
+
+ CDo_command=sbpcd_ioaddr;
+ CDi_info=sbpcd_ioaddr;
+ CDi_status=sbpcd_ioaddr+1;
+ CDo_reset=sbpcd_ioaddr+2;
+ CDo_enable=sbpcd_ioaddr+3;
+ if (sbpro_type==1)
+ {
+ MIXER_addr=sbpcd_ioaddr-0x10+0x04;
+ MIXER_data=sbpcd_ioaddr-0x10+0x05;
+ CDo_sel_d_i=sbpcd_ioaddr+1;
+ CDi_data=sbpcd_ioaddr;
+ }
+ else CDi_data=sbpcd_ioaddr+2;
+}
+/*==========================================================================*/
+/*
+ * Test for presence of drive and initialize it. Called at boot time.
+ */
+u_long sbpcd_init(u_long mem_start, u_long mem_end)
+{
+ int i=0, j=0;
+ int addr[2]={1, CDROM_PORT};
+ int port_index;
+
+ DPRINTF((DBG_INF,"SBPCD version %s\n", VERSION));
+
+ DPRINTF((DBG_INF,"SBPCD: Looking for a SoundBlaster/Matsushita CD-ROM drive\n"));
+ DPRINTF((DBG_WRN,"SBPCD: \n"));
+ DPRINTF((DBG_WRN,"SBPCD: = = = = = = = = = = W A R N I N G = = = = = = = = = =\n"));
+ DPRINTF((DBG_WRN,"SBPCD: Auto-Probing can cause a hang (f.e. touching an ethernet card).\n"));
+ DPRINTF((DBG_WRN,"SBPCD: If that happens, you have to reboot and use the\n"));
+ DPRINTF((DBG_WRN,"SBPCD: LILO (kernel) command line feature like:\n"));
+ DPRINTF((DBG_WRN,"SBPCD: \n"));
+ DPRINTF((DBG_WRN,"SBPCD: LILO boot: linux sbpcd=0x230,SoundBlaster\n"));
+ DPRINTF((DBG_WRN,"SBPCD: or like:\n"));
+ DPRINTF((DBG_WRN,"SBPCD: LILO boot: linux sbpcd=0x300,LaserMate\n"));
+ DPRINTF((DBG_WRN,"SBPCD: \n"));
+ DPRINTF((DBG_WRN,"SBPCD: with your REAL address.\n"));
+ DPRINTF((DBG_WRN,"SBPCD: = = = = = = = = = = END of WARNING = = = = = = = = = =\n"));
+ DPRINTF((DBG_WRN,"SBPCD: \n"));
+ sti(); /* to avoid possible "printk" bug */
+
+ autoprobe[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */
+ autoprobe[1]=sbpro_type; /* possibly changed by kernel command line */
+
+ for (port_index=0;port_index<NUM_AUTOPROBE;port_index+=2)
+ {
+ addr[1]=autoprobe[port_index];
+ if (check_region(addr[1],4)) continue;
+ DPRINTF((DBG_INI,"SBPCD: check_region done.\n"));
+ if (autoprobe[port_index+1]==0) type=str_lm;
+ else type=str_sb;
+ sbpcd_setup(type, addr);
+ DPRINTF((DBG_INF,"SBPCD: Trying to detect a %s CD-ROM drive at 0x%X.\n",
+ type, CDo_command));
+
+ DPRINTF((DBG_INF,"SBPCD: - "));
+ sti(); /* to avoid possible "printk" bug */
+ i=check_drives();
+ DPRINTF((DBG_INI,"SBPCD: check_drives done.\n"));
+ sti(); /* to avoid possible "printk" bug */
+ if (i>=0) break; /* drive found */
+ printk ("\n");
+ sti(); /* to avoid possible "printk" bug */
+ } /* end of cycling through the set of possible I/O port addresses */
+
+ if (ndrives==0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: No drive found.\n"));
+ sti();
+ return (mem_start);
+ }
+
+ DPRINTF((DBG_INF,"SBPCD: %d %s CD-ROM drive(s) at 0x%04X.\n",
+ ndrives, type, CDo_command));
+ sti(); /* to avoid possible "printk" bug */
+ check_datarate();
+ DPRINTF((DBG_INI,"SBPCD: check_datarate done.\n"));
+ sti(); /* to avoid possible "printk" bug */
+
+ for (j=0;j<NR_SBPCD;j++)
+ {
+ if (DS[j].drv_minor==-1) continue;
+ switch_drive(j);
+ xy_DriveReset();
+ if (!st_spinning) xx_SpinUp();
+ DS[d].sbp_first_frame = -1; /* First frame in buffer */
+ DS[d].sbp_last_frame = -1; /* Last frame in buffer */
+ DS[d].sbp_read_frames = 0; /* Number of frames being read to buffer */
+ DS[d].sbp_current = 0; /* Frame being currently read */
+ DS[d].CD_changed=1;
+ DS[d].frame_size=CD_FRAMESIZE;
+
+ xx_ReadStatus();
+ i=ResponseStatus(); /* returns orig. status or p_busy_new */
+ if (i<0)
+ DPRINTF((DBG_INF,"SBPCD: init: ResponseStatus returns %02X\n",i));
+ else
+ {
+ if (st_check)
+ {
+ i=xx_ReadError();
+ DPRINTF((DBG_INI,"SBPCD: init: xx_ReadError returns %d\n",i));
+ sti(); /* to avoid possible "printk" bug */
+ }
+ }
+ DPRINTF((DBG_INI,"SBPCD: init: first GetStatus: %d\n",i));
+ sti(); /* to avoid possible "printk" bug */
+ if (DS[d].error_byte==aud_12)
+ {
+ do { i=GetStatus();
+ DPRINTF((DBG_INI,"SBPCD: init: second GetStatus: %02X\n",i));
+ sti(); /* to avoid possible "printk" bug */
+ if (i<0) break;
+ if (!st_caddy_in) break;
+ }
+ while (!st_diskok);
+ }
+ i=SetSpeed();
+ if (i>=0) DS[d].CD_changed=1;
+ }
+
+ if (sbpro_type)
+ {
+ OUT(MIXER_addr,MIXER_CD_Volume);
+ OUT(MIXER_data,0xCC); /* one nibble per channel */
+ }
+
+ if (register_blkdev(MATSUSHITA_CDROM_MAJOR, "sbpcd", &sbpcd_fops) != 0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: Can't get MAJOR %d for Matsushita CDROM\n",
+ MATSUSHITA_CDROM_MAJOR));
+ sti(); /* to avoid possible "printk" bug */
+ return (mem_start);
+ }
+ blk_dev[MATSUSHITA_CDROM_MAJOR].request_fn = DEVICE_REQUEST;
+ read_ahead[MATSUSHITA_CDROM_MAJOR] = 4; /* just one frame */
+
+ snarf_region(CDo_command,4);
+
+#if SBPCD_USE_IRQ
+ if (irqaction(SBPCD_INTR_NR, &sbpcd_sigaction))
+ {
+ DPRINTF((DBG_INF,"SBPCD: Can't get IRQ%d for sbpcd driver\n",
+ SBPCD_INTR_NR));
+ sti(); /* to avoid possible "printk" bug */
+ }
+#endif SBPCD_USE_IRQ
+
+/*
+ * allocate memory for the frame buffers
+ */
+ for (j=0;j<NR_SBPCD;j++)
+ {
+ if (DS[j].drv_minor==-1) continue;
+ DS[j].sbp_buf=(u_char *)mem_start;
+ mem_start += SBP_BUFFER_FRAMES*CD_FRAMESIZE;
+ }
+ DPRINTF((DBG_INF,"SBPCD: init done.\n"));
+ sti(); /* to avoid possible "printk" bug */
+ return (mem_start);
+}
+/*==========================================================================*/
+/*
+ * adopted from sr.c
+ *
+ * Check if the media has changed in the CD-ROM drive.
+ * used externally (isofs/inode.c) - but still does not work.
+ *
+ */
+int check_sbpcd_media_change(int full_dev, int unused_minor)
+{
+ int st;
+
+ if (MAJOR(full_dev) != MATSUSHITA_CDROM_MAJOR)
+ {
+ DPRINTF((DBG_INF,"SBPCD: media_check: invalid device.\n"));
+ return (-1);
+ }
+
+ xx_ReadStatus(); /* command: give 1-byte status */
+ st=ResponseStatus();
+ DPRINTF((DBG_CHK,"SBPCD: media_check: %02X\n",DS[d].status_byte));
+ if (st<0)
+ {
+ DPRINTF((DBG_INF,"SBPCD: media_check: ResponseStatus error.\n"));
+ return (1); /* status not obtainable */
+ }
+ if (DS[d].CD_changed==0xFF) DPRINTF((DBG_CHK,"SBPCD: media_check: \"changed\" assumed.\n"));
+ if (!st_spinning) DPRINTF((DBG_CHK,"SBPCD: media_check: motor off.\n"));
+ if (!st_door_closed)
+ {
+ DPRINTF((DBG_CHK,"SBPCD: media_check: door open.\n"));
+ DS[d].CD_changed=0xFF;
+ }
+ if (!st_caddy_in)
+ {
+ DPRINTF((DBG_CHK,"SBPCD: media_check: no disk in drive.\n"));
+ DS[d].CD_changed=0xFF;
+ }
+ if (!st_diskok) DPRINTF((DBG_CHK,"SBPCD: media_check: !st_diskok.\n"));
+
+#if 0000
+ if (DS[d].CD_changed==0xFF)
+ {
+ DS[d].CD_changed=1;
+ return (1); /* driver had a change detected before */
+ }
+#endif 0000 /* seems to give additional errors at the moment */
+
+ if (!st_diskok) return (1); /* disk not o.k. */
+ if (!st_caddy_in) return (1); /* disk removed */
+ if (!st_door_closed) return (1); /* door open */
+ return (0);
+}
+/*==========================================================================*/
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 690250b..2a72deb 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -213,7 +213,7 @@ static int screen_size = 0;
#define VT102ID "\033[?6c"
static unsigned char * translations[] = {
-/* 8-bit Latin-1 mapped to the PC charater set: '\0' means non-printable */
+/* 8-bit Latin-1 mapped to the PC character set: '\0' means non-printable */
(unsigned char *)
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0"
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 8f4a744..c443c3a 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -213,24 +213,9 @@ static int set_termios_2(struct tty_struct * tty, struct termios * termios)
wake_up_interruptible(&tty->link->secondary.proc_list);
}
-#if 0
- /* puting mpty's into echo mode is very bad, and I think under
- some situations can cause the kernel to do nothing but
- copy characters back and forth. -RAB */
- /* This can no longer happen because a set_termios is redirected
- to the pty slave. -- jrs */
- if (IS_A_PTY_MASTER(channel)) tty->termios->c_lflag &= ~ECHO;
-#endif
-
unset_locked_termios(tty->termios, &old_termios,
termios_locked[tty->line]);
-#if 0
- retval = tty_set_ldisc(tty, tty->termios->c_line);
- if (retval)
- return retval;
-#endif
-
if (tty->set_termios)
(*tty->set_termios)(tty, &old_termios);
diff --git a/drivers/net/CONFIG b/drivers/net/CONFIG
index 882a654..cb9bbed 100644
--- a/drivers/net/CONFIG
+++ b/drivers/net/CONFIG
@@ -1,9 +1,12 @@
#
-# Set any special options here. Most drivers will autoprobe/autoIRQ
-# if you set the address or IRQ to zero, so we do that by default.
-# Cards and options supported:
+# This file is used for selecting non-standard netcard options, and
+# need not be modified for typical use.
+#
+# Drivers are *not* selected in this file, but rather with files
+# automatically generated during the top-level kernel configuration.
+#
+# Special options supported, indexed by their 'config' name:
#
-# EI_DEBUG Set the debugging level for 8390-based boards
# CONFIG_WD80x3 The Western Digital (SMC) WD80x3 driver
# WD_SHMEM=xxx Forces the address of the shared memory
# WD_no_mapout Don't map out the shared memory (faster, but
@@ -16,28 +19,37 @@
# rw_bugfix Patch an obscure bug with a version of the 8390.
# CONFIG_HPLAN The HP-LAN driver (for 8390-based boards only).
# rw_bugfix Fix the same obscure bug.
-# CONFIG_EL1 The 3c501 driver (just joking, never released)
# CONFIG_EL2 The 3c503 EtherLink II driver
# EL2_AUI Default to the AUI port instead of the BNC port
# no_probe_nonshared_memory Don't probe for programmed-I/O boards.
# EL2MEMTEST Test shared memory at boot-time.
-# CONFIG_EL3
-# EL3_DEBUG Set the debugging message level.
-# CONFIG_AT1500
-# LANCE_DEBUG Set the debugging message level.
-# DEFAULT_DMA Change the default DMA to other than 5.
# CONFIG_PLIP The Crynwr-protocol PL/IP driver
+# INITIALTIMEOUTFACTOR Timing parameters.
+# MAXTIMEOUTFACTOR
# D_LINK The D-Link DE-600 Portable Ethernet Adaptor.
-# D_LINK_IO The D-Link I/O address (0x378 == default)
-# D_LINK_IRQ The D-Link IRQ number to use (IRQ7 == default)
+# D_LINK_IO The D-Link I/O address (0x378 == typical)
+# D_LINK_IRQ The D-Link IRQ number to use (IRQ7 == typical)
# D_LINK_DEBUG Enable or disable D-Link debugging
#
-OPTS = #-DEI8390=0 -DEI8390_IRQ=0
-WD_OPTS = #-DWD_SHMEM=0
-EL2_OPTS = #-UEL2_AUI
+# The following options exist, but cannot be set in this file.
+# lance.c
+# LANCE_DMA Change the default DMA to other than DMA5.
+# 8390.c
+# NO_PINGPONG Disable ping-pong transmit buffers.
+
+
+# Most drivers also have a *_DEBUG setting that may be adjusted.
+# The 8390 drivers share the EI_DEBUG settting.
+
+# General options for Space.c
+OPTS = # -DETH0_ADDR=0x300 -DETH0_IRQ=11
+
+WD_OPTS = #-DWD_SHMEM=0xDD000
+EL2_OPTS = #-DEL2_AUI
NE_OPTS =
HP_OPTS =
PLIP_OPTS =
+
+# The following are the only parameters that must be set in this file.
DL_OPTS = -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG
-AT_OPTS = # -DLANCE_DMA=5
diff --git a/drivers/net/README.8390 b/drivers/net/README.8390
index 87af97b..e69de29 100644
--- a/drivers/net/README.8390
+++ b/drivers/net/README.8390
@@ -1,96 +0,0 @@
-
-These drivers support all common 8390-based ethernet boards. Currently
-"common" is defined as:
-
- 3Com Products:
-* 3Com 3c503 Board loaned by Chance Reschke, USRA.edu (thanks!)
- 3Com 3c503/16 and excellent documentation provided by 3Com.
-
- Clones-n-things
- NE1000 Novell and Eagle are useless for documentation,
-* NE2000 but copied the designs directly from NatSemi;->.
-
- WD/SMC products
- WD8003
-* WD8013 Board loaned by Russ Nelson, Crynwr Software. Thanks!
-
-* I've seen it work myself!
-
-There is support for the following boards, but since I've only been
-able to borrow a thinnet of an HP ethercard I've relied upon reports
-from others:
-
- HP LAN adaptors
-** HP27245
-** HP27247
-** HP27250
-
-Thanks are due to the dozens of alpha testers. Special thanks are due
-to Chance Reschke <@usra.edu> and Russ Nelson <@crynwr.com> for
-loaning me ethercards.
-
-The following addresses are autoprobed, in this order:
-wd.c: 0x300, 0x280, 0x380, 0x240
-3c503: 0x300, 0x310, 0x330, 0x350, 0x250, 0x280, 0x2a0, 0x2e0
-ne.c: 0x300, 0x280, 0x320, 0x340, 0x360
-hp.c: 0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240
-
-80x3 clones that are reported to work:
- LANNET LEC-45
-
-"NE2000" clones that are reported to work:
- Alta Combo(NE2000 clone)
- Aritsoft LANtastic AE-2 (NE2000 clone w/ extra memory)
- Asante Etherpak 2001/2003
- D-Link Ethernet II
- LTC E-NET/16 P/N: 8300-200-002 (lipka@lip.hanse.de)
- Network Solutions HE-203
- SVEC 4 Dimension Ethernet
- 4-Dimension FD0490 EtherBoard16
- Cabletron products:
- E1010 No ID PROM and sketchy info from Ctron means you'll
- E1010-x have to compile-in information about your board.
- E2010
- E2010-x
- N.B. The E2100 will not work with Linux until Cabletron
- releases the programming information!
-
-Important defines
-
-For Space.c
-#define EI8390 0 /* The base address of your ethercard. */
-#define EI8390_IRQ 0 /* and the interrupt you want to use. */
- /* '0' means autoconfigure */
-For 8390.c
-#define EI_DEBUG 2 /* Use '0' for no messages. */
-#define EL2 /* For the 3c503 driver. */
-#define NE2000 /* For the NE1000/NE2000/Ctron driver. */
-#define WD80x3 /* For the WD8003/WD8013 driver. */
-#define HPLAN /* For the HP27xxx driver. */
-
-For the individual drivers
-
-EI8390 Define (probably in autoconf.h or config.site.h) this to the base
- address of your ethernet card.
-EI8390_IRQ Define (probably in autoconf.h or config.site.h) this to the
- IRQ line of your ethernet card. Most drivers convert a IRQ2 to an
- IRQ9 for you, so don't be surprised.
-EI_DEBUG Set to the desired numeric debugging level. Use 3 or
- greater when actively debugging a problem, '1' for a
- casual interest in what's going on, and '0' for normal
- use.
-NO_PINGPONG
- Define this if you don't want ping-pong transmit buffers.
-EL2_AUI
- Define for this if you are using the 3c503 and use the AUI/DIX
- connector rather than the built-in thin-net transceiver.
-WD_SHMEM
- Define this to override the shared memory address used by the
- WD driver. This should only be necessary for jumpered ethercards.
-
-If you have a Cabletron ethercard you might want to look at ne.c:neprobe()
-for info on how to enable more packet buffer space.
-
-ETHERLINK1_IRQ
-ETHERLINK1 Define these to the base address and IRQ of a 3c501 (NOT 3c503)
- card. Refer to net/tcp/Space.c.
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index 9ad85fd..e198d55 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -17,7 +17,7 @@
/* Routines for the NatSemi-based designs (NE[12]000). */
static char *version =
- "ne.c:v0.99-15 1/19/93 Donald Becker (becker@super.org)\n";
+ "ne.c:v0.99-14a 12/3/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
@@ -123,10 +123,6 @@ static int neprobe1(int ioaddr, struct device *dev, int verbose)
printk("NE*000 ethercard probe at %#3x:", ioaddr);
- /* First hard-reset the ethercard. */
- i = inb_p(ioaddr + NE_RESET);
- outb_p(i, ioaddr + NE_RESET);
-
/* Read the 16 bytes of station address prom, returning 1 for
an eight-bit interface and 2 for a 16-bit interface.
We must first initialize registers, similar to NS8390_init(eifdev, 0).
@@ -162,8 +158,8 @@ static int neprobe1(int ioaddr, struct device *dev, int verbose)
/* We must set the 8390 for word mode, AND RESET IT. */
int tmp;
outb_p(0x49, ioaddr + EN0_DCFG);
- tmp = inb_p(ioaddr + NE_RESET);
- outb(tmp, ioaddr + NE_RESET);
+ tmp = inb_p(NE_BASE + NE_RESET);
+ outb(tmp, NE_BASE + NE_RESET);
/* Un-double the SA_prom values. */
for (i = 0; i < 16; i++)
SA_prom[i] = SA_prom[i+i];
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 550d792..d800d59 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -30,6 +30,9 @@ extern int check_cdu31a_media_change(int, int);
#if defined(CONFIG_MCD)
extern int check_mcd_media_change(int, int);
#endif
+#if defined (CONFIG_SBPCD)
+extern int check_sbpcd_media_change(int, int);
+#endif CONFIG_SBPCD
#ifdef LEAK_CHECK
static int check_malloc = 0;
@@ -288,6 +291,13 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
goto out;
}
#endif
+#if defined(CONFIG_SBPCD)
+ if (MAJOR(s->s_dev) == MATSUSHITA_CDROM_MAJOR) {
+ if (check_sbpcd_media_change(s->s_dev,0))
+ goto out;
+ };
+#endif CONFIG_SBPCD
+
return s;
out: /* Kick out for various error conditions */
brelse(bh);
diff --git a/fs/open.c b/fs/open.c
index b7dc800..88a5591 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -225,6 +225,7 @@ asmlinkage int sys_fchdir(unsigned int fd)
return -EACCES;
iput(current->pwd);
current->pwd = inode;
+ inode->i_count++;
return (0);
}
diff --git a/include/linux/major.h b/include/linux/major.h
index 9990250..8b3a8ab 100644
--- a/include/linux/major.h
+++ b/include/linux/major.h
@@ -42,7 +42,7 @@
* 22 - (at2disk)
* 23 - mitsumi cdrom
* 24 - sony535 cdrom
- * 25 -
+ * 25 - matsushita cdrom minors 0..3
* 26 -
* 27 - qic117 tape
*/
@@ -71,6 +71,7 @@
/* unused: 22 */
#define MITSUMI_CDROM_MAJOR 23
#define CDU535_CDROM_MAJOR 24
+#define MATSUSHITA_CDROM_MAJOR 25
#define QIC117_TAPE_MAJOR 27
/*
diff --git a/include/linux/sbpcd.h b/include/linux/sbpcd.h
index e69de29..880781f 100644
--- a/include/linux/sbpcd.h
+++ b/include/linux/sbpcd.h
@@ -0,0 +1,473 @@
+/*
+ * sbpcd.h Specify interface address and interface type here.
+ */
+
+/*
+ * these definitions can get overridden by the kernel command line
+ * ("lilo boot option"). Examples:
+ * sbpcd=0x230,SoundBlaster
+ * or
+ * sbpcd=0x300,LaserMate
+ * these strings are case sensitive !!!
+ */
+
+/*
+ * change this to select the type of your interface board:
+ *
+ * set SBPRO to 1 for "true" SoundBlaster card
+ * set SBPRO to 0 for "poor" (no sound) interface cards
+ * and for "compatible" soundcards.
+ *
+ * most "compatible" sound boards like Galaxy need to set SBPRO to 0 !!!
+ * if SBPRO gets set wrong, the drive will get found - but any
+ * data access will give errors (audio access will work).
+ * The OmniCD interface card from CreativeLabs needs SBPRO 1.
+ *
+ * mail to emoenke@gwdg.de if your "compatible" card needs SBPRO 1
+ * (currently I do not know any "compatible" with SBPRO 1)
+ * then I can include better information with the next release.
+ */
+#define SBPRO 1
+
+/*
+ * put your CDROM port base address here:
+ * SBPRO addresses typically are 0x0230 (=0x220+0x10), 0x0250, ...
+ * LASERMATE (CI-101P) adresses typically are 0x0300, 0x0310, ...
+ * there are some soundcards on the market with 0x0630, 0x0650, ...
+ *
+ * obey! changed against v0.4 !!!
+ * for SBPRO cards, specify the CDROM address - no longer the audio address!
+ * example: if your SBPRO audio address is 0x220, specify 0x230.
+ *
+ * a fill-in is not always necessary - the driver does auto-probing now,
+ * with the here specified address first...
+ */
+#define CDROM_PORT 0x0230
+
+
+/*==========================================================================*/
+/*==========================================================================*/
+/*
+ * nothing to change below here if you are not experimenting
+ */
+/*==========================================================================*/
+/*==========================================================================*/
+/*
+ * Debug output levels
+ */
+#define DBG_INF 1 /* necessary information */
+#define DBG_IRQ 2 /* interrupt trace */
+#define DBG_REA 3 /* "read" status trace */
+#define DBG_CHK 4 /* "media check" trace */
+#define DBG_TIM 5 /* datarate timer test */
+#define DBG_INI 6 /* initialization trace */
+#define DBG_TOC 7 /* tell TocEntry values */
+#define DBG_IOC 8 /* ioctl trace */
+#define DBG_STA 9 /* "ResponseStatus" trace */
+#define DBG_ERR 10 /* "xx_ReadError" trace */
+#define DBG_CMD 11 /* "cmd_out" trace */
+#define DBG_WRN 12 /* give explanation before auto-probing */
+#define DBG_MUL 13 /* multi session code test */
+#define DBG_ID 14 /* "drive_id !=0" test code */
+#define DBG_IOX 15 /* some special information */
+#define DBG_DID 16 /* drive ID test */
+#define DBG_RES 17 /* drive reset info */
+#define DBG_SPI 18 /* SpinUp test */
+#define DBG_000 19 /* unnecessary information */
+
+/*==========================================================================*/
+/*==========================================================================*/
+
+/*
+ * bits of flags_cmd_out:
+ */
+#define f_respo3 0x100
+#define f_putcmd 0x80
+#define f_respo2 0x40
+#define f_lopsta 0x20
+#define f_getsta 0x10
+#define f_ResponseStatus 0x08
+#define f_obey_p_check 0x04
+#define f_bit1 0x02
+#define f_wait_if_busy 0x01
+
+/*
+ * diskstate_flags:
+ */
+#define upc_bit 0x40
+#define volume_bit 0x20
+#define toc_bit 0x10
+#define multisession_bit 0x08
+#define cd_size_bit 0x04
+#define subq_bit 0x02
+#define frame_size_bit 0x01
+
+/*
+ * disk states (bits of diskstate_flags):
+ */
+#define upc_valid (DS[d].diskstate_flags&upc_bit)
+#define volume_valid (DS[d].diskstate_flags&volume_bit)
+#define toc_valid (DS[d].diskstate_flags&toc_bit)
+#define multisession_valid (DS[d].diskstate_flags&multisession_bit)
+#define cd_size_valid (DS[d].diskstate_flags&cd_size_bit)
+#define subq_valid (DS[d].diskstate_flags&subq_bit)
+#define frame_size_valid (DS[d].diskstate_flags&frame_size_bit)
+
+
+/*
+ * bits of the status_byte (result of xx_ReadStatus):
+ */
+#define p_door_closed 0x80
+#define p_caddy_in 0x40
+#define p_spinning 0x20
+#define p_check 0x10
+#define p_busy_new 0x08
+#define p_door_locked 0x04
+#define p_bit_1 0x02
+#define p_disk_ok 0x01
+/*
+ * "old" drives status result bits:
+ */
+#define p_caddin_old 0x40
+#define p_success_old 0x08
+#define p_busy_old 0x04
+
+/*
+ * used drive states:
+ */
+#define st_door_closed (DS[d].status_byte&p_door_closed)
+#define st_caddy_in (DS[d].status_byte&p_caddy_in)
+#define st_spinning (DS[d].status_byte&p_spinning)
+#define st_check (DS[d].status_byte&p_check)
+#define st_busy (DS[d].status_byte&p_busy_new)
+#define st_door_locked (DS[d].status_byte&p_door_locked)
+#define st_diskok (DS[d].status_byte&p_disk_ok)
+
+/*
+ * bits of the CDi_status register:
+ */
+#define s_not_result_ready 0x04 /* 0: "result ready" */
+#define s_not_data_ready 0x02 /* 0: "data ready" */
+#define s_attention 0x01 /* 1: "attention required" */
+/*
+ * usable as:
+ */
+#define DRV_ATTN ((inb(CDi_status)&s_attention)!=0)
+#define DATA_READY ((inb(CDi_status)&s_not_data_ready)==0)
+#define RESULT_READY ((inb(CDi_status)&s_not_result_ready)==0)
+
+/*
+ * drive types (firmware versions):
+ */
+#define drv_199 0 /* <200 */
+#define drv_200 1 /* <201 */
+#define drv_201 2 /* <210 */
+#define drv_210 3 /* <211 */
+#define drv_211 4 /* <300 */
+#define drv_300 5 /* else */
+#define drv_099 0x10 /* new, <100 */
+#define drv_100 0x11 /* new, >=100 */
+#define drv_new 0x10 /* all new drives have that bit set */
+#define drv_old 0x00 /* */
+
+/*
+ * drv_099 and drv_100 are the "new" drives
+ */
+#define new_drive (DS[d].drv_type&0x10)
+
+/*
+ * audio states:
+ */
+#define audio_playing 2
+#define audio_pausing 1
+
+/*
+ * drv_pattern, drv_options:
+ */
+#define speed_auto 0x80
+#define speed_300 0x40
+#define speed_150 0x20
+#define sax_a 0x04
+#define sax_xn2 0x02
+#define sax_xn1 0x01
+
+/*
+ * values of cmd_type (0 else):
+ */
+#define cmd_type_READ_M1 0x01 /* "data mode 1": 2048 bytes per frame */
+#define cmd_type_READ_M2 0x02 /* "data mode 2": 12+2048+280 bytes per frame */
+#define cmd_type_READ_SC 0x04 /* "subchannel info": 96 bytes per frame */
+
+/*
+ * sense byte: used only if new_drive
+ * only during cmd 09 00 xx ah al 00 00
+ *
+ * values: 00
+ * 82
+ * xx from infobuf[0] after 85 00 00 00 00 00 00
+ */
+
+
+#define CD_MINS 75 /* minutes per CD */
+#define CD_SECS 60 /* seconds per minutes */
+#define CD_FRAMES 75 /* frames per second */
+#define CD_FRAMESIZE 2048 /* bytes per frame, data mode */
+#define CD_FRAMESIZE_XA 2340 /* bytes per frame, "xa" mode */
+#define CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */
+#define CD_BLOCK_OFFSET 150 /* offset of first logical frame */
+
+
+/* audio status (bin) */
+#define aud_00 0x00 /* Audio status byte not supported or not valid */
+#define audx11 0x0b /* Audio play operation in progress */
+#define audx12 0x0c /* Audio play operation paused */
+#define audx13 0x0d /* Audio play operation successfully completed */
+#define audx14 0x0e /* Audio play operation stopped due to error */
+#define audx15 0x0f /* No current audio status to return */
+
+/* audio status (bcd) */
+#define aud_11 0x11 /* Audio play operation in progress */
+#define aud_12 0x12 /* Audio play operation paused */
+#define aud_13 0x13 /* Audio play operation successfully completed */
+#define aud_14 0x14 /* Audio play operation stopped due to error */
+#define aud_15 0x15 /* No current audio status to return */
+
+/*============================================================================
+==============================================================================
+
+COMMAND SET of "old" drives like CR-521, CR-522
+ (the CR-562 family is different):
+
+No. Command Code
+--------------------------------------------
+
+Drive Commands:
+ 1 Seek 01
+ 2 Read Data 02
+ 3 Read XA-Data 03
+ 4 Read Header 04
+ 5 Spin Up 05
+ 6 Spin Down 06
+ 7 Diagnostic 07
+ 8 Read UPC 08
+ 9 Read ISRC 09
+10 Play Audio 0A
+11 Play Audio MSF 0B
+12 Play Audio Track/Index 0C
+
+Status Commands:
+13 Read Status 81
+14 Read Error 82
+15 Read Drive Version 83
+16 Mode Select 84
+17 Mode Sense 85
+18 Set XA Parameter 86
+19 Read XA Parameter 87
+20 Read Capacity 88
+21 Read SUB_Q 89
+22 Read Disc Code 8A
+23 Read Disc Information 8B
+24 Read TOC 8C
+25 Pause/Resume 8D
+26 Read Packet 8E
+27 Read Path Check 00
+
+
+all numbers (lba, msf-bin, msf-bcd, counts) to transfer high byte first
+
+mnemo 7-byte command #bytes response (r0...rn)
+________ ____________________ ____
+
+Read Status:
+status: 81. (1) one-byte command, gives the main
+ status byte
+Read Error:
+check1: 82 00 00 00 00 00 00. (6) r1: audio status
+
+Read Packet:
+check2: 8e xx 00 00 00 00 00. (xx) gets xx bytes response, relating
+ to commands 01 04 05 07 08 09
+
+Play Audio:
+play: 0a ll-bb-aa nn-nn-nn. (0) play audio, ll-bb-aa: starting block (lba),
+ nn-nn-nn: #blocks
+Play Audio MSF:
+ 0b mm-ss-ff mm-ss-ff (0) play audio from/to
+
+Play Audio Track/Index:
+ 0c ...
+
+Pause/Resume:
+pause: 8d pr 00 00 00 00 00. (0) pause (pr=00)
+ resume (pr=80) audio playing
+
+Mode Select:
+ 84 00 nn-nn ??-?? 00 (0) nn-nn: 2048 or 2340
+ possibly defines transfer size
+
+set_vol: 84 83 00 00 sw le 00. (0) sw(itch): lrxxxxxx (off=1)
+ le(vel): min=0, max=FF, else half
+ (firmware 2.11)
+
+Mode Sense:
+get_vol: 85 03 00 00 00 00 00. (2) tell current audio volume setting
+
+Read Disc Information:
+tocdesc: 8b 00 00 00 00 00 00. (6) read the toc descriptor ("msf-bin"-format)
+
+Read TOC:
+tocent: 8c fl nn 00 00 00 00. (8) read toc entry #nn
+ (fl=0:"lba"-, =2:"msf-bin"-format)
+
+Read Capacity:
+capacit: 88 00 00 00 00 00 00. (5) "read CD-ROM capacity"
+
+
+Read Path Check:
+ping: 00 00 00 00 00 00 00. (2) r0=AA, r1=55
+ ("ping" if the drive is connected)
+
+Read Drive Version:
+ident: 83 00 00 00 00 00 00. (12) gives "MATSHITAn.nn"
+ (n.nn = 2.01, 2.11., 3.00, ...)
+
+Seek:
+seek: 01 00 ll-bb-aa 00 00. (0)
+seek: 01 02 mm-ss-ff 00 00. (0)
+
+Read Data:
+read: 02 xx-xx-xx nn-nn fl. (??) read nn-nn blocks of 2048 bytes,
+ starting at block xx-xx-xx
+ fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx
+
+Read XA-Data:
+read: 03 xx-xx-xx nn-nn fl. (??) read nn-nn blocks of 2340 bytes,
+ starting at block xx-xx-xx
+ fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx
+
+Read SUB_Q:
+ 89 fl 00 00 00 00 00. (13) r0: audio status, r4-r7: lba/msf,
+ fl=0: "lba", fl=2: "msf"
+
+Read Disc Code:
+ 8a 00 00 00 00 00 00. (14) possibly extended "check condition"-info
+
+Read Header:
+ 04 00 ll-bb-aa 00 00. (0) 4 bytes response with "check2"
+ 04 02 mm-ss-ff 00 00. (0) 4 bytes response with "check2"
+
+Spin Up:
+ 05 00 ll-bb-aa 00 00. (0) possibly implies a "seek"
+
+Spin Down:
+ 06 ...
+
+Diagnostic:
+ 07 00 ll-bb-aa 00 00. (2) 2 bytes response with "check2"
+ 07 02 mm-ss-ff 00 00. (2) 2 bytes response with "check2"
+
+Read UPC:
+ 08 00 ll-bb-aa 00 00. (16)
+ 08 02 mm-ss-ff 00 00. (16)
+
+Read ISRC:
+ 09 00 ll-bb-aa 00 00. (15) 15 bytes response with "check2"
+ 09 02 mm-ss-ff 00 00. (15) 15 bytes response with "check2"
+
+Set XA Parameter:
+ 86 ...
+
+Read XA Parameter:
+ 87 ...
+
+==============================================================================
+============================================================================*/
+
+/*==========================================================================*/
+/*==========================================================================*/
+
+/*
+ * highest allowed drive number (MINOR+1)
+ * currently only one controller, maybe later up to 4
+ */
+#define NR_SBPCD 4
+
+/*
+ * we try to never disable interrupts - seems to work
+ */
+#define SBPCD_DIS_IRQ 0
+
+/*
+ * we don't use the IRQ line - leave it free for the sound driver
+ */
+#define SBPCD_USE_IRQ 0
+
+/*
+ * you can set the interrupt number of your interface board here:
+ * It is not used at this time. No need to set it correctly.
+ */
+#define SBPCD_INTR_NR 7
+
+/*
+ * "write byte to port"
+ */
+#define OUT(x,y) outb(y,x)
+
+
+#define MIXER_CD_Volume 0x28
+
+/*==========================================================================*/
+/*
+ * use "REP INSB" for strobing the data in:
+ */
+#if PATCHLEVEL<15
+#define READ_DATA(port, buf, nr) \
+__asm__("cld;rep;insb": :"d" (port),"D" (buf),"c" (nr):"cx","dx","di")
+#else
+#define READ_DATA(port, buf, nr) insb(port, buf, nr)
+#endif
+
+/*==========================================================================*/
+/*
+ * to fork and execute a function after some elapsed time:
+ * one "jifs" unit is 10 msec.
+ */
+#define SET_TIMER(func, jifs) \
+ ((timer_table[SBPCD_TIMER].expires = jiffies + jifs), \
+ (timer_table[SBPCD_TIMER].fn = func), \
+ (timer_active |= 1<<SBPCD_TIMER))
+
+#define CLEAR_TIMER timer_active &= ~(1<<SBPCD_TIMER)
+
+/*==========================================================================*/
+/*
+ * Creative Labs Programmers did this:
+ */
+#define MAX_TRACKS 120 /* why more than 99? */
+
+
+/*==========================================================================*/
+/*
+ * To make conversions easier (machine dependent!)
+ */
+typedef union _msf
+{
+ u_int n;
+ u_char c[4];
+}
+MSF;
+
+typedef union _blk
+{
+ u_int n;
+ u_char c[4];
+}
+BLK;
+
+/*==========================================================================*/
+
+
+
+
+
+
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 59ae295..ad23e32 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -30,6 +30,8 @@
* TAPE_QIC02_TIMER timer for QIC-02 tape driver (it's not hardcoded)
*
* MCD_TIMER Mitsumi CD-ROM Timer
+ *
+ * SBPCD_TIMER SoundBlaster/Matsushita/Panasonic CD-ROM timer
*/
#define BLANK_TIMER 0
@@ -48,6 +50,8 @@
#define HD_TIMER2 24
+#define SBPCD_TIMER 25
+
struct timer_struct {
unsigned long expires;
void (*fn)(void);
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 732bd4e..49fdb90 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -294,7 +294,7 @@ struct tty_ldisc {
unsigned int cmd, unsigned long arg);
int (*select)(struct tty_struct * tty, struct inode * inode,
struct file * file, int sel_type,
- select_table *wait);
+ struct select_table_struct *wait);
/*
* The following routines are called from below.
*/
diff --git a/init/main.c b/init/main.c
index 15e3f6b..41309a4 100644
--- a/init/main.c
+++ b/init/main.c
@@ -91,6 +91,9 @@ extern void t128_setup(char *str, int *ints);
extern void generic_NCR5380_setup(char *str, int *intr);
extern void aha152x_setup(char *str, int *ints);
extern void sound_setup(char *str, int *ints);
+#ifdef CONFIG_SBPCD
+extern void sbpcd_setup(char *str, int *ints);
+#endif CONFIG_SBPCD
#ifdef CONFIG_SYSVIPC
extern void ipc_init(void);
@@ -198,6 +201,9 @@ struct {
#ifdef CONFIG_SOUND
{ "sound=", sound_setup },
#endif
+#ifdef CONFIG_SBPCD
+ { "sbpcd=", sbpcd_setup },
+#endif CONFIG_SBPCD
{ 0, 0 }
};
diff --git a/kernel/ksyms.S b/kernel/ksyms.S
index acb4752..d219643 100644
--- a/kernel/ksyms.S
+++ b/kernel/ksyms.S
@@ -9,9 +9,11 @@
_register_chrdev
_unregister_chrdev
-___verify_write
_wake_up_interruptible
+_wp_works_ok
+___verify_write
+
_current
_jiffies
_printk
diff --git a/net/inet/ip.c b/net/inet/ip.c
index af6fdbf..fdef4c6 100644
--- a/net/inet/ip.c
+++ b/net/inet/ip.c
@@ -72,6 +72,8 @@
extern int last_retran;
extern void sort_send(struct sock *sk);
+#define min(a,b) ((a)<(b)?(a):(b))
+
void
ip_print(struct iphdr *ip)
{
@@ -1402,8 +1404,7 @@ ip_queue_xmit(struct sock *sk, struct device *dev,
}
}
sti();
- reset_timer(sk, TIME_WRITE,
- backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
+ reset_timer(sk, TIME_WRITE, sk->rto);
} else {
skb->sk = sk;
}
@@ -1423,14 +1424,16 @@ ip_queue_xmit(struct sock *sk, struct device *dev,
void
-ip_retransmit(struct sock *sk, int all)
+ip_do_retransmit(struct sock *sk, int all)
{
struct sk_buff * skb;
struct proto *prot;
struct device *dev;
+ int retransmits;
prot = sk->prot;
skb = sk->send_head;
+ retransmits = sk->retransmits;
while (skb != NULL) {
dev = skb->dev;
/* I know this can't happen but as it does.. */
@@ -1469,7 +1472,7 @@ ip_retransmit(struct sock *sk, int all)
/* else dev->queue_xmit(skb, dev, SOPRI_NORMAL ); CANNOT HAVE SK=NULL HERE */
}
-oops: sk->retransmits++;
+oops: retransmits++;
sk->prot->retransmits ++;
if (!all) break;
@@ -1477,43 +1480,37 @@ oops: sk->retransmits++;
if (sk->retransmits > sk->cong_window) break;
skb = (struct sk_buff *)skb->link3;
}
-
- /*
- * Increase the RTT time every time we retransmit.
- * This will cause exponential back off on how hard we try to
- * get through again. Once we get through, the rtt will settle
- * back down reasonably quickly.
- */
- sk->backoff++;
- reset_timer(sk, TIME_WRITE, backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
}
-/* Backoff function - the subject of much research */
-int backoff(int n)
+/*
+ * This is the normal code called for timeouts. It does the retransmission
+ * and then does backoff. ip_do_retransmit is separated out because
+ * tcp_ack needs to send stuff from the retransmit queue without
+ * initiating a backoff.
+ */
+
+void
+ip_retransmit(struct sock *sk, int all)
{
- /* Use binary exponential up to retry #4, and quadratic after that
- * This yields the sequence
- * 1, 2, 4, 8, 16, 25, 36, 49, 64, 81, 100 ...
- */
+ ip_do_retransmit(sk, all);
- if(n<0)
- {
- printk("Backoff < 0!\n");
- return 16; /* Make up a value */
- }
-
- if(n <= 4)
- return 1 << n; /* Binary exponential back off */
- else
- {
- if(n<255)
- return n * n; /* Quadratic back off */
- else
- {
- printk("Overloaded backoff!\n");
- return 255*255;
- }
- }
+ /*
+ * Increase the timeout each time we retransmit. Note that
+ * we do not increase the rtt estimate. rto is initialized
+ * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests
+ * that doubling rto each time is the least we can get away with.
+ * In KA9Q, Karns uses this for the first few times, and then
+ * goes to quadratic. netBSD doubles, but only goes up to *64,
+ * and clamps at 1 to 64 sec afterwards. Note that 120 sec is
+ * defined in the protocol as the maximum possible RTT. I guess
+ * we'll have to use something other than TCP to talk to the
+ * University of Mars.
+ */
+
+ sk->retransmits++;
+ sk->backoff++;
+ sk->rto = min(sk->rto << 1, 120*HZ);
+ reset_timer(sk, TIME_WRITE, sk->rto);
}
/*
diff --git a/net/inet/sock.c b/net/inet/sock.c
index 8001bae..37efd6f 100644
--- a/net/inet/sock.c
+++ b/net/inet/sock.c
@@ -843,13 +843,15 @@ inet_create(struct socket *sock, int protocol)
sk->copied_seq = 0;
sk->fin_seq = 0;
sk->proc = 0;
- sk->rtt = TCP_WRITE_TIME;
+ sk->rtt = TCP_WRITE_TIME << 3;
+ sk->rto = TCP_WRITE_TIME;
sk->mdev = 0;
sk->backoff = 0;
sk->packets_out = 0;
sk->cong_window = 1; /* start with only sending one packet at a time. */
- sk->exp_growth = 1; /* if set cong_window grow exponentially every time
- we get an ack. */
+ sk->cong_count = 0;
+ sk->ssthresh = 0;
+ sk->max_window = 0;
sk->urginline = 0;
sk->intr = 0;
sk->linger = 0;
diff --git a/net/inet/sock.h b/net/inet/sock.h
index cbd6027..ee6fb0e 100644
--- a/net/inet/sock.h
+++ b/net/inet/sock.h
@@ -79,7 +79,6 @@ struct sock {
destroy,
ack_timed,
no_check,
- exp_growth,
zapped, /* In ax25 & ipx means not linked */
broadcast,
nonagle;
@@ -103,14 +102,21 @@ struct sock {
unsigned short window;
unsigned short bytes_rcv;
unsigned short mtu;
+ unsigned short max_window;
unsigned short num;
volatile unsigned short cong_window;
+ volatile unsigned short cong_count;
+ volatile unsigned short ssthresh;
volatile unsigned short packets_out;
volatile unsigned short urg;
volatile unsigned short shutdown;
unsigned short mss;
volatile unsigned long rtt;
volatile unsigned long mdev;
+ volatile unsigned long rto;
+/* currently backoff isn't used, but I'm maintaining it in case
+ * we want to go back to a backoff formula that needs it
+ */
volatile unsigned short backoff;
volatile short err;
unsigned char protocol;
diff --git a/net/inet/tcp.c b/net/inet/tcp.c
index 41a3262..9c1223b 100644
--- a/net/inet/tcp.c
+++ b/net/inet/tcp.c
@@ -103,6 +103,7 @@
#define SEQ_TICK 3
unsigned long seq_offset;
+#define LOCALNET_BIGPACKETS
static __inline__ int
min(unsigned int a, unsigned int b)
@@ -177,10 +178,18 @@ static int tcp_select_window(struct sock *sk)
{
int new_window = sk->prot->rspace(sk);
- /* Enforce RFC793 - we've offered it we must live with it */
- if(new_window<sk->window)
- return(sk->window);
-
+/*
+ * two things are going on here. First, we don't ever offer a
+ * window less than min(sk->mtu, MAX_WINDOW/2). This is the
+ * receiver side of SWS as specified in RFC1122.
+ * Second, we always give them at least the window they
+ * had before, in order to avoid retracting window. This
+ * is technically allowed, but RFC1122 advises against it and
+ * in practice it causes trouble.
+ */
+ if (new_window < min(sk->mtu, MAX_WINDOW/2) ||
+ new_window < sk->window)
+ return(sk->window);
return(new_window);
}
@@ -210,18 +219,13 @@ tcp_retransmit(struct sock *sk, int all)
return;
}
-/*
- * If we had the full V-J mechanism, this might be right. But
- * for the moment we want simple slow start after error.
- *
- * if (sk->cong_window > 4)
- * sk->cong_window = sk->cong_window / 2;
- */
-
+ sk->ssthresh = sk->cong_window >> 1; /* remember window where we lost */
+ /* sk->ssthresh in theory can be zero. I guess that's OK */
+ sk->cong_count = 0;
+
sk->cong_window = 1;
- sk->exp_growth = 0;
- /* Do the actuall retransmit. */
+ /* Do the actual retransmit. */
ip_retransmit(sk, all);
}
@@ -638,8 +642,7 @@ static void tcp_send_skb(struct sock *sk, struct sk_buff *skb)
if (before(sk->window_seq, sk->wfront->h.seq) &&
sk->send_head == NULL &&
sk->ack_backlog == 0)
- reset_timer(sk, TIME_PROBE0,
- backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
+ reset_timer(sk, TIME_PROBE0, sk->rto);
} else {
sk->prot->queue_xmit(sk, skb->dev, skb, 0);
}
@@ -918,25 +921,26 @@ tcp_write(struct sock *sk, unsigned char *from,
continue;
}
-#if 0
/*
* We also need to worry about the window.
- * If window < 1/4 offered window, don't use it. That's
- * silly window prevention. What we actually do is
+ * If window < 1/2 the maximum window we've seen from this
+ * host, don't use it. This is sender side
+ * silly window prevention, as specified in RFC1122.
+ * (Note that this is diffferent than earlier versions of
+ * SWS prevention, e.g. RFC813.). What we actually do is
* use the whole MTU. Since the results in the right
* edge of the packet being outside the window, it will
* be queued for later rather than sent.
*/
copy = diff(sk->window_seq, sk->send_seq);
- if (copy < (diff(sk->window_seq, sk->rcv_ack_seq) >> 2))
- copy = sk->mtu;
+ if (sk->max_window > 1) {
+ if (copy < (sk->max_window >> 1))
+ copy = sk->mtu;
+ } else /* no max_window yet, punt this test */
+ copy = sk->mtu;
copy = min(copy, sk->mtu);
copy = min(copy, len);
-#else
- /* This also prevents silly windows by simply ignoring the offered window.. */
- copy = min(sk->mtu, len);
-#endif
/* We should really check the window here also. */
if (sk->packets_out && copy < sk->mtu && !(flags & MSG_OOB)) {
@@ -1780,6 +1784,16 @@ tcp_options(struct sock *sk, struct tcphdr *th)
}
+static inline unsigned long default_mask(unsigned long dst)
+{
+ dst = ntohl(dst);
+ if (IN_CLASSA(dst))
+ return htonl(IN_CLASSA_NET);
+ if (IN_CLASSB(dst))
+ return htonl(IN_CLASSB_NET);
+ return htonl(IN_CLASSC_NET);
+}
+
/*
* This routine handles a connection request.
* It should make sure we haven't already responded.
@@ -1846,8 +1860,13 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
newsk->send_head = NULL;
newsk->send_tail = NULL;
newsk->back_log = NULL;
- newsk->rtt = TCP_CONNECT_TIME;
+ newsk->rtt = TCP_CONNECT_TIME << 3;
+ newsk->rto = TCP_CONNECT_TIME;
newsk->mdev = 0;
+ newsk->max_window = 0;
+ newsk->cong_window = 1;
+ newsk->cong_count = 0;
+ newsk->ssthresh = 0;
newsk->backoff = 0;
newsk->blog = 0;
newsk->intr = 0;
@@ -1903,8 +1922,14 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
/* note use of sk->mss, since user has no direct access to newsk */
if (sk->mss)
newsk->mtu = sk->mss;
- else
- newsk->mtu = 576 - HEADER_SIZE;
+ else {
+#ifdef LOCALNET_BIGPACKETS
+ if ((saddr & default_mask(saddr)) == (daddr & default_mask(daddr)))
+ newsk->mtu = MAX_WINDOW;
+ else
+#endif
+ newsk->mtu = 576 - HEADER_SIZE;
+ }
/* but not bigger than device MTU */
newsk->mtu = min(newsk->mtu, dev->mtu - HEADER_SIZE);
@@ -2036,7 +2061,11 @@ tcp_close(struct sock *sk, int timeout)
case TCP_FIN_WAIT2:
case TCP_LAST_ACK:
/* start a timer. */
- reset_timer(sk, TIME_CLOSE, 4 * sk->rtt);
+ /* original code was 4 * sk->rtt. In converting to the
+ * new rtt representation, we can't quite use that.
+ * it seems to make most sense to use the backed off value
+ */
+ reset_timer(sk, TIME_CLOSE, 4 * sk->rto);
if (timeout) tcp_time_wait(sk);
release_sock(sk);
return; /* break causes a double release - messy */
@@ -2109,8 +2138,7 @@ tcp_close(struct sock *sk, int timeout)
if (sk->wfront == NULL) {
prot->queue_xmit(sk, dev, buff, 0);
} else {
- reset_timer(sk, TIME_WRITE,
- backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
+ reset_timer(sk, TIME_WRITE, sk->rto);
buff->next = NULL;
if (sk->wback == NULL) {
sk->wfront=buff;
@@ -2218,6 +2246,12 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
{
unsigned long ack;
int flag = 0;
+ /*
+ * 1 - there was data in packet as well as ack or new data is sent or
+ * in shutdown state
+ * 2 - data from retransmit queue was acked and removed
+ * 4 - window shrunk or data from retransmit queue was acked and removed
+ */
if(sk->zapped)
return(1); /* Dead, cant ack any more so why bother */
@@ -2227,6 +2261,9 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
"sk->rcv_ack_seq=%d, sk->window_seq = %d\n",
ack, ntohs(th->window), sk->rcv_ack_seq, sk->window_seq));
+ if (ntohs(th->window) > sk->max_window)
+ sk->max_window = ntohs(th->window);
+
if (sk->retransmits && sk->timeout == TIME_KEEPOPEN)
sk->retransmits = 0;
@@ -2309,9 +2346,29 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
/* We don't want too many packets out there. */
if (sk->timeout == TIME_WRITE &&
- sk->cong_window < 2048 && ack != sk->rcv_ack_seq) {
- if (sk->exp_growth) sk->cong_window *= 2;
- else sk->cong_window++;
+ sk->cong_window < 2048 && after(ack, sk->rcv_ack_seq)) {
+/*
+ * This is Jacobson's slow start and congestion avoidance.
+ * SIGCOMM '88, p. 328. Because we keep cong_window in integral
+ * mss's, we can't do cwnd += 1 / cwnd. Instead, maintain a
+ * counter and increment it once every cwnd times. It's possible
+ * that this should be done only if sk->retransmits == 0. I'm
+ * interpreting "new data is acked" as including data that has
+ * been retransmitted but is just now being acked.
+ */
+ if (sk->cong_window < sk->ssthresh)
+ /* in "safe" area, increase */
+ sk->cong_window++;
+ else {
+ /* in dangerous area, increase slowly. In theory this is
+ sk->cong_window += 1 / sk->cong_window
+ */
+ if (sk->cong_count >= sk->cong_window) {
+ sk->cong_window++;
+ sk->cong_count = 0;
+ } else
+ sk->cong_count++;
+ }
}
DPRINTF((DBG_TCP, "tcp_ack: Updating rcv ack sequence.\n"));
@@ -2327,6 +2384,12 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
! before (sk->window_seq, sk->wfront->h.seq)) {
sk->retransmits = 0;
sk->backoff = 0;
+ /* recompute rto from rtt. this eliminates any backoff */
+ sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1;
+ if (sk->rto > 120*HZ)
+ sk->rto = 120*HZ;
+ if (sk->rto < 1*HZ)
+ sk->rto = 1*HZ;
}
}
@@ -2344,23 +2407,36 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
if (sk->retransmits) {
- /* if we're retransmitting, don't start any new
- * packets until after everything in retransmit queue
- * is acked. That's as close as I can come at the
- * moment to slow start the way this code is organized
+ /* we were retransmitting. don't count this in RTT est */
+ flag |= 2;
+
+ /*
+ * even though we've gotten an ack, we're still
+ * retransmitting as long as we're sending from
+ * the retransmit queue. Keeping retransmits non-zero
+ * prevents us from getting new data interspersed with
+ * retransmissions.
*/
+
if (sk->send_head->link3)
sk->retransmits = 1;
else
sk->retransmits = 0;
+
}
- /*
- * need to restart backoff whenever we get a response,
- * or things get impossible if we lose a window-full of
- * data with very small MSS
+ /*
+ * Note that we only reset backoff and rto in the
+ * rtt recomputation code. And that doesn't happen
+ * if there were retransmissions in effect. So the
+ * first new packet after the retransmissions is
+ * sent with the backoff still in effect. Not until
+ * we get an ack from a non-retransmitted packet do
+ * we reset the backoff and rto. This allows us to deal
+ * with a situation where the network delay has increased
+ * suddenly. I.e. Karn's algorithm. (SIGCOMM '87, p5.)
*/
- sk->backoff = 0;
+
/* We have one less packet out there. */
if (sk->packets_out > 0) sk->packets_out --;
DPRINTF((DBG_TCP, "skb=%X skb->h.seq = %d acked ack=%d\n",
@@ -2371,42 +2447,32 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
oskb = sk->send_head;
- /*
- * In theory we're supposed to ignore rtt's when there's
- * retransmission in process. Unfortunately this means
- * that if there's a sharp increase in RTT, we may
- * never get out of retransmission. For the moment
- * ignore the test.
- */
+ if (!(flag&2)) {
+ long m;
- if (/* sk->retransmits == 0 && */ !(flag&2)) {
- long abserr, rtt = jiffies - oskb->when;
-
- /*
- * Berkeley's code puts these limits on a separate timeout
- * field, not on the RTT estimate itself. However the way this
- * code is done, that would complicate things. If we're going
- * to clamp the values, we have to do so before calculating
- * the mdev, or we'll get unreasonably large mdev's. Experience
- * shows that with a minium rtt of .1 sec, we get spurious
- * retransmits, due to delayed acks on some hosts. Berkeley uses
- * 1 sec, so why not?
+ /* The following amusing code comes from Jacobson's
+ * article in SIGCOMM '88. Note that rtt and mdev
+ * are scaled versions of rtt and mean deviation.
+ * This is designed to be as fast as possible
+ * m stands for "measurement".
*/
- if (rtt < 100) rtt = 100; /* 1 sec */
- if (rtt > 12000) rtt = 12000; /* 2 min - max rtt allowed by protocol */
-
- if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) {
- /* first ack, so nothing else to average with */
- sk->rtt = rtt;
- sk->mdev = rtt; /* overcautious initial estimate */
- }
- else {
- abserr = (rtt > sk->rtt) ? rtt - sk->rtt : sk->rtt - rtt;
- sk->rtt = (7 * sk->rtt + rtt) >> 3;
- sk->mdev = (3 * sk->mdev + abserr) >> 2;
- }
+ m = jiffies - oskb->when; /* RTT */
+ m -= (sk->rtt >> 3); /* m is now error in rtt est */
+ sk->rtt += m; /* rtt = 7/8 rtt + 1/8 new */
+ if (m < 0)
+ m = -m; /* m is now abs(error) */
+ m -= (sk->mdev >> 2); /* similar update on mdev */
+ sk->mdev += m; /* mdev = 3/4 mdev + 1/4 new */
+
+ /* now update timeout. Note that this removes any backoff */
+ sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1;
+ if (sk->rto > 120*HZ)
+ sk->rto = 120*HZ;
+ if (sk->rto < 1*HZ)
+ sk->rto = 1*HZ;
sk->backoff = 0;
+
}
flag |= (2|4);
@@ -2446,8 +2512,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
sk->send_head == NULL &&
sk->ack_backlog == 0 &&
sk->state != TCP_TIME_WAIT) {
- reset_timer(sk, TIME_PROBE0,
- backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
+ reset_timer(sk, TIME_PROBE0, sk->rto);
}
} else {
if (sk->send_head == NULL && sk->ack_backlog == 0 &&
@@ -2461,8 +2526,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
delete_timer(sk);
} else {
if (sk->state != (unsigned char) sk->keepopen) {
- reset_timer(sk, TIME_WRITE,
- backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
+ reset_timer(sk, TIME_WRITE, sk->rto);
}
if (sk->state == TCP_TIME_WAIT) {
reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
@@ -2503,12 +2567,41 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
}
}
+/*
+ * I make no guarantees about the first clause in the following
+ * test, i.e. "(!flag) || (flag&4)". I'm not entirely sure under
+ * what conditions "!flag" would be true. However I think the rest
+ * of the conditions would prevent that from causing any
+ * unnecessary retransmission.
+ * Clearly if the first packet has expired it should be
+ * retransmitted. The other alternative, "flag&2 && retransmits", is
+ * harder to explain: You have to look carefully at how and when the
+ * timer is set and with what timeout. The most recent transmission always
+ * sets the timer. So in general if the most recent thing has timed
+ * out, everything before it has as well. So we want to go ahead and
+ * retransmit some more. If we didn't explicitly test for this
+ * condition with "flag&2 && retransmits", chances are "when + rto < jiffies"
+ * would not be true. If you look at the pattern of timing, you can
+ * show that rto is increased fast enough that the next packet would
+ * almost never be retransmitted immediately. Then you'd end up
+ * waiting for a timeout to send each packet on the retranmission
+ * queue. With my implementation of the Karn sampling algorithm,
+ * the timeout would double each time. The net result is that it would
+ * take a hideous amount of time to recover from a single dropped packet.
+ * It's possible that there should also be a test for TIME_WRITE, but
+ * I think as long as "send_head != NULL" and "retransmit" is on, we've
+ * got to be in real retransmission mode.
+ * Note that ip_do_retransmit is called with all==1. Setting cong_window
+ * back to 1 at the timeout will cause us to send 1, then 2, etc. packets.
+ * As long as no further losses occur, this seems reasonable.
+ */
+
if (((!flag) || (flag&4)) && sk->send_head != NULL &&
- (sk->send_head->when + backoff(sk->backoff) * (2 * sk->mdev + sk->rtt)
- < jiffies)) {
- sk->exp_growth = 0;
- ip_retransmit(sk, 1);
- }
+ (((flag&2) && sk->retransmits) ||
+ (sk->send_head->when + sk->rto < jiffies))) {
+ ip_do_retransmit(sk, 1);
+ reset_timer(sk, TIME_WRITE, sk->rto);
+ }
DPRINTF((DBG_TCP, "leaving tcp_ack\n"));
return(1);
@@ -2979,8 +3072,15 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
/* use 512 or whatever user asked for */
if (sk->mss)
sk->mtu = sk->mss;
- else
- sk->mtu = 576 - HEADER_SIZE;
+ else {
+#ifdef LOCALNET_BIGPACKETS
+ if ((sk->saddr & default_mask(sk->saddr)) ==
+ (sk->daddr & default_mask(sk->daddr)))
+ sk->mtu = MAX_WINDOW;
+ else
+#endif
+ sk->mtu = 576 - HEADER_SIZE;
+ }
/* but not bigger than device MTU */
sk->mtu = min(sk->mtu, dev->mtu - HEADER_SIZE);
@@ -3639,8 +3739,15 @@ tcp_send_probe0(struct sock *sk)
*/
sk->prot->queue_xmit(sk, dev, skb2, 1);
sk->backoff++;
- reset_timer (sk, TIME_PROBE0,
- backoff (sk->backoff) * (2 * sk->mdev + sk->rtt));
+ /*
+ * in the case of retransmissions, there's good reason to limit
+ * rto to 120 sec, as that's the maximum legal RTT on the Internet.
+ * For probes it could reasonably be longer. However making it
+ * much longer could cause unacceptable delays in some situation,
+ * so we might as well use the same value
+ */
+ sk->rto = min(sk->rto << 1, 120*HZ);
+ reset_timer (sk, TIME_PROBE0, sk->rto);
sk->retransmits++;
sk->prot->retransmits ++;
}
diff --git a/net/inet/timer.c b/net/inet/timer.c
index ed5c69b..73d4b24 100644
--- a/net/inet/timer.c
+++ b/net/inet/timer.c
@@ -157,10 +157,9 @@ net_timer (unsigned long data)
* So we need to check for that.
*/
if (sk->send_head) {
- if (jiffies < (sk->send_head->when + backoff (sk->backoff)
- * (2 * sk->mdev + sk->rtt))) {
- reset_timer (sk, TIME_WRITE, (sk->send_head->when
- + backoff (sk->backoff) * (2 * sk->mdev + sk->rtt)) - jiffies);
+ if (jiffies < (sk->send_head->when + sk->rto)) {
+ reset_timer (sk, TIME_WRITE,
+ (sk->send_head->when + sk->rto - jiffies));
release_sock (sk);
break;
}