S: 97078 Wuerzburg
S: Germany
+N: Patrick Volkerding
+E: volkerdi@ftp.cdrom.com
+D: Produced the Slackware distribution, updated the SVGAlib
+D: patches for ghostscript, worked on color 'ls', etc.
+S: 301 15th Street S.
+S: Moorhead, MN 56560
+S: USA
+
N: Juergen Weigert
E: jnweiger@immd4.informatik.uni-erlangen.de
D: The Linux Support Team Erlangen
VERSION = 1
PATCHLEVEL = 1
-SUBLEVEL = 0
+SUBLEVEL = 1
all: Version zImage
-This is release 1.3 of the SoundBlaster Pro (Matsushita, Kotobuki,
+This is release 1.4 of the SoundBlaster Pro (Matsushita, Kotobuki,
Panasonic, CreativeLabs, Aztech) CD-ROM driver for Linux.
The driver is able to drive the whole family of IDE-style
and with "new" drives (which count the releases around 0.75 or
1.00).
-Up to 4 drives are supported. CR-52x and CR-56x drives can be mixed,
-but the CR-521 ones are hard-wired to drive ID 0. The drives have
-to use different drive IDs, but the same controller (it will be a
-little bit harder to support up to four interface cards - but I plan
-to do it the day somebody wishes to connect a fifth drive).
+Up to 4 drives are supported. CR-52x ("old") and CR-56x ("new") drives
+can be mixed, but the CR-521 ones are hard-wired to drive ID 0.
+The drives have to use different drive IDs, but the same controller
+(it will be a little bit harder to support up to four interface cards -
+but I plan to do it the day somebody wishes to connect a fifth drive).
Each drive has to get a unique minor number (0...3), corresponding
to it's drive ID. The drive IDs may be selected freely from 0 to 3 -
they must not be in consecutive order.
with the "non-X11" products CDplayer and WorkBone - tell me if
it is not compatible with other software.
-MultiSession is supported, "ManySession" (see below) alternatively.
+MultiSession is supported (but "old" drives lack this capability),
+"ManySession" (see below) alternatively.
Photo CDs work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is a package
to convert photo CD image files.
-The transfer rate will reach 150 kB/sec with standard drives and
-the full 300 kB/sec with double-speed drives.
+The transfer rate will reach 150 kB/sec with "old" drives and
+the full 300 kB/sec with double-speed drives. XA (PhotoCD) disks
+with "old" drives are as slow as 50 kB/sec.
This release is part of the standard kernel and consists of
- this README file
Currently, the detection of disk change or removal does not
work as good as it should.
+The "door (un)lock" commands get done at every "(u)mount" (only the
+"new" drives support it), but after an unlock, locking again does not
+work.
+
+All attempts to read the UPC/EAN code result in a stream of zeroes.
+All my drives are telling there is no UPC/EAN code on disk or there
+is, but it is an all-zero number.
Bug reports, comments, wishes, donations (technical information
is a donation, too :-) etc. to
base = &floppy_types[(code-1)*2];
printk("fd%d is %s",drive,base->name);
return base;
+ } else if (!code) {
+ printk("fd%d is not installed", drive);
+ return NULL;
}
printk("fd%d is unknown type %d",drive,code);
return NULL;
{
printk("Floppy drive(s): ");
base_type[0] = find_base(0,(CMOS_READ(0x10) >> 4) & 15);
- if (((CMOS_READ(0x14) >> 6) & 1) == 0)
+ if ((CMOS_READ(0x10) & 15) == 0)
base_type[1] = NULL;
else {
printk(", ");
* and for "no-sound" interfaces like Lasermate and the
* Panasonic CI-101P.
*
- * NOTE: This is release 1.3.
+ * NOTE: This is release 1.4.
* 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.
* 1.3 Minor cleanups.
* Refinements regarding Workman.
*
+ * 1.4 Read XA disks (PhotoCDs) with "old" drives, too (but possibly only
+ * the first session - I could not try a "multi-session" CD yet).
+ * This currently still is too slow (50 kB/sec) - but possibly
+ * the old drives won't do it faster.
+ * Implemented "door (un)lock" for new drives (still does not work
+ * as wanted - no lock possible after an unlock).
+ * Added some debugging printout for the UPC/EAN code - but my drives
+ * return only zeroes. Is there no UPC/EAN code written?
+ *
* 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
#define MAJOR_NR MATSUSHITA_CDROM_MAJOR
#include "blk.h"
-#define VERSION "1.3 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "1.4 Eberhard Moenkeberg <emoenke@gwdg.de>"
#define SBPCD_DEBUG
/*
* still testing around...
*/
-#define MANY_SESSION 0
-#define CDMKE
+#define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */
+#define MANY_SESSION 0 /* this will conflict with "true" multi-session! */
#undef FUTURE
#define WORKMAN 1 /* some testing stuff to make it better */
+#define CDMKE /* makes timing independent of processor speed */
+
+#undef XA_TEST1
+#define XA_TEST2
+
+/*==========================================================================*/
+/*==========================================================================*/
+
+#if MANY_SESSION
+#undef LONG_TIMING
+#define LONG_TIMING 1
+#endif
/*==========================================================================*/
/*==========================================================================*/
* (1<<DBG_SPI) SpinUp test info
* (1<<DBG_IOS) ioctl trace: "subchannel"
* (1<<DBG_IO2) ioctl trace: general
+ * (1<<DBG_UPC) show UPC info
+ * (1<<DBG_XA) XA mode debugging
+ * (1<<DBG_LCK) door (un)lock info
* (1<<DBG_000) unnecessary information
*/
#if 1
#else
static int sbpcd_debug = (1<<DBG_INF) |
(1<<DBG_TOC) |
+ (1<<DBG_UPC) |
(1<<DBG_IOC) |
+ (1<<DBG_XA) |
+ (1<<DBG_LCK) |
(1<<DBG_IOX);
#endif
static int sbpcd_ioaddr = CDROM_PORT; /* default I/O base address */
static u_char cmd_type=0;
static u_char drvcmd[7];
static u_char infobuf[20];
+static u_char scratch_buf[CD_XA_TAIL];
static u_char timed_out=0;
static u_int datarate= 1000000;
static u_int maxtim04= 4000000;
static u_int maxtim02= 2000000;
static u_int maxtim_8= 30000;
-#if MANY_SESSION
+#if LONG_TIMING
static u_int maxtim_data= 9000;
#else
static u_int maxtim_data= 3000;
-#endif MANY_SESSION
+#endif LONG_TIMING
/*==========================================================================*/
u_char sense_byte;
u_char CD_changed;
-
+ u_char open_count;
u_char error_byte;
u_char f_multisession;
/*
* drive space ends here (needed separate for each unit)
*/
-
/*==========================================================================*/
/*==========================================================================*/
/*
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);
+ return (-22);
}
else i=ResponseInfo();
if (i<0) return (-9);
int i, speed;
if (!(DS[d].drv_options&(speed_auto|speed_300|speed_150))) return (0);
- speed=0x80;
+ speed=speed_auto;
if (!(DS[d].drv_options&speed_auto))
{
- speed |= 0x40;
+ speed |= speed_300;
if (!(DS[d].drv_options&speed_300)) speed=0;
}
i=yy_SetSpeed(speed,0,0);
return (i);
}
/*==========================================================================*/
-#if 000
static int yy_LockDoor(char lock)
{
int i;
- if (!new_drive) return (-3);
+ if (!new_drive) return (0);
+ DPRINTF((DBG_LCK,"SBPCD: yy_LockDoor: %d (drive %d)\n", lock, d));
clr_cmdbuf();
drvcmd[0]=0x0C;
if (lock==1) drvcmd[1]=0x01;
i=cmd_out();
return (i);
}
-#endif 000
/*==========================================================================*/
static int xx_ReadSubQ(void)
{
i=0;
if (new_drive) DS[d].sense_byte=infobuf[i++];
DS[d].frame_size=make16(infobuf[i],infobuf[i+1]);
+
+ DPRINTF((DBG_XA,"SBPCD: xx_ModeSense: "));
+ for (i=0;i<(new_drive?5:2);i++)
+ {
+ DPRINTF((DBG_XA,"%02X ", infobuf[i]));
+ }
+ DPRINTF((DBG_XA,"\n"));
+
+ DS[d].diskstate_flags |= frame_size_bit;
+ return (0);
+}
+/*==========================================================================*/
+/*==========================================================================*/
+static int xx_ModeSelect(int framesize)
+{
+ int i;
+
+ DS[d].diskstate_flags &= ~frame_size_bit;
+ clr_cmdbuf();
+ DS[d].frame_size=framesize;
+
+ DPRINTF((DBG_XA,"SBPCD: xx_ModeSelect: %02X %04X\n",
+ DS[d].sense_byte, DS[d].frame_size));
+
+ if (new_drive)
+ {
+ drvcmd[0]=0x09;
+ drvcmd[1]=0x00;
+ drvcmd[2]=DS[d].sense_byte;
+ drvcmd[3]=(DS[d].frame_size>>8)&0xFF;
+ drvcmd[4]=DS[d].frame_size&0xFF;
+ flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+ }
+ else
+ {
+ drvcmd[0]=0x84;
+ drvcmd[1]=0x00;
+ drvcmd[2]=(DS[d].frame_size>>8)&0xFF;
+ drvcmd[3]=DS[d].frame_size&0xFF;
+ drvcmd[4]=0x00;
+ 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 |= frame_size_bit;
return (0);
}
i=xx_ReadPacket();
if (i<0) return (i);
}
+
+ DPRINTF((DBG_UPC,"SBPCD: UPC info: "));
+ for (i=0;i<(new_drive?8:16);i++)
+ {
+ DPRINTF((DBG_UPC,"%02X ", infobuf[i]));
+ }
+ DPRINTF((DBG_UPC,"\n"));
+
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].UPC_ctl_adr = (DS[d].TocEnt_ctl_adr & 0xF0) | 0x02;
}
+
+ DPRINTF((DBG_UPC,"SBPCD: UPC code: "));
+ DPRINTF((DBG_UPC,"(%02X) ", DS[d].UPC_ctl_adr));
+ for (i=0;i<7;i++)
+ {
+ DPRINTF((DBG_UPC,"%02X ", DS[d].UPC_buf[i]));
+ }
+ DPRINTF((DBG_UPC,"\n"));
+
DS[d].diskstate_flags |= upc_bit;
return (0);
}
maxtim04=datarate*4;
maxtim02=datarate*2;
maxtim_8=datarate/32;
-#if MANY_SESSION
+#if LONG_TIMING
maxtim_data=datarate/100;
#else
maxtim_data=datarate/300;
-#endif MANY_SESSION
+#endif LONG_TIMING
DPRINTF((DBG_TIM,"SBPCD: maxtim_8 %d, maxtim_data %d.\n",
maxtim_8, maxtim_data));
#endif CDMKE
DPRINTF((DBG_INF,"SBPCD: DiskInfo: xx_ReadUPC returns %d\n", i));
return (i);
}
+#ifdef XA_TEST2
+ if ((!new_drive) && (DS[d].xa_byte==0x20)) /* XA disk with old drive */
+ {
+ xx_ModeSelect(CD_FRAMESIZE_XA);
+ xx_ModeSense();
+ }
+#endif XA_TEST2
+
return (0);
}
/*==========================================================================*/
if (!st_spinning) xx_SpinUp();
+#ifdef XA_TEST1
+ if ((!new_drive) && (DS[d].xa_byte==0x20)) /* XA disk with old drive */
+ {
+ xx_ModeSelect(CD_FRAMESIZE_XA);
+ xx_ModeSense();
+ }
+#endif XA_TEST1
+
for (data_tries=3; data_tries > 0; data_tries--)
{
for (status_tries=3; status_tries > 0; status_tries--)
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
+ flags_cmd_out |= f_lopsta | f_getsta | f_bit1;
+ if (DS[d].xa_byte==0x20)
{
+ cmd_type=READ_M2;
+ drvcmd[0]=0x03; /* "read XA frames" command for old drives */
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]=0;
+ }
+ else
+ {
+ drvcmd[0]=0x02; /* "read frames" command for old drives */
+
+ 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[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 */
{
+ drvcmd[0]=0x10; /* "read frames" command for new drives */
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();
cli();
#endif SBPCD_DIS_IRQ
try=maxtim_data;
+#if LONG_TIMING
+ for (timeout=jiffies+900; ; )
+#else
for (timeout=jiffies+100; ; )
+#endif
{
for ( ; try!=0;try--)
{
p = DS[d].sbp_buf + frame * CD_FRAMESIZE;
if (sbpro_type) OUT(CDo_sel_d_i,0x01);
+ if (cmd_type==READ_M2) READ_DATA(CDi_data, scratch_buf, CD_XA_HEAD);
READ_DATA(CDi_data, p, CD_FRAMESIZE);
+ if (cmd_type==READ_M2) READ_DATA(CDi_data, scratch_buf, CD_XA_TAIL);
if (sbpro_type) OUT(CDo_sel_d_i,0x00);
DS[d].sbp_current++;
}
/*
- * we could try to keep an "open" counter here and lock the door if 0->1.
- * not done yet.
+ * try to keep an "open" counter here and lock the door if 0->1.
*/
-
+ DPRINTF((DBG_LCK,"SBPCD: open_count: %d -> %d\n",
+ DS[d].open_count,DS[d].open_count+1));
+ if (++DS[d].open_count==1) yy_LockDoor(1);
if (!st_spinning) xx_SpinUp();
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) )
sync_dev(ip->i_rdev); /* nonsense if read only device? */
invalidate_buffers(ip->i_rdev);
DS[d].diskstate_flags &= ~cd_size_bit;
+
+/*
+ * try to keep an "open" counter here and unlock the door if 1->0.
+ */
+ DPRINTF((DBG_LCK,"SBPCD: open_count: %d -> %d\n",
+ DS[d].open_count,DS[d].open_count-1));
+ if (--DS[d].open_count==0) yy_LockDoor(0);
}
/*==========================================================================*/
/*
/* fdomain.c -- Future Domain TMC-16x0 SCSI driver
* Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu
- * Revised: Sun Jan 23 08:59:04 1994 by faith@cs.unc.edu
+ * Revised: Fri Apr 1 23:47:55 1994 by faith@cs.unc.edu
* Author: Rickard E. Faith, faith@cs.unc.edu
* Copyright 1992, 1993, 1994 Rickard E. Faith
*
- * $Id: fdomain.c,v 5.9 1994/01/23 13:59:14 root Exp $
+ * $Id: fdomain.c,v 5.15 1994/04/02 04:48:04 root Exp $
* 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+
**************************************************************************
DESCRIPTION:
high-density external connector. The 1670 and 1680 have floppy disk
controllers built in.
- Future Domain's older boards are based on the TMC-1800 chip, and the
+ Future Domain's older boards are based on the TMC-1800 chip, and this
driver was originally written for a TMC-1680 board with the TMC-1800
chip. More recently, boards are being produced with the TMC-18C50 chip.
The latest and greatest board may not work with this driver. If you have
signature, then the driver may fail to function after the board is
detected.
+ The following BIOS versions are supported: 2.0, 3.0, 3.2, and 3.4.
+ The following chips are supported: TMC-1800, TMC-18C50.
+ Reports suggest that the driver will also work with the TMC-18C30 chip.
+ The support for the version 3.4 BIOS is new, as of March 1994, and may not
+ be stable.
+
If you have a TMC-8xx or TMC-9xx board, then this is not the driver for
your board. Please refer to the Seagate driver for more information and
possible support.
Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric
Youngdale (eric@tantalus.nrl.navy.mil), 1992.
+ Private communication, Tuong Le (Future Domain Engineering department),
+ 1994. (Disk geometry computations for Future Domain BIOS version 3.4, and
+ TMC-18C30 detection.)
+
+ Hogan, Thom. The Programmer's PC Sourcebook. Microsoft Press, 1988. Page
+ 60 (2.39: Disk Partition Table Layout).
+
+ "18C30 Technical Reference Manual", Future Domain Corporation, 1993, page
+ 6-1.
+
NOTES ON REFERENCES:
his 18C50-based card for debugging. He is the sole reason that this
driver works with the 18C50 chip.
+ Thanks to Dave Newman (dnewman@crl.com) for providing initial patches for
+ the version 3.4 BIOS.
+
All of the alpha testers deserve much thanks.
of the two race conditions which were introduced by multiple outstanding
commands). The instability seems a very high price to pay just so that
you don't have to wait for the tape to rewind. When I have time, I will
- work on this again. In the interim, if anyone want to work on the code, I
- can give them my latest version.
+ work on this again. In the interim, if anyone wants to work on the code,
+ I can give them my latest version.
**************************************************************************/
+#include <linux/config.h>
#include <linux/sched.h>
#include <asm/io.h>
#include "../block/blk.h"
#include <linux/string.h>
#include <linux/ioport.h>
-#define VERSION "$Revision: 5.9 $"
+#define VERSION "$Revision: 5.15 $"
/* START OF USER DEFINABLE OPTIONS */
unknown = 0x00,
tmc1800 = 0x01,
tmc18c50 = 0x02,
+ tmc18c30 = 0x03,
};
enum {
Read_SCSI_Data = 0,
SCSI_Status = 1,
TMC_Status = 2,
- FIFO_Status = 3, /* tmc18c50 only */
- Interrupt_Cond = 4, /* tmc18c50 only */
+ FIFO_Status = 3, /* tmc18c50/tmc18c30 only */
+ Interrupt_Cond = 4, /* tmc18c50/tmc18c30 only */
LSB_ID_Code = 5,
MSB_ID_Code = 6,
Read_Loopback = 7,
SCSI_Data_NoACK = 8,
Interrupt_Status = 9,
Configuration1 = 10,
- Configuration2 = 11, /* tmc18c50 only */
+ Configuration2 = 11, /* tmc18c50/tmc18c30 only */
Read_FIFO = 12,
FIFO_Data_Count = 14
};
Interrupt_Cntl = 2,
SCSI_Mode_Cntl = 3,
TMC_Cntl = 4,
- Memory_Cntl = 5, /* tmc18c50 only */
+ Memory_Cntl = 5, /* tmc18c50/tmc18c30 only */
Write_Loopback = 7,
+ IO_Control = 11, /* tmc18c30 only */
Write_FIFO = 12
};
READ EVERY WORD, ESPECIALLY THE WORD *NOT*
- This driver works *ONLY* for Future Domain cards using the TMC-1800 or
- the TMC-18C50 chip. This includes models TMC-1650, 1660, 1670, and 1680.
+ This driver works *ONLY* for Future Domain cards using the TMC-1800,
+ TMC-18C50, or TMC-18C30 chip. This includes models TMC-1650, 1660, 1670,
+ and 1680.
The following BIOS signature signatures are for boards which do *NOT*
work with this driver (these TMC-8xx and TMC-9xx boards may work with the
{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89", 5, 50, 2, 0 },
{ "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92", 5, 44, 3, 0 },
{ "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93", 5, 44, 3, 2 },
+ { "Future Domain Corp. V1.0008/18/93", 5, 33, 3, 4 },
{ "FUTURE DOMAIN TMC-18XX", 5, 22, -1, -1 },
/* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGANTURE
printk( "Future Domain: BIOS version %d.%d, %s\n",
bios_major, bios_minor,
chip == tmc1800 ? "TMC-1800"
- : (chip == tmc18c50 ? "TMC-18C50" : "Unknown") );
+ : (chip == tmc18c50 ? "TMC-18C50"
+ : (chip == tmc18c30 ? "TMC-18C30" : "Unknown")) );
if (interrupt_level) {
printk( "Future Domain: BIOS at %x; port base at %x; using IRQ %d\n",
{
outb( 0, SCSI_Cntl_port );
outb( 0, SCSI_Mode_Cntl_port );
- if (chip == tmc18c50)
+ if (chip == tmc18c50 || chip == tmc18c30)
outb( 0x21 | PARITY_MASK, TMC_Cntl_port ); /* Clear forced intr. */
else
outb( 0x01 | PARITY_MASK, TMC_Cntl_port );
} else { /* test for 0xe960 id */
if (inb( port + MSB_ID_Code ) != 0x60) return 0;
chip = tmc18c50;
+
+#if 0
+
+ /* Try to toggle 32-bit mode. This only
+ works on an 18c30 chip. (User reports
+ say that this doesn't work at all, so
+ we'll use the other method.) */
+
+ outb( 0x80, port + IO_Control );
+ if (inb( port + Configuration2 ) & 0x80 == 0x80) {
+ outb( 0x00, port + IO_Control );
+ if (inb( port + Configuration2 ) & 0x80 == 0x00) chip = tmc18c30;
+ }
+#else
+
+ /* That should have worked, but appears to
+ have problems. Lets assume it is an
+ 18c30 if the RAM is disabled. */
+
+ if (inb( port + Configuration2 ) & 0x02) chip = tmc18c30;
+#endif
+ /* If that failed, we are an 18c50. */
}
/* We have a valid MCA ID for a TMC-1660/TMC-1680 Future Domain board.
printk( " Options = %x\n", options );
#endif
- /* Check for board with lowest bios_base. */
- if (addresses[ (options & 0xc0) >> 6 ] != bios_base)
+ /* Check for board with lowest bios_base --
+ this isn't valid for the 18c30, so just
+ assume we have the right board. */
+
+ if (chip != tmc18c30 && addresses[ (options & 0xc0) >> 6 ] != bios_base)
return 0;
+
interrupt_level = ints[ (options & 0x0e) >> 1 ];
return 1;
printk( "Arbitration failed, status = %x\n", status );
#endif
#if ERRORS_ONLY
- printk( "Future Domain: Arbitration failed, status = %x", status );
+ printk( "Future Domain: Arbitration failed, status = %x\n", status );
#endif
return 1;
}
/* Stop arbitration and enable parity */
outb( PARITY_MASK, TMC_Cntl_port );
+#if 0
timeout = jiffies + 25; /* 250mS */
+#else
+ timeout = jiffies + 35; /* 350mS -- because of timeouts */
+#endif
while (jiffies < timeout) {
status = inb( SCSI_Status_port ); /* Read adapter status */
if (status & 1) { /* Busy asserted */
if (!target) printk( "Selection failed\n" );
#endif
#if ERRORS_ONLY
- if (!target) printk( "Future Domain: Selection failed" );
+ if (!target) printk( "Future Domain: Selection failed\n" );
#endif
return 1;
}
current_SC->cmnd[ current_SC->SCp.sent_command - 1] );
#endif
break;
- case 0x00: /* DATA OUT -- tmc18c50 only */
+ case 0x00: /* DATA OUT -- tmc18c50/tmc18c30 only */
if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
current_SC->SCp.have_data_in = -1;
outb( 0xd0 | PARITY_MASK, TMC_Cntl_port );
}
break;
- case 0x04: /* DATA IN -- tmc18c50 only */
+ case 0x04: /* DATA IN -- tmc18c50/tmc18c30 only */
if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
current_SC->SCp.have_data_in = 1;
outb( 0x90 | PARITY_MASK, TMC_Cntl_port );
if (inb( Interrupt_Status_port ) & 0x08)
printk( " (enabled)" );
printk( "\n" );
- if (chip == tmc18c50) {
+ if (chip == tmc18c50 || chip == tmc18c30) {
printk( "FIFO Status = 0x%02x\n", inb( port_base + FIFO_Status ) );
printk( "Int. Condition = 0x%02x\n",
inb( port_base + Interrupt_Cond ) );
}
printk( "Configuration 1 = 0x%02x\n", inb( port_base + Configuration1 ) );
- if (chip == tmc18c50)
+ if (chip == tmc18c50 || chip == tmc18c30)
printk( "Configuration 2 = 0x%02x\n",
inb( port_base + Configuration2 ) );
}
return 0;
}
+#ifdef CONFIG_BLK_DEV_SD
+
+#include "sd.h"
+#include "scsi_ioctl.h"
+
int fdomain_16x0_biosparam( int size, int dev, int *info_array )
{
- int drive;
+ int drive;
+ unsigned char buf[512 + sizeof( int ) * 2];
+ int *sizes = (int *)buf;
+ unsigned char *data = (unsigned char *)(sizes + 2);
+ unsigned char do_read[] = { READ_6, 0, 0, 0, 1, 0 };
+ int retcode;
+ Scsi_Device *disk;
struct drive_info {
unsigned short cylinders;
unsigned char heads;
*/
drive = MINOR(dev) / 16;
+ disk = rscsi_disks[ drive ].device;
if (bios_major == 2) {
i = (struct drive_info *)( (char *)bios_base + 0x1f31 + drive * 25 );
info_array[0] = i->heads;
info_array[1] = i->sectors;
info_array[2] = i->cylinders;
- } else if (bios_major == 3) { /* Appears to be the same for 3.0 and 3.2 */
- i = (struct drive_info *)( (char *)bios_base + 0x1f71 + drive * 10 );
- info_array[0] = i->heads + 1;
- info_array[1] = i->sectors;
- info_array[2] = i->cylinders;
- } else {
- /* How the data is stored in the RAM area is very BIOS-dependent.
- Therefore, assume a version 3 layout, and check for validity. */
-
+ } else if (bios_major == 3 && bios_minor < 4) { /* 3.0 and 3.2 BIOS */
i = (struct drive_info *)( (char *)bios_base + 0x1f71 + drive * 10 );
info_array[0] = i->heads + 1;
info_array[1] = i->sectors;
info_array[2] = i->cylinders;
+ } else { /* 3.4 BIOS (and up?) */
+ /* This algorithm was provided by Future Domain (much thanks!). */
+
+ sizes[0] = 0; /* zero bytes out */
+ sizes[1] = 512; /* one sector in */
+ memcpy( data, do_read, sizeof( do_read ) );
+ retcode = kernel_scsi_ioctl( disk,
+ SCSI_IOCTL_SEND_COMMAND,
+ (void *)buf );
+ if (!retcode /* SCSI command ok */
+ && data[511] == 0xaa && data[510] == 0x55 /* Partition table valid */
+ && data[0x1c2]) { /* Partition type */
+
+ /* The partition table layout is as follows:
+
+ Start: 0x1b3h
+ Offset: 0 = partition status
+ 1 = starting head
+ 2 = starting sector and cylinder (word, encoded)
+ 4 = partition type
+ 5 = ending head
+ 6 = ending sector and cylinder (word, encoded)
+ 8 = starting absolute sector (double word)
+ c = number of sectors (double word)
+ Signature: 0x1fe = 0x55aa
+
+ So, this algorithm assumes:
+ 1) the first partition table is in use,
+ 2) the data in the first entry is correct, and
+ 3) partitions never divide cylinders
+
+ Note that (1) may be FALSE for NetBSD (and other BSD flavors),
+ as well as for Linux. Note also, that Linux doesn't pay any
+ attention to the fields that are used by this algorithm -- it
+ only uses the absolute sector data. Recent versions of Linux's
+ fdisk(1) will fill this data in correctly, and forthcoming
+ versions will check for consistency.
+
+ Checking for a non-zero partition type is not part of the
+ Future Domain algorithm, but it seemed to be a reasonable thing
+ to do, especially in the Linux and BSD worlds. */
+
+ info_array[0] = data[0x1c3] + 1; /* heads */
+ info_array[1] = data[0x1c4] & 0x3f; /* sectors */
+ } else {
- if (!info_array[0]
- || !info_array[1]
- || !info_array[2]
- || info_array[2] > 1024 /* DOS uses only 10 bits.
- Should this be changed
- to support larger drives?
- I.e., will the controller
- "do the right thing"?
- */
- ) {
-
- info_array[0]
- = info_array[1]
- = info_array[2]
- = 0;
+ /* Note that this new method guarantees that there will always be
+ less than 1024 cylinders on a platter. This is good for drives
+ up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
+
+ if ((unsigned int)size >= 0x7e0000U) {
+ info_array[0] = 0xff; /* heads = 255 */
+ info_array[1] = 0x3f; /* sectors = 63 */
+ } else if ((unsigned int)size >= 0x200000U) {
+ info_array[0] = 0x80; /* heads = 128 */
+ info_array[1] = 0x3f; /* sectors = 63 */
+ } else {
+ info_array[0] = 0x40; /* heads = 64 */
+ info_array[1] = 0x20; /* sectors = 32 */
+ }
}
+ /* For both methods, compute the cylinders */
+ info_array[2] = (unsigned int)size / (info_array[0] * info_array[1] );
}
return 0;
}
+
+#endif /* CONFIG_BLK_DEV_SD */
/* fdomain.h -- Header for Future Domain TMC-16x0 driver
* Created: Sun May 3 18:47:33 1992 by faith@cs.unc.edu
- * Revised: Tue Jan 4 20:44:04 1994 by faith@cs.unc.edu
+ * Revised: Sat Mar 19 16:07:14 1994 by faith@cs.unc.edu
* Author: Rickard E. Faith, faith@cs.unc.edu
* Copyright 1992, 1993, 1994 Rickard E. Faith
*
- * $Id: fdomain.h,v 5.3 1994/01/05 01:44:16 root Exp $
+ * $Id: fdomain.h,v 5.5 1994/03/19 21:07:38 root Exp $
* 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+
*/
#ifndef _FDOMAIN_H
const char *fdomain_16x0_info( void );
int fdomain_16x0_reset( Scsi_Cmnd * );
int fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
+
+#ifdef CONFIG_BLK_DEV_SD
int fdomain_16x0_biosparam( int, int, int * );
+#else
+#define fdomain_16x0_biosparam NULL
+#endif
#define FDOMAIN_16X0 { "Future Domain TMC-16x0", \
fdomain_16x0_detect, \
#define DBG_SPI 18 /* SpinUp test */
#define DBG_IOS 19 /* ioctl trace: "subchannel" */
#define DBG_IO2 20 /* ioctl trace: general */
-#define DBG_000 21 /* unnecessary information */
+#define DBG_UPC 21 /* show UPC information */
+#define DBG_XA 22 /* XA mode debugging */
+#define DBG_LCK 23 /* door (un)lock info */
+#define DBG_000 24 /* unnecessary information */
/*==========================================================================*/
/*==========================================================================*/
/*
* 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 */
+#define READ_M1 0x01 /* "data mode 1": 2048 bytes per frame */
+#define READ_M2 0x02 /* "data mode 2": 12+2048+280 bytes per frame */
+#define READ_SC 0x04 /* "subchannel info": 96 bytes per frame */
/*
* sense byte: used only if new_drive
#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_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 */
-
+#define CD_XA_HEAD 12 /* header size of XA frame */
+#define CD_XA_TAIL 280 /* tail size of XA frame */
/* audio status (bin) */
#define aud_00 0x00 /* Audio status byte not supported or not valid */
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: 03 ll-bb-aa nn-nn 00. (??) read nn-nn blocks of 2340 bytes,
+ starting at block ll-bb-aa
Read SUB_Q:
89 fl 00 00 00 00 00. (13) r0: audio status, r4-r7: lba/msf,
#include <linux/fs.h>
#include <linux/sched.h>
-#define X(name) { (void *) &name, #name }
+#define X(name) { (void *) &name, "_" #name }
struct {
void *addr;
}
+/* Handle ICMP Timestamp requests. */
+static void
+icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
+ unsigned long saddr, unsigned long daddr, int len,
+ struct options *opt)
+{
+ struct icmphdr *icmphr;
+ struct sk_buff *skb2;
+ int size, offset;
+ unsigned long *timeptr, midtime;
+ extern struct timeval xtime; /* kernel/time.c */
+
+ size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
+ if (! (skb2 = alloc_skb(size, GFP_ATOMIC))) {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+ skb2->sk = NULL;
+ skb2->mem_addr = skb2;
+ skb2->mem_len = size;
+ skb2->free = 1;
+
+ /* Build Layer 2-3 headers for message back to source */
+ offset = ip_build_header(skb2, daddr, saddr, &dev, IPPROTO_ICMP, opt, len,
+ skb->ip_hdr->tos, 255);
+ if (offset < 0) {
+ printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n");
+ kfree_skb(skb2, FREE_WRITE);
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+
+ /* Re-adjust length according to actual IP header size. */
+ skb2->len = offset + len;
+
+ /* Build ICMP_TIMESTAMP Response message. */
+ icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
+ memcpy((char *) icmphr, (char *) icmph, len);
+ icmphr->type = ICMP_TIMESTAMPREPLY;
+ icmphr->code = icmphr->checksum = 0;
+
+ /* fill in the current time as ms since midnight UT: */
+ midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000;
+ timeptr = (unsigned long *) (icmphr + 1);
+ /* the originate timestamp (timeptr [0]) is still in the copy: */
+ timeptr [1] = timeptr [2] = htonl(midtime);
+
+ icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, len);
+
+ /* Ship it out - free it when done */
+ ip_queue_xmit((struct sock *) NULL, dev, skb2, 1);
+
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+}
+
+
/* Handle the ICMP INFORMATION REQUEST. */
static void
icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
skb1->sk = NULL;
kfree_skb(skb1, FREE_READ);
return(0);
+ case ICMP_TIMESTAMP:
+ icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt);
+ return 0;
+ case ICMP_TIMESTAMPREPLY:
+ skb1->sk = NULL;
+ kfree_skb(skb1, FREE_READ);
+ return(0);
case ICMP_INFO_REQUEST:
icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
return 0;
release_sock(sk);
return(0);
+ case TCP_SYN_RECV:
+ if (th->syn) {
+ /* Probably a retransmitted syn */
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+
+
default:
if (!tcp_sequence(sk, th, len, opt, saddr,dev)) {
kfree_skb(skb, FREE_READ);
#define MAX_FIN_SIZE 40 + sizeof (struct sk_buff) + MAX_HEADER
#define MAX_ACK_SIZE 40 + sizeof (struct sk_buff) + MAX_HEADER
#define MAX_RESET_SIZE 40 + sizeof (struct sk_buff) + MAX_HEADER
-#define MAX_WINDOW 4096
+#define MAX_WINDOW 8192
#define MIN_WINDOW 2048
#define MAX_ACK_BACKLOG 2
#define MIN_WRITE_SPACE 2048