Commit be164636 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.2.8

parent d43cc577
VERSION = 1
PATCHLEVEL = 2
SUBLEVEL = 7
SUBLEVEL = 8
ARCH = i386
......
......@@ -358,6 +358,14 @@ void handle_vm86_fault(struct vm86_regs * regs, long error_code)
IP(regs) += 2;
set_vflags_long(popl(ssp, sp), regs);
return;
/* iretd */
case 0xcf:
SP(regs) += 12;
IP(regs) = (unsigned short)popl(ssp, sp);
regs->cs = (unsigned short)popl(ssp, sp);
set_vflags_long(popl(ssp, sp), regs);
return;
}
/* pushf */
......
This README belongs to release 3.4 or newer of the SoundBlaster Pro
This README belongs to release 3.5 or newer of the SoundBlaster Pro
(Matsushita, Kotobuki, Panasonic, CreativeLabs, Longshine and soon TEAC, too)
CD-ROM driver for Linux.
......@@ -16,28 +16,18 @@ of the "LaserMate" type), and it is possibly the best buy today (cheaper than
an internal drive, and you can use it as an internal, too - f.e. plug it into
a soundcard).
The quad-speed TEAC CD-55A drive uses the same interface types, but has a
totally different command and flow control scheme. Support is under
construction, but split: Greg Nowicki (nowicki@tardis.larc.nasa.gov)
cares about the separate driver "teaccd". Please, do not mail him merely for
asking "user questions" at the moment - the project is still a "baby".
CreativeLabs has a new drive "CD-200". Support is under construction.
Detection should already work.
Drive detection and playing audio should already work. I need qualified
feedback about the bugs within the data functions or a drive (I never saw
a CD200).
Regarding CD200 support:
Please, don't mail me about it if you are not a competent BETA tester
(if you are: mail!; I do not have such drives).
Please, don't drop simple questions about the new drives in the
newsgroups. Full support needs more or less time.
If you like to help, you can mail me the "SBPCD:..." messages, regarding the
new drives. But I mostly will not answer (just use) it.
The quad-speed TEAC CD-55A drive is supported. The routines may still be
a little bit buggy, but the data rate already reaches 500 kB/sec if you
set SBP_BUFFER_FRAMES to 64. The drive is able to deliver 600 kB/sec, so
this has to get a point of work.
This driver is NOT for Mitsumi or Sony or Aztech or Philips or XXX drives,
and this driver is in no way usable for any new IDE ATAPI drive.
For Aztech CDA-268 drives (and for some Wearnes, Okano and Orchid drives),
Werner Zimmermann has done a driver which currently resides at ftp.gwdg.de
under /pub/linux/cdrom/drivers/aztech/.
This driver will work with the soundcard interfaces (SB Pro, SB 16, Galaxy,
SoundFX, ...) and/or with the "no-sound" cards (Panasonic CI-101P, LaserMate,
......@@ -53,8 +43,8 @@ The interface type has to get configured in /usr/include/linux/sbpcd.h,
because the behavior of some sound card interfaces is different.
The driver respects all known drive firmware releases - my old drive is a 2.11,
but it should work with "old" drives <2.01 ... >3.00 and with "new" drives
(which count the releases around 0.75 or 1.00).
but it should work with CR-52x drives <2.01 ... >3.00 and with CR-56x drives
<0.75 .. 5.00.
Up to 4 drives per interface card, and up to 4 interface cards are supported.
All supported drive families can be mixed, but the CR-521 drives are
......@@ -90,28 +80,30 @@ CDplayer and WorkBone - tell me if it is not compatible with other software.
With the CR-562 and CR-563 drives, the reading of audio frames is possible.
This is implemented by an IOCTL function which per default reads only up to
4 frames of 2352 bytes at once (configurable with the "READ_AUDIO" define).
4 frames of 2352 bytes at once (configurable with the "READ_AUDIO" define,
"55" is the maximum if you use sbpcd as a "module").
Reading the same frame a second time gives different data; the frame data
start at a different position, but all read bytes are valid, and we always
read 98 consecutive chunks (of 24 Bytes) as a frame. Reading more than 1 frame
at once misses some chunks at each frame boundary.This lack has to get
corrected by external, "higher level" software which reads the same frame
at once possibly misses some chunks at each frame boundary. This lack has to
get corrected by external, "higher level" software which reads the same frame
again and tries to find and eliminate overlapping chunks (24-byte-pieces).
The transfer rate with reading audio (1-frame-pieces) is as slow as 32 kB/sec.
This could be better reading bigger chunks, but the "missing" chunks occur at
the beginning of each single frame.
This could be better reading bigger chunks, but the "missing" chunks possibly
occur at the beginning of each single frame.
The software interface possibly may change a bit the day the SCSI driver
supports it too.
With the CR-562 and CR-563 drives, MultiSession is supported.
With all but the CR-52x drives, MultiSession is supported.
Photo CDs work (the "old" drives like CR-521 can access only the first
session of a photoCD).
At ftp.gwdg.de:/pub/linux/hpcdtoppm/ you will find Hadmut Danisch's package to
convert photo CD image files and Gerd Knorr's viewing utility.
The transfer rate will reach 150 kB/sec with "old" drives and 300 kB/sec with
double-speed drives. XA (PhotoCD) disks with "old" drives give only 50 kB/sec.
The transfer rate will reach 150 kB/sec with "old" drives, 300 kB/sec with
double-speed drives, and about 500 kB/sec with quad speed drives.
XA (PhotoCD) disks with "old" drives give only 50 kB/sec.
This release is part of the standard kernel and consists of
- this README file
......@@ -138,6 +130,7 @@ To install:
If you configure "SBPRO" wrong, the playing of audio CDs will work,
but you will not be able to mount a data CD.
a2. Tell the address of your CDROM_PORT (not of the sound port).
a3. Set DISTRIBUTION to 0.
b. Additionally for 2.a1 and 2.a2, the setup may be done during
boot time (via the "kernel command line" or "LILO option"):
sbpcd=0x230,SoundBlaster
......@@ -145,7 +138,6 @@ To install:
sbpcd=0x320,LaserMate
or
sbpcd=0x330,SPEA
(these strings are case sensitive!).
This is especially useful if you install a fresh distribution.
2. "cd /usr/src/linux" and do a "make config" and select "y" for Matsushita
CD-ROM support and for ISO9660 FileSystem support. If you do not have a
......@@ -198,11 +190,15 @@ If you do NOT select "Matsushita/Panasonic CDROM driver support" during the
"make config" of your kernel, you can build the "loadable module" sbpcd.o.
Read /usr/src/linux/README.modules on this.
If sbpcd gets used as a module, the "audio copy" feature is disabled, and the
internal read-ahead buffer has a reduced size (the latter may affect throughput
a little bit under "slow" CPUs). Further, support of more than one interface
If sbpcd gets used as a module, the support of more than one interface
card (i.e. drives 4...15) is disabled.
You can specify interface address and type with the "insmod" command like:
# insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x340,0
or
# insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x230,1
where the last number represents the SBPRO setting (no strings allowed here).
Things of interest:
-------------------
......@@ -215,7 +211,6 @@ No DMA and no IRQ is used.
To reduce or increase the amount of kernel messages, edit sbpcd.c and play
with the "DBG_xxx" switches (initialization of the variable "sbpcd_debug").
This is the way to get rid of the initial warning message block, too.
The driver uses the "variable BLOCK_SIZE" feature. To use it, you have to
specify "block=2048" as a mount option. Doing this will disable the direct
......@@ -229,120 +224,13 @@ do not use block=2048 with those.
At the beginning of sbpcd.c, you will find some "#define"s (f.e. EJECT and
JUKEBOX). With that, you can configure the driver for some special things.
The following program disables the auto-eject feature during runtime:
/*=================== begin program ========================================*/
/*
* set the "eject" switch (enable/disable auto-ejecting)
*
* (c) 1994 Eberhard Moenkeberg <emoenke@gwdg.de>
* may be used & enhanced freely
*
* Disables or enables the auto-eject feature at run time.
* Works only if a CD is in the drive (just like the feature itself ;-)
* Useful for a "quiet" shutdown or for weird audio player programs.
*/
#define EJECT 0 /* 0: disable, 1: enable auto-ejecting */
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/cdrom.h>
static char arg=EJECT;
static int drive;
static int err;
main(int argc, char *argv[])
{
/*
* open /dev/cdrom
*/
drive=open("/dev/cdrom", 0);
if (drive<0)
{
fprintf(stderr, "can't open drive /dev/cdrom.\n");
exit (-1);
}
/*
* set EJECT_SW
*/
err=ioctl(drive, CDROMEJECT_SW, arg);
if (err!=0)
{
fprintf(stderr, "can't set EJECT_SW (error %d).\n", err);
exit (-1);
}
else
fprintf(stdout, "EJECT_SW set to %d\n", arg);
}
/*===================== end program ========================================*/
Jeff Tranter's "eject" utility can do this, too (and more) for you.
You can use the appended program "cdtester" to set the auto-eject feature
during runtime. Jeff Tranter's "eject" utility can do this, too (and more)
for you.
There is a new ioctl CDROMMULTISESSION to obtain with a user program if
the CD is an XA disk and - if it is - where the last session starts. The
following example illustrates how to call it:
/*=================== begin program ========================================*/
/*
* ask for multisession redirection info
*
* (c) 1994 Eberhard Moenkeberg <emoenke@gwdg.de>
* may be used & enhanced freely
*
*/
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/cdrom.h>
static struct cdrom_multisession ms_info;
static int drive;
static int err;
main(int argc, char *argv[])
{
/*
* open /dev/cdrom
*/
drive=open("/dev/cdrom", 0);
if (drive<0)
{
fprintf(stderr, "can't open drive /dev/cdrom.\n");
exit (-1);
}
/*
*
*/
ms_info.addr_format=CDROM_LBA;
err=ioctl(drive, CDROMMULTISESSION, &ms_info);
if (err!=0)
{
fprintf(stderr, "CDROMMULTISESSION(lba) returns error %d.\n", err);
exit (-1);
}
else
if (ms_info.xa_flag)
fprintf(stdout, "lba: %d\n", ms_info.addr.lba);
else
fprintf(stdout, "not an XA disk.\n");
ms_info.addr_format=CDROM_MSF;
err=ioctl(drive, CDROMMULTISESSION, &ms_info);
if (err!=0)
{
fprintf(stderr, "CDROMMULTISESSION(msf) returns error %d.\n", err);
exit (-1);
}
else
if (ms_info.xa_flag)
fprintf(stdout, "msf: %02d:%02d:%02d\n",
ms_info.addr.msf.minute,
ms_info.addr.msf.second,
ms_info.addr.msf.frame);
else
fprintf(stdout, "not an XA disk.\n");
}
/*===================== end program ========================================*/
"cdtester" program illustrates how to call it.
Auto-probing at boot time:
......@@ -354,7 +242,8 @@ Some probings can cause a hang if an NE2000 ethernet card gets touched, because
SBPCD's auto-probing happens before the initialization of the net drivers.
Those "hazardous" addresses are excluded from auto-probing; the "kernel
command line" feature has to be used during installation if you have your
drive at those addresses.
drive at those addresses. The "module" version is allowed to probe at those
addresses, too.
The auto-probing looks first at the configured address resp. the address
submitted by the kernel command line. With this, it is possible to use this
......@@ -382,7 +271,7 @@ loadable module would be better because it allows an "extended" auto-probing
without fearing NE2000 cards).
To shorten the auto-probing list to a single entry, set DISTRIBUTION 0 within
sbpcd.c.
sbpcd.h.
Setting up address and interface type:
......@@ -569,3 +458,537 @@ SnailMail address, preferable for CD editors if they want to submit a free
D-37083 Goettingen
Germany
---
Appendix -- the "cdtester" utility:
/*
* cdtester.c -- test the audio functions of a CD driver
*
* (c) 1995 Eberhard Moenkeberg <emoenke@gwdg.de>
* published under the GPL
*
* made under heavy use of the "Tiny Audio CD Player"
* from Werner Zimmermann <zimmerma@rz.fht-esslingen.de>
* (see linux/drivers/block/README.aztcd)
*/
#undef AZT_PRIVATE_IOCTLS /* not supported by every CDROM driver */
#define SBP_PRIVATE_IOCTLS /* not supported by every CDROM driver */
#include <stdio.h>
#include <stdio.h>
#include <malloc.h>
#include <sys/ioctl.h>
#include <linux/cdrom.h>
#ifdef AZT_PRIVATE_IOCTLS
#include <linux/aztcd.h>
#endif AZT_PRIVATE_IOCTLS
#ifdef SBP_PRIVATE_IOCTLS
#include <linux/sbpcd.h>
#include <linux/fs.h>
#endif SBP_PRIVATE_IOCTLS
struct cdrom_tochdr hdr;
struct cdrom_tochdr tocHdr;
struct cdrom_tocentry TocEntry[101];
struct cdrom_tocentry entry;
struct cdrom_multisession ms_info;
struct cdrom_read_audio read_audio;
struct cdrom_ti ti;
struct cdrom_subchnl subchnl;
struct cdrom_msf msf;
struct cdrom_volctrl volctrl;
#ifdef AZT_PRIVATE_IOCTLS
union
{
struct cdrom_msf msf;
unsigned char buf[CD_FRAMESIZE_RAW];
} azt;
#endif AZT_PRIVATE_IOCTLS
int i, i1, i2, i3, j, k;
unsigned char sequence=0;
unsigned char command[80];
unsigned char first=1, last=1;
char *default_device="/dev/cdrom";
char dev[20];
char filename[20];
int drive;
int datafile;
int rc;
void help(void)
{
printf("Available Commands:\n");
printf("STOP s EJECT e QUIT q\n");
printf("PLAY TRACK t PAUSE p RESUME r\n");
printf("NEXT TRACK n REPEAT LAST l HELP h\n");
printf("SUBCHANNEL_Q c TRACK INFO i PLAY AT a\n");
printf("READ d READ RAW w READ AUDIO A\n");
printf("MS-INFO M TOC T START S\n");
printf("SET EJECTSW X DEVICE D DEBUG Y\n");
printf("AUDIO_BUFSIZ Z RESET R BLKRASET B\n");
printf("SET VOLUME v GET VOLUME V\n");
}
/*
* convert MSF number (3 bytes only) to Logical_Block_Address
*/
int msf2lba(u_char *msf)
{
int i;
i=(msf[0] * CD_SECS + msf[1]) * CD_FRAMES + msf[2] - CD_BLOCK_OFFSET;
if (i<0) return (0);
return (i);
}
/*
* convert logical_block_address to m-s-f_number (3 bytes only)
*/
void lba2msf(int lba, unsigned 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;
}
int init_drive(char *dev)
{
unsigned char msf_ent[3];
/*
* open the device
*/
drive=open(dev,0);
if (drive<0) return (-1);
/*
* get TocHeader
*/
printf("getting TocHeader...\n");
rc=ioctl(drive,CDROMREADTOCHDR,&hdr);
if (rc!=0)
{
printf("can't get TocHeader (error %d).\n",rc);
return (-2);
}
else
first=hdr.cdth_trk0;
last=hdr.cdth_trk1;
printf("TocHeader: %d %d\n",hdr.cdth_trk0,hdr.cdth_trk1);
/*
* get and display all TocEntries
*/
printf("getting TocEntries...\n");
for (i=1;i<=hdr.cdth_trk1+1;i++)
{
if (i!=hdr.cdth_trk1+1) TocEntry[i].cdte_track = i;
else TocEntry[i].cdte_track = CDROM_LEADOUT;
TocEntry[i].cdte_format = CDROM_LBA;
rc=ioctl(drive,CDROMREADTOCENTRY,&TocEntry[i]);
if (rc!=0)
{
printf("can't get TocEntry #%d (error %d).\n",i,rc);
}
else
{
lba2msf(TocEntry[i].cdte_addr.lba,&msf_ent[0]);
if (TocEntry[i].cdte_track==CDROM_LEADOUT)
{
printf("TocEntry #%02X: %1X %1X %02d:%02d:%02d (lba: 0x%06X) %02X\n",
TocEntry[i].cdte_track,
TocEntry[i].cdte_adr,
TocEntry[i].cdte_ctrl,
msf_ent[0],
msf_ent[1],
msf_ent[2],
TocEntry[i].cdte_addr.lba,
TocEntry[i].cdte_datamode);
}
else
{
printf("TocEntry #%02d: %1X %1X %02d:%02d:%02d (lba: 0x%06X) %02X\n",
TocEntry[i].cdte_track,
TocEntry[i].cdte_adr,
TocEntry[i].cdte_ctrl,
msf_ent[0],
msf_ent[1],
msf_ent[2],
TocEntry[i].cdte_addr.lba,
TocEntry[i].cdte_datamode);
}
}
}
return (hdr.cdth_trk1); /* number of tracks */
}
void display(int size,unsigned char *buffer)
{
k=0;
getchar();
for (i=0;i<(size+1)/16;i++)
{
printf("%4d:",i*16);
for (j=0;j<16;j++)
{
printf(" %02X",buffer[i*16+j]);
}
printf(" ");
for (j=0;j<16;j++)
{
if (isalnum(buffer[i*16+j]))
printf("%c",buffer[i*16+j]);
else
printf(".");
}
printf("\n");
k++;
if (k>=20)
{
printf("press ENTER to continue\n");
getchar();
k=0;
}
}
}
main(int argc, char *argv[])
{
printf("\nTesting tool for a CDROM driver's audio functions V0.1\n");
printf("(C) 1995 Eberhard Moenkeberg <emoenke@gwdg.de>\n");
printf("initializing...\n");
rc=init_drive(default_device);
if (rc<0) printf("could not open %s (rc=%d).\n",default_device,rc);
help();
while (1)
{
printf("Give a one-letter command (h = help): ");
scanf("%s",command);
command[1]=0;
switch (command[0])
{
case 'D':
printf("device name (f.e. /dev/sbpcd3): ? ");
scanf("%s",&dev);
close(drive);
rc=init_drive(dev);
if (rc<0) printf("could not open %s (rc %d).\n",dev,rc);
break;
case 'e':
rc=ioctl(drive,CDROMEJECT);
if (rc<0) printf("CDROMEJECT: rc=%d.\n",rc);
break;
case 'p':
rc=ioctl(drive,CDROMPAUSE);
if (rc<0) printf("CDROMPAUSE: rc=%d.\n",rc);
break;
case 'r':
rc=ioctl(drive,CDROMRESUME);
if (rc<0) printf("CDROMRESUME: rc=%d.\n",rc);
break;
case 's':
rc=ioctl(drive,CDROMSTOP);
if (rc<0) printf("CDROMSTOP: rc=%d.\n",rc);
break;
case 'S':
rc=ioctl(drive,CDROMSTART);
if (rc<0) printf("CDROMSTART: rc=%d.\n",rc);
break;
case 't':
rc=ioctl(drive,CDROMREADTOCHDR,&tocHdr);
if (rc<0)
{
printf("CDROMREADTOCHDR: rc=%d.\n",rc);
break;
}
first=tocHdr.cdth_trk0;
last= tocHdr.cdth_trk1;
if ((first==0)||(first>last))
{
printf ("--got invalid TOC data.\n");
}
else
{
printf("--enter track number(first=%d, last=%d): ",first,last);
scanf("%d",&i1);
ti.cdti_trk0=i1;
if (ti.cdti_trk0<first) ti.cdti_trk0=first;
if (ti.cdti_trk0>last) ti.cdti_trk0=last;
ti.cdti_ind0=0;
ti.cdti_trk1=last;
ti.cdti_ind1=0;
rc=ioctl(drive,CDROMSTOP);
rc=ioctl(drive,CDROMPLAYTRKIND,&ti);
if (rc<0) printf("CDROMPLAYTRKIND: rc=%d.\n",rc);
}
break;
case 'n':
rc=ioctl(drive,CDROMSTOP);
if (++ti.cdti_trk0>last) ti.cdti_trk0=last;
ti.cdti_ind0=0;
ti.cdti_trk1=last;
ti.cdti_ind1=0;
rc=ioctl(drive,CDROMPLAYTRKIND,&ti);
if (rc<0) printf("CDROMPLAYTRKIND: rc=%d.\n",rc);
break;
case 'l':
rc=ioctl(drive,CDROMSTOP);
if (--ti.cdti_trk0<first) ti.cdti_trk0=first;
ti.cdti_ind0=0;
ti.cdti_trk1=last;
ti.cdti_ind1=0;
rc=ioctl(drive,CDROMPLAYTRKIND,&ti);
if (rc<0) printf("CDROMPLAYTRKIND: rc=%d.\n",rc);
break;
case 'c':
subchnl.cdsc_format=CDROM_MSF;
rc=ioctl(drive,CDROMSUBCHNL,&subchnl);
if (rc<0) printf("CDROMSUBCHNL: rc=%d.\n",rc);
else
{
printf("AudioStatus:%s Track:%d Mode:%d MSF=%02d:%02d:%02d\n",
subchnl.cdsc_audiostatus==CDROM_AUDIO_PLAY ? "PLAYING":"NOT PLAYING",
subchnl.cdsc_trk,subchnl.cdsc_adr,
subchnl.cdsc_absaddr.msf.minute,
subchnl.cdsc_absaddr.msf.second,
subchnl.cdsc_absaddr.msf.frame);
}
break;
case 'i':
printf("Track No.: ");
scanf("%d",&i1);
entry.cdte_track=i1;
if (entry.cdte_track<first) entry.cdte_track=first;
if (entry.cdte_track>last) entry.cdte_track=last;
entry.cdte_format=CDROM_MSF;
rc=ioctl(drive,CDROMREADTOCENTRY,&entry);
if (rc<0) printf("CDROMREADTOCENTRY: rc=%d.\n",rc);
else
{
printf("Mode %d Track, starts at %02d:%02d:%02d\n",
entry.cdte_adr,
entry.cdte_addr.msf.minute,
entry.cdte_addr.msf.second,
entry.cdte_addr.msf.frame);
}
break;
case 'a':
printf("Address (min:sec:frm) ");
scanf("%d:%d:%d",&i1,&i2,&i3);
msf.cdmsf_min0=i1;
msf.cdmsf_sec0=i2;
msf.cdmsf_frame0=i3;
if (msf.cdmsf_sec0>59) msf.cdmsf_sec0=59;
if (msf.cdmsf_frame0>74) msf.cdmsf_frame0=74;
lba2msf(TocEntry[last+1].cdte_addr.lba-1,&msf.cdmsf_min1);
rc=ioctl(drive,CDROMSTOP);
rc=ioctl(drive,CDROMPLAYMSF,&msf);
if (rc<0) printf("CDROMPLAYMSF: rc=%d.\n",rc);
break;
#ifdef AZT_PRIVATE_IOCTLS /*not supported by every CDROM driver*/
case 'd':
printf("Address (min:sec:frm) ");
scanf("%d:%d:%d",&i1,&i2,&i3);
azt.msf.cdmsf_min0=i1;
azt.msf.cdmsf_sec0=i2;
azt.msf.cdmsf_frame0=i3;
if (azt.msf.cdmsf_sec0>59) azt.msf.cdmsf_sec0=59;
if (azt.msf.cdmsf_frame0>74) azt.msf.cdmsf_frame0=74;
rc=ioctl(drive,CDROMREADMODE1,&azt.msf);
if (rc<0) printf("CDROMREADMODE1: rc=%d.\n",rc);
else display(CD_FRAMESIZE,azt.buf);
break;
case 'w':
printf("Address (min:sec:frame) ");
scanf("%d:%d:%d",&i1,&i2,&i3);
azt.msf.cdmsf_min0=i1;
azt.msf.cdmsf_sec0=i2;
azt.msf.cdmsf_frame0=i3;
if (azt.msf.cdmsf_sec0>59) azt.msf.cdmsf_sec0=59;
if (azt.msf.cdmsf_frame0>74) azt.msf.cdmsf_frame0=74;
rc=ioctl(drive,CDROMREADMODE2,&azt.msf);
if (rc<0) printf("CDROMREADMODE2: rc=%d.\n",rc);
else display(CD_FRAMESIZE_RAW,azt.buf); /* currently only 2336 */
break;
#endif
case 'v':
printf("--Channel 0 (Left) (0-255): ");
scanf("%d",&i1);
volctrl.channel0=i1;
printf("--Channel 1 (Right) (0-255): ");
scanf("%d",&i1);
volctrl.channel1=i1;
volctrl.channel2=0;
volctrl.channel3=0;
rc=ioctl(drive,CDROMVOLCTRL,&volctrl);
if (rc<0) printf("CDROMVOLCTRL: rc=%d.\n",rc);
break;
case 'q':
close(drive);
exit(0);
case 'h':
help();
break;
case 'T': /* display TOC entry - without involving the driver */
scanf("%d",&i);
if ((i<hdr.cdth_trk0)||(i>hdr.cdth_trk1))
printf("invalid track number.\n");
else
printf("TocEntry %02d: adr=%01X ctrl=%01X msf=%02d:%02d:%02d mode=%02X\n",
TocEntry[i].cdte_track,
TocEntry[i].cdte_adr,
TocEntry[i].cdte_ctrl,
TocEntry[i].cdte_addr.msf.minute,
TocEntry[i].cdte_addr.msf.second,
TocEntry[i].cdte_addr.msf.frame,
TocEntry[i].cdte_datamode);
break;
case 'A': /* read audio data into file */
printf("Address (min:sec:frm) ? ");
scanf("%d:%d:%d",&i1,&i2,&i3);
read_audio.addr.msf.minute=i1;
read_audio.addr.msf.second=i2;
read_audio.addr.msf.frame=i3;
read_audio.addr_format=CDROM_MSF;
printf("# of frames ? ");
scanf("%d",&i1);
read_audio.nframes=i1;
k=read_audio.nframes*CD_FRAMESIZE_RAW;
read_audio.buf=malloc(k);
if (read_audio.buf==NULL)
{
printf("can't malloc %d bytes.\n",k);
break;
}
sprintf(filename,"audio_%02d%02d%02d_%02d.%02d\0",
read_audio.addr.msf.minute,
read_audio.addr.msf.second,
read_audio.addr.msf.frame,
read_audio.nframes,
++sequence);
datafile=creat(filename, 0755);
if (datafile<0)
{
printf("can't open datafile %s.\n",filename);
break;
}
rc=ioctl(drive,CDROMREADAUDIO,&read_audio);
if (rc!=0)
{
printf("CDROMREADAUDIO: rc=%d.\n",rc);
}
else
{
rc=write(datafile,&read_audio.buf,k);
if (rc!=k) printf("datafile I/O error (%d).\n",rc);
}
close(datafile);
break;
case 'X': /* set EJECT_SW (0: disable, 1: enable auto-ejecting) */
scanf("%d",&i);
rc=ioctl(drive,CDROMEJECT_SW,i);
if (rc!=0)
printf("CDROMEJECT_SW: rc=%d.\n",rc);
else
printf("EJECT_SW set to %d\n",i);
break;
case 'M': /* get the multisession redirection info */
ms_info.addr_format=CDROM_LBA;
rc=ioctl(drive,CDROMMULTISESSION,&ms_info);
if (rc!=0)
{
printf("CDROMMULTISESSION(lba): rc=%d.\n",rc);
}
else
{
if (ms_info.xa_flag) printf("MultiSession offset (lba): %d (0x%06X)\n",ms_info.addr.lba,ms_info.addr.lba);
else
{
printf("this CD is not an XA disk.\n");
break;
}
}
ms_info.addr_format=CDROM_MSF;
rc=ioctl(drive,CDROMMULTISESSION,&ms_info);
if (rc!=0)
{
printf("CDROMMULTISESSION(msf): rc=%d.\n",rc);
}
else
{
if (ms_info.xa_flag)
printf("MultiSession offset (msf): %02d:%02d:%02d (0x%02X%02X%02X)\n",
ms_info.addr.msf.minute,
ms_info.addr.msf.second,
ms_info.addr.msf.frame,
ms_info.addr.msf.minute,
ms_info.addr.msf.second,
ms_info.addr.msf.frame);
else printf("this CD is not an XA disk.\n");
}
break;
#ifdef SBP_PRIVATE_IOCTLS
case 'Y': /* set the driver's message level */
#if 0 /* not implemented yet */
printf("enter switch name (f.e. DBG_CMD): ");
scanf("%s",&dbg_switch);
j=get_dbg_num(dbg_switch);
#else
printf("enter DDIOCSDBG switch number: ");
scanf("%d",&j);
#endif
printf("enter 0 for \"off\", 1 for \"on\": ");
scanf("%d",&i);
if (i==0) j|=0x80;
printf("calling \"ioctl(drive,DDIOCSDBG,%d)\"\n",j);
rc=ioctl(drive,DDIOCSDBG,j);
printf("DDIOCSDBG: rc=%d.\n",rc);
break;
case 'Z': /* set the audio buffer size */
printf("# frames wanted: ? ");
scanf("%d",&j);
rc=ioctl(drive,CDROMAUDIOBUFSIZ,j);
printf("%d frames granted.\n",rc);
break;
case 'V':
rc=ioctl(drive,CDROMVOLREAD,&volctrl);
if (rc<0) printf("CDROMVOLCTRL: rc=%d.\n",rc);
printf("Volume: channel 0 (left) %d, channel 1 (right) %d\n",volctrl.channel0,volctrl.channel1);
break;
case 'R':
rc=ioctl(drive,CDROMRESET);
if (rc<0) printf("CDROMRESET: rc=%d.\n",rc);
break;
case 'B': /* set the driver's (?) read ahead value */
printf("enter read-ahead size: ? ");
scanf("%d",&i);
rc=ioctl(drive,BLKRASET,i);
if (rc<0) printf("BLKRASET: rc=%d.\n",rc);
break;
#endif SBP_PRIVATE_IOCTLS
default:
printf("unknown command: \"%s\".\n",command);
break;
}
}
}
/*==========================================================================*/
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 8
* c-brace-imaginary-offset: 0
* c-brace-offset: -8
* c-argdecl-indent: 8
* c-label-offset: -8
* c-continued-statement-offset: 8
* c-continued-brace-offset: 0
* End:
*/
This source diff could not be displayed because it is too large. You can view the blob instead.
Tue May 2 00:53:25 1995 <tytso@rsx-11.mit.edu>
* tty_io.c (tty_set_ldisc): Wait until the output buffer is
drained before closing the old line discipline --- needed
in only one case: XON/XOFF processing.
* n_tty.c (n_tty_close): Don't bother waiting until the output
driver is closed; in general, the line discipline
shouldn't care if the hardware is finished
transmitting before the line discipline terminates.
* tty_io.c (release_dev): Shutdown the line discipline after
decrementing the tty count variable; but set the
TTY_CLOSING flag so that we know that this tty structure
isn't long for this world.
* tty_io.c (init_dev): Add sanity code to check to see if
TTY_CLOSING is set on a tty structure; if so, something
bad has happened (probably a line discipline close blocked
when it shouldn't have; so do a kernel printk and then
return an error).
Wed Apr 26 10:23:44 1995 Theodore Y. Ts'o <tytso@localhost>
* tty_io.c (release_dev): Try to shutdown the line discpline
* tty_io.c (release_dev): Try to shutdown the line discipline
*before* decrementing the tty count variable; this removes
a potential race condition which occurs when the line
discpline close blocks, and another process then tries
discipline close blocks, and another process then tries
open the same serial port.
* serial.c (rs_hangup): When hanging up, flush the output buffer
befure shutting down the UART. Otherwise the line
discpline close blocks waiting for the characters to get
before shutting down the UART. Otherwise the line
discipline close blocks waiting for the characters to get
flushed, which never happens until the serial port gets reused.
Wed Apr 12 08:06:16 1995 Theodore Y. Ts'o <tytso@localhost>
......
......@@ -676,7 +676,6 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
static void n_tty_close(struct tty_struct *tty)
{
tty_wait_until_sent(tty, 0);
n_tty_flush_buffer(tty);
if (tty->read_buf) {
free_page((unsigned long) tty->read_buf);
......
......@@ -204,6 +204,8 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
return 0; /* We are already in the desired discipline */
o_ldisc = tty->ldisc;
tty_wait_until_sent(tty, 0);
/* Shutdown the current discipline. */
if (tty->ldisc.close)
(tty->ldisc.close)(tty);
......@@ -865,8 +867,15 @@ static int init_dev(dev_t device, struct tty_struct **ret_tty)
}
}
tty = NULL;
} else
} else {
if ((*tty_loc)->flags & (1 << TTY_CLOSING)) {
printk("Attempt to open closing tty %s.\n",
tty_name(*tty_loc));
printk("Ack!!!! This should never happen!!\n");
return -EINVAL;
}
(*tty_loc)->count++;
}
if (driver->type == TTY_DRIVER_TYPE_PTY) {
if (!*o_tp_loc) {
*o_tp_loc = o_tp;
......@@ -1006,22 +1015,6 @@ static void release_dev(struct file * filp)
tty->link->count = 0;
}
}
if (tty->count <= 1) {
/*
* Shutdown the current line discipline, and reset it
* to N_TTY.
*/
if (tty->ldisc.close)
(tty->ldisc.close)(tty);
tty->ldisc = ldiscs[N_TTY];
tty->termios->c_line = N_TTY;
if (o_tty && o_tty->count <= 0) {
if (o_tty->ldisc.close)
(o_tty->ldisc.close)(o_tty);
o_tty->ldisc = ldiscs[N_TTY];
o_tty->termios->c_line = N_TTY;
}
}
if (--tty->count < 0) {
printk("release_dev: bad tty->count (%d) for %s\n",
tty->count, tty_name(tty));
......@@ -1030,6 +1023,9 @@ static void release_dev(struct file * filp)
if (tty->count)
return;
/*
* We're committed; at this point, we must not block!
*/
if (o_tty) {
if (o_tty->count)
return;
......@@ -1041,6 +1037,7 @@ static void release_dev(struct file * filp)
#ifdef TTY_DEBUG_HANGUP
printk("freeing tty structure...");
#endif
tty->flags |= (1 << TTY_CLOSING);
/*
* Make sure there aren't any processes that still think this
......@@ -1055,6 +1052,20 @@ static void release_dev(struct file * filp)
(*p)->tty = NULL;
}
/*
* Shutdown the current line discipline, and reset it to
* N_TTY.
*/
if (tty->ldisc.close)
(tty->ldisc.close)(tty);
tty->ldisc = ldiscs[N_TTY];
tty->termios->c_line = N_TTY;
if (o_tty) {
if (o_tty->ldisc.close)
(o_tty->ldisc.close)(o_tty);
o_tty->ldisc = ldiscs[N_TTY];
}
tty->driver.table[idx] = NULL;
if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
tty->driver.termios[idx] = NULL;
......
......@@ -60,7 +60,7 @@ struct ei_device {
struct enet_statistics stat;
};
/* The maximum number of 8390 interrupt serivce routines called per IRQ. */
/* The maximum number of 8390 interrupt service routines called per IRQ. */
#define MAX_SERVICE 12
/* The maximum number of jiffies waited before assuming a Tx failed. */
......
......@@ -40,10 +40,27 @@
# EWRK3_DEBUG Set the desired debug level
#
# DE4x5 The DIGITAL series of PCI/EISA Ethernet Cards,
# DE425, DE434 and DE435
# DE4x5_DEBUG Set the desired debug level
# IS_ZYNX May allow driver to work with Zynx cards -
# DE425, DE434, DE435, DE500
# DE4X5_DEBUG Set the desired debug level
# IS_NOT_DEC May allow driver to work with Zynx & SMC cards -
# see linux/drivers/net/README.de4x5
# DE4X5_AUTOSENSE (Default) auto media/mode selection
# If you want at least one board to not autosense then
# no board can autosense. For a board mix of several
# types, OR the manual values [eg for a DE500 (100M) with
# a DE450 (AUI) use '-DDE4X5_AUTOSENSE=(0x80|0x08)']
# For full auto media/mode selection = 0x4000
# For manual TP media selection = 0x01
# For manual TP/Nway media selection (DC21041) = 0x02
# For manual BNC media selection = 0x04
# For manual AUI media selection = 0x08
# For manual BNC/AUI media selection (DC21040) = 0x10
# For manual 10Mb/s mode selection (DC21140) = 0x40
# For manual 100Mb/s mode selection (DC21140) = 0x80
# The DC21040 will default to TP if TP_NW is specified
# The DC21041 will default to BNC if BNC_AUI is specified
# The DC21140 needs it's speed to be manually set to
# 10Mb/s or 100Mb/s (AUTO defaults to 10Mb/s)
#
# The following options exist, but cannot be set in this file.
......@@ -66,4 +83,4 @@ HP_OPTS =
PLIP_OPTS =
DEPCA_OPTS = -DDEPCA_DEBUG=1
EWRK3_OPTS = -DEWRK3_DEBUG=1
DE4x5_OPTS = -DDE4x5_DEBUG=1
DE4X5_OPTS = -DDE4X5_DEBUG=1 -DDE4X5_AUTOSENSE=0x4000
The de425/de434/de435 driver in this distribution is designed to work with
the Digital Equipment Corporation series of PCI/EISA ethernet cards (DE425,
DE434, DE435) and with all kernels that support PCI.
The de425/de434/de435/de500 driver in this distribution is designed to work
with the Digital Equipment Corporation series of PCI/EISA ethernet cards
(DE425, DE434, DE435, DE500) and with all kernels that support PCI.
Auto media detection is provided so that the media choice isn't compiled in
and is flexible enough to be able to reconfigure on-the-fly.
The ability to load this driver as a loadable module has been included,
and is flexible enough to be able to reconfigure on-the-fly. This feature
hasn't been included for the DE500 unfortunately, due to a potential patent
dispute. When I get around to implementing the autosense algorithm by myself
(which could legally be difficult to prove since I'm part of the group that
has implemented the patented algorithm) you'll have an auto speed selection
for the de500. If you want the auto speed feature yell at Digital. If enough
of you do things might change.
The ability to load this driver as a loadable module has been included,
although I don't recommend its use with PCI, since PCI dynamically allocates
where the card will go at boot time.
The performance we've achieved so far has been measured through the 'ttcp'
tool at 1.08MB/s. This measures the total tcp stack performance which
includes the card, so don't expect to get much nearer the 1.25MB/s
theoretical ethernet rate.
************************************************************************
However there is still a known bug which causes ttcp to hang on transmit
(receive is OK), although the adapter/driver continues to function
normally for other applications e.g. nfs mounting disks, pinging etc.
The cause is under investigation.
************************************************************************
ZYNX cards, which use the PCI DECchip DC21040, are not specifically
where the card will go at boot time (i.e. the card would have to be present
in the system at boot time for its address/IRQ to be assigned).
The performance we've achieved so far has been measured through the 'ttcp'
tool at 1.06MB/s for TCP and 1.17MB/s for UDP. This measures the total
stack performance which includes the card, so don't expect to get much
nearer the 1.25MB/s theoretical ethernet rate.
TCP UDP
TX RX TX RX
DE425 1030k 997k 1170k 1128k (EISA on a Dell 433DE)
DE434 1063k 995k 1170k 1125k (PCI: DECpc XL 466d2)
DE435 1063k 995k 1170k 1125k (PCI: DECpc XL 466d2)
DE500 1063k 998k 1170k 1125k in 10Mb/s mode (PCI: DECpc XL 466d2)
All values are typical (in kBytes/sec) from a sample of 4 for each
measurement. Their error is approx +/-20k on a quiet (private) network and
also depend on what load the CPU has, CPU speed etc.
ZYNX and SMC cards, which use the PCI DECchip DC21040, are not specifically
supported in this driver because
a) I have no information on them.
b) I cannot test them with the driver.
c) Donald Becker's 'tulip.c' driver works with them....well one person says
they do and another doesn't, so take your pick!
they do and another says they do not, so take your pick!
This driver can be made to work with the ZYNX (and may be the SMC) card by
setting a compile time flag in linux/drivers/net/CONFIG
setting a compile time flag (IS_NOT_DEC) in linux/drivers/net/CONFIG
Enjoy!
......
/* de4x5.c: A DIGITAL DE425/DE434/DE435 ethernet driver for linux.
Copyright 1994 Digital Equipment Corporation.
Copyright 1994, 1995 Digital Equipment Corporation.
This software may be used and distributed according to the terms of
the GNU Public License, incorporated herein by reference.
......@@ -11,17 +11,22 @@
DE425 TP/COAX EISA
DE434 TP PCI
DE435 TP/COAX/AUI PCI
DE500 10/100 PCI Fasternet
The driver has been tested on a relatively busy network using the DE425
and DE435 cards and benchmarked with 'ttcp': it transferred 16M of data
at 1.08MB/s (8.6Mb/s) to a DECstation 5000/200.
The driver has been tested on a relatively busy network using the DE425,
DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred
16M of data to a DECstation 5000/200 as follows:
************************************************************************
However there is still a known bug which causes ttcp to hang on transmit
(receive is OK), although the adapter/driver continues to function
normally for other applications e.g. nfs mounting disks, pinging etc.
The cause is under investigation.
************************************************************************
TCP UDP
TX RX TX RX
DE425 1030k 997k 1170k 1128k
DE434 1063k 995k 1170k 1125k
DE435 1063k 995k 1170k 1125k
DE500 1063k 998k 1170k 1125k in 10Mb/s mode
All values are typical (in kBytes/sec) from a sample of 4 for each
measurement. Their error is +/-20k on a quiet (private) network and also
depend on what load the CPU has.
The author may be reached as davies@wanton.lkg.dec.com or Digital
Equipment Corporation, 550 King Street, Littleton MA 01460.
......@@ -98,9 +103,6 @@
TO DO:
------
1. Add DC21041 Nway/Autosense support
2. Add DC21140 Autosense support
3. Add timer support
Revision History
......@@ -109,18 +111,26 @@
Version Date Description
0.1 17-Nov-94 Initial writing. ALPHA code release.
0.2 13-Jan-95 Added PCI support for DE435's
0.21 19-Jan-95 Added auto media detection
0.22 10-Feb-95 Fix interrupt handler call <chris@cosy.sbg.ac.at>
Fix recognition bug reported by <bkm@star.rl.ac.uk>
Add request/release_region code
Add loadable modules support for PCI
Clean up loadable modules support
0.2 13-Jan-95 Added PCI support for DE435's.
0.21 19-Jan-95 Added auto media detection.
0.22 10-Feb-95 Fix interrupt handler call <chris@cosy.sbg.ac.at>.
Fix recognition bug reported by <bkm@star.rl.ac.uk>.
Add request/release_region code.
Add loadable modules support for PCI.
Clean up loadable modules support.
0.23 28-Feb-95 Added DC21041 and DC21140 support.
Fix missed frame counter value and initialisation.
Fixed EISA probe.
0.24 11-Apr-95 Change delay routine to use <linux/udelay>.
Change TX_BUFFS_AVAIL macro.
Change media autodetection to allow manual setting.
Completed DE500 (DC21140) support.
0.241 18-Apr-95 Interim release without DE500 Autosense Algorithm.
=========================================================================
*/
static char *version = "de4x5.c:v0.22 2/10/95 davies@wanton.lkg.dec.com\n";
static char *version = "de4x5.c:v0.241 4/18/95 davies@wanton.lkg.dec.com\n";
#include <linux/config.h>
#ifdef MODULE
......@@ -140,6 +150,7 @@ static char *version = "de4x5.c:v0.22 2/10/95 davies@wanton.lkg.dec.com\n";
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
......@@ -161,6 +172,12 @@ static int de4x5_debug = DE4X5_DEBUG;
static int de4x5_debug = 1;
#endif
#ifdef DE4X5_AUTOSENSE /* Should be done on a per adapter basis */
static int de4x5_autosense = DE4X5_AUTOSENSE;
#else
static int de4x5_autosense = AUTO; /* Do auto media/mode sensing */
#endif
/*
** Ethernet PROM defines
*/
......@@ -198,79 +215,102 @@ static int de4x5_debug = 1;
#define DE4X5_PCI_TOTAL_SIZE 0x80 /* I/O address extent */
/*
** Timer defines
** Memory Alignment. Each descriptor is 4 longwords long. To force a
** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
** DESC_ALIGN. ALIGN aligns the start address of the private memory area
** and hence the RX descriptor ring's first entry.
*/
#define TIMER_WIDTH 16
#define TIMER_PORT 0x43
#define TIMER_LATCH 0x06
#define TIMER_READ 0x40
#define TIMER_TICK 419 /*ns*/
#define DELAY_QUANT 5 /*us*/
#define LWPAD ((long)(sizeof(long) - 1)) /* for longword alignment */
#ifndef IS_ZYNX /* See README.de4x5 for using this */
static int is_zynx = 0;
#define ALIGN4 ((u_long)4 - 1) /* 1 longword align */
#define ALIGN8 ((u_long)8 - 1) /* 2 longword align */
#define ALIGN16 ((u_long)16 - 1) /* 4 longword align */
#define ALIGN32 ((u_long)32 - 1) /* 8 longword align */
#define ALIGN64 ((u_long)64 - 1) /* 16 longword align */
#define ALIGN128 ((u_long)128 - 1) /* 32 longword align */
#define ALIGN ALIGN32 /* Keep the DC21040 happy... */
#define CACHE_ALIGN CAL_16LONG
#define DESC_SKIP_LEN DSL_0 /* Must agree with DESC_ALIGN */
/*#define DESC_ALIGN u_long dummy[4]; / * Must agree with DESC_SKIP_LEN */
#define DESC_ALIGN
#ifndef IS_NOT_DEC /* See README.de4x5 for using this */
static int is_not_dec = 0;
#else
static int is_zynx = 1;
static int is_not_dec = 1;
#endif
/*
** DE4X5 IRQ ENABLE/DISABLE
*/
static u_long irq_mask = IMR_RIM | IMR_TIM | IMR_TUM ;
static u_long irq_mask = IMR_SEM | IMR_RIM | IMR_RUM | IMR_TIM | IMR_TUM ;
static u_long irq_en = IMR_NIM | IMR_AIM;
#define ENABLE_IRQs \
#define ENABLE_IRQs { \
imr |= irq_en;\
outl(imr, DE4X5_IMR) /* Enable the IRQs */
outl(imr, DE4X5_IMR); /* Enable the IRQs */\
}
#define DISABLE_IRQs \
#define DISABLE_IRQs {\
imr = inl(DE4X5_IMR);\
imr &= ~irq_en;\
outl(imr, DE4X5_IMR) /* Disable the IRQs */
outl(imr, DE4X5_IMR); /* Disable the IRQs */\
}
#define UNMASK_IRQs \
#define UNMASK_IRQs {\
imr |= irq_mask;\
outl(imr, DE4X5_IMR) /* Unmask the IRQs */
outl(imr, DE4X5_IMR); /* Unmask the IRQs */\
}
#define MASK_IRQs \
#define MASK_IRQs {\
imr = inl(DE4X5_IMR);\
imr &= ~irq_mask;\
outl(imr, DE4X5_IMR) /* Mask the IRQs */
outl(imr, DE4X5_IMR); /* Mask the IRQs */\
}
/*
** DE4X5 START/STOP
*/
#define START_DE4X5 \
#define START_DE4X5 {\
omr = inl(DE4X5_OMR);\
omr |= OMR_ST | OMR_SR;\
outl(omr, DE4X5_OMR) /* Enable the TX and/or RX */
outl(omr, DE4X5_OMR); /* Enable the TX and/or RX */\
}
#define STOP_DE4X5 \
#define STOP_DE4X5 {\
omr = inl(DE4X5_OMR);\
omr &= ~(OMR_ST|OMR_SR);\
outl(omr, DE4X5_OMR) /* Disable the TX and/or RX */
outl(omr, DE4X5_OMR); /* Disable the TX and/or RX */ \
}
/*
** DE4X5 SIA RESET
*/
#define RESET_SIA \
outl(SICR_RESET, DE4X5_SICR); /* Reset SIA connectivity regs */ \
outl(STRR_RESET, DE4X5_STRR); /* Write reset values */ \
outl(SIGR_RESET, DE4X5_SIGR) /* Write reset values */
#define RESET_SIA outl(0, DE4X5_SICR); /* Reset SIA connectivity regs */
/*
** SROM Structure
*/
struct de4x5_srom {
char reserved[18];
char version;
char num_adapters;
char ieee_addr[6];
char info[100];
short chksum;
};
/*
** DE4X5 Descriptors. Make sure that all the RX buffers are contiguous
** and have sizes of both a power of 2 and a multiple of 4.
** A size of 256 bytes for each buffer was chosen because over 90% of
** all packets in our network are <256 bytes long.
** all packets in our network are <256 bytes long and 64 longword alignment
** is possible.
*/
#define NUM_RX_DESC 64 /* Number of RX descriptors */
#define NUM_RX_DESC 8 /* Number of RX descriptors */
#define NUM_TX_DESC 8 /* Number of TX descriptors */
#define BUFF_ALLOC_RETRIES 10 /* In case of memory shortage */
#define RX_BUFF_SZ 256 /* Power of 2 for kmalloc and */
#define RX_BUFF_SZ 1536 /* Power of 2 for kmalloc and */
/* Multiple of 4 for DC21040 */
struct de4x5_desc {
......@@ -278,6 +318,7 @@ struct de4x5_desc {
u_long des1;
char *buf;
char *next;
DESC_ALIGN
};
/*
......@@ -308,48 +349,76 @@ struct de4x5_private {
char rxRingSize;
char txRingSize;
char bus; /* EISA or PCI */
u_short chipset; /* DC21040, DC21041 or DC21140 */
long media; /* Media (eg TP), mode (eg 100B)*/
int autosense; /* Allow/disallow autosensing */
int tx_enable; /* Enable descriptor polling */
char lostMedia; /* Possibly lost media */
int setup_f; /* Setup frame filtering type */
};
/*
** The transmit ring full condition is described by the tx_old and tx_new
** pointers by:
** tx_old = tx_new Empty ring
** tx_old = tx_new+1 Full ring
** tx_old+txRingSize = tx_new+1 Full ring (wrapped condition)
*/
#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
lp->tx_old+lp->txRingSize-lp->tx_new-1:\
lp->tx_old -lp->tx_new-1)
#define TX_SUSPENDED (((sts & STS_TS) ^ TS_SUSP)==0)
/*#define TX_BUFFS_AVAIL ((lp->tx_ring[lp->tx_new].status)>=0 ? 1 : 0)*/
/*
** Public Functions
*/
static int de4x5_open(struct device *dev);
static int de4x5_queue_pkt(struct sk_buff *skb, struct device *dev);
static void de4x5_interrupt(int irq, struct pt_regs * regs);
static int de4x5_close(struct device *dev);
static struct enet_statistics *de4x5_get_stats(struct device *dev);
static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd);
static int de4x5_open(struct device *dev);
static int de4x5_queue_pkt(struct sk_buff *skb, struct device *dev);
static void de4x5_interrupt(int irq, struct pt_regs *regs);
static int de4x5_close(struct device *dev);
static struct enet_statistics *de4x5_get_stats(struct device *dev);
static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd);
/*
** Private functions
*/
static int de4x5_hw_init(struct device *dev, short iobase);
static int de4x5_init(struct device *dev);
static int de4x5_rx(struct device *dev);
static int de4x5_tx(struct device *dev);
static int autoconf_media(struct device *dev);
static void create_packet(struct device *dev, char *frame, int len);
static u_short dce_get_ticks(void);
static void dce_us_delay(u_long usec);
static void dce_ms_delay(u_long msec);
static void load_packet(struct device *dev, char *buf, u_long flags, struct sk_buff *skb);
static void EISA_signature(char * name, short iobase);
static int DevicePresent(short iobase);
static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs, char *multicast_table);
static int aprom_crc (struct device *dev);
static void eisa_probe(struct device *dev, short iobase);
static void pci_probe(struct device *dev, short iobase);
static struct device *alloc_device(struct device *dev, int iobase);
static int de4x5_hw_init(struct device *dev, short iobase);
static int de4x5_init(struct device *dev);
static int de4x5_rx(struct device *dev);
static int de4x5_tx(struct device *dev);
static int autoconf_media(struct device *dev);
static void create_packet(struct device *dev, char *frame, int len);
static void dce_us_delay(u_long usec);
static void dce_ms_delay(u_long msec);
static void load_packet(struct device *dev, char *buf, u_long flags, struct sk_buff *skb);
static void dc21040_autoconf(struct device *dev);
static void dc21041_autoconf(struct device *dev);
static void dc21140_autoconf(struct device *dev);
static long test_media(struct device *dev, long irqs, long irq_mask, long csr13, long csr14, long csr15, long msec);
static long ping_media(struct device *dev);
static void reset_init_sia(struct device *dev, long sicr, long strr, long sigr);
static int test_ans(struct device *dev, long irqs, long irq_mask, long msec);
static void load_ms_timer(struct device *dev, u_long msec);
static int EISA_signature(char *name, long eisa_id);
static int DevicePresent(short iobase);
static short srom_rd(u_short address, u_char offset);
static void srom_latch(u_long command, u_short address);
static void srom_command(u_long command, u_short address);
static void srom_address(u_long command, u_short address, u_char offset);
static short srom_data(u_long command, u_short address);
/*static void srom_busy(u_long command, u_short address);*/
static void sendto_srom(u_long command, u_short addr);
static long getfrom_srom(u_short addr);
static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs);
static int aprom_crc (struct device *dev);
static void eisa_probe(struct device *dev, short iobase);
static void pci_probe(struct device *dev, short iobase);
static struct device *alloc_device(struct device *dev, int iobase);
static char *build_setup_frame(struct device *dev, int mode);
#ifdef MODULE
int init_module(void);
......@@ -371,6 +440,9 @@ static int num_de4x5s = 0, num_eth = 0;
static struct bus_type {
int bus;
int device;
int chipset;
struct de4x5_srom srom;
int autosense;
} bus;
/*
......@@ -382,8 +454,7 @@ static struct bus_type {
outl(i | BMR_SWR, DE4X5_BMR);\
outl(i, DE4X5_BMR);\
for (i=0;i<5;i++) inl(DE4X5_BMR);\
}
}
......@@ -409,7 +480,7 @@ int de4x5_probe(struct device *dev)
** Walk the device list to check that at least one device
** initialised OK
*/
for (; dev->priv == NULL && dev->next != NULL; dev = dev->next);
for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next);
if (dev->priv) status = 0;
if (iobase == 0) autoprobed = 1;
......@@ -422,10 +493,16 @@ static int
de4x5_hw_init(struct device *dev, short iobase)
{
struct bus_type *lp = &bus;
int tmpbus, i, j, status=0;
int tmpbus, tmpchs, i, j, status=0;
char *tmp;
u_long nicsr;
/* Ensure we're not sleeping */
if (lp->chipset == DC21041) {
outl(0, PCI_CFDA);
dce_ms_delay(10);
}
RESET_DE4X5;
if (((nicsr=inl(DE4X5_STS)) & (STS_TS | STS_RS)) == 0) {
......@@ -433,10 +510,14 @@ de4x5_hw_init(struct device *dev, short iobase)
** Now find out what kind of DC21040/DC21041/DC21140 board we have.
*/
if (lp->bus == PCI) {
if (!is_zynx) {
strcpy(name, "DE435");
if (!is_not_dec) {
if ((lp->chipset == DC21040) || (lp->chipset == DC21041)) {
strcpy(name, "DE435");
} else if (lp->chipset == DC21140) {
strcpy(name, "DE500"); /* Must read the SROM here! */
}
} else {
strcpy(name, "ZYNX");
strcpy(name, "UNKNOWN");
}
} else {
EISA_signature(name, EISA_ID0);
......@@ -444,8 +525,6 @@ de4x5_hw_init(struct device *dev, short iobase)
if (*name != '\0') { /* found a board signature */
dev->base_addr = iobase;
request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
DE4X5_EISA_TOTAL_SIZE), name);
if (lp->bus == EISA) {
printk("%s: %s at %#3x (EISA slot %d)",
......@@ -462,6 +541,7 @@ de4x5_hw_init(struct device *dev, short iobase)
printk("%2.2x,\n", dev->dev_addr[i]);
tmpbus = lp->bus;
tmpchs = lp->chipset;
if (status == 0) {
struct de4x5_private *lp;
......@@ -470,26 +550,50 @@ de4x5_hw_init(struct device *dev, short iobase)
** Reserve a section of kernel memory for the adapter
** private area and the TX/RX descriptor rings.
*/
dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + LWPAD,
dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN,
GFP_KERNEL);
/*
** Align to a longword boundary
*/
dev->priv = (void *)(((u_long)dev->priv + LWPAD) & ~LWPAD);
dev->priv = (void *)(((u_long)dev->priv + ALIGN) & ~ALIGN);
lp = (struct de4x5_private *)dev->priv;
memset(dev->priv, 0, sizeof(struct de4x5_private));
lp->bus = tmpbus;
strcpy(lp->adapter_name, name);
lp->chipset = tmpchs;
/*
** Choose autosensing
*/
if (de4x5_autosense & AUTO) {
lp->autosense = AUTO;
} else {
if (lp->chipset != DC21140) {
if ((lp->chipset == DC21040) && (de4x5_autosense & TP_NW)) {
de4x5_autosense = TP;
}
if ((lp->chipset == DC21041) && (de4x5_autosense & BNC_AUI)) {
de4x5_autosense = BNC;
}
lp->autosense = de4x5_autosense & 0x001f;
} else {
lp->autosense = de4x5_autosense & 0x00c0;
}
}
sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
DE4X5_EISA_TOTAL_SIZE),
lp->adapter_name);
/*
** Allocate contiguous receive buffers, long word aligned.
** This could be a possible memory leak if the private area
** is ever hosed.
*/
for (tmp=NULL, j=0; j<BUFF_ALLOC_RETRIES && tmp==NULL; j++) {
if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + LWPAD,
for (tmp=NULL, j=0; (j<BUFF_ALLOC_RETRIES) && (tmp==NULL); j++) {
if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN,
GFP_KERNEL)) != NULL) {
tmp = (void *)(((u_long) tmp + LWPAD) & ~LWPAD);
tmp = (char *)(((u_long) tmp + ALIGN) & ~ALIGN);
for (i=0; i<NUM_RX_DESC; i++) {
lp->rx_ring[i].status = 0;
lp->rx_ring[i].des1 = RX_BUFF_SZ;
......@@ -508,8 +612,10 @@ de4x5_hw_init(struct device *dev, short iobase)
lp->tx_ring[lp->txRingSize - 1].des1 |= TD_TER;
/* Tell the adapter where the TX/RX rings are located. */
outl((u_long)lp->rx_ring, DE4X5_RRBA);
outl((u_long)lp->tx_ring, DE4X5_TRBA);
outl((long)lp->rx_ring, DE4X5_RRBA);
outl((long)lp->tx_ring, DE4X5_TRBA);
lp->tx_enable = TRUE;
if (dev->irq < 2) {
#ifndef MODULE
......@@ -526,7 +632,7 @@ de4x5_hw_init(struct device *dev, short iobase)
printk(" and failed to detect IRQ line.\n");
status = -ENXIO;
} else {
for (dev->irq=0,i=0; i<sizeof(de4x5_irq) && !dev->irq; i++) {
for (dev->irq=0,i=0; (i<sizeof(de4x5_irq)) && (!dev->irq); i++) {
if (irqnum == de4x5_irq[i]) {
dev->irq = irqnum;
printk(" and uses IRQ%d.\n", dev->irq);
......@@ -550,13 +656,13 @@ de4x5_hw_init(struct device *dev, short iobase)
dev->name);
status = -ENXIO;
}
if (status) release_region(iobase, (lp->bus == PCI ?
DE4X5_PCI_TOTAL_SIZE :
DE4X5_EISA_TOTAL_SIZE));
} else {
printk(" which has an Ethernet PROM CRC error.\n");
status = -ENXIO;
}
if (status) release_region(iobase, (lp->bus == PCI ?
DE4X5_PCI_TOTAL_SIZE :
DE4X5_EISA_TOTAL_SIZE));
} else {
status = -ENXIO;
}
......@@ -583,13 +689,19 @@ de4x5_hw_init(struct device *dev, short iobase)
/* Fill in the generic field of the device structure. */
ether_setup(dev);
/* Let the adapter sleep to save power */
if (lp->chipset == DC21041) {
outl(0, DE4X5_SICR);
outl(CFDA_PSM, PCI_CFDA);
}
} else { /* Incorrectly initialised hardware */
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
if (lp) {
kfree_s(lp->rx_ring[0].buf, RX_BUFF_SZ * NUM_RX_DESC + LWPAD);
kfree_s(lp->rx_ring[0].buf, RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
}
if (dev->priv) {
kfree_s(dev->priv, sizeof(struct de4x5_private) + LWPAD);
kfree_s(dev->priv, sizeof(struct de4x5_private) + ALIGN);
dev->priv = NULL;
}
}
......@@ -604,12 +716,15 @@ de4x5_open(struct device *dev)
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
short iobase = dev->base_addr;
int i, status = 0;
u_long imr, omr, sts;
long imr, omr, sts;
/*
** Stop the TX and RX...
** Wake up the adapter
*/
STOP_DE4X5;
if (lp->chipset == DC21041) {
outl(0, PCI_CFDA);
dce_ms_delay(10);
}
if (request_irq(dev->irq, (void *)de4x5_interrupt, 0, lp->adapter_name)) {
printk("de4x5_open(): Requested IRQ%d is busy\n",dev->irq);
......@@ -669,21 +784,19 @@ de4x5_open(struct device *dev)
dev->tbusy = 0;
dev->start = 1;
dev->interrupt = UNMASK_INTERRUPTS;
/*
** Reset any pending interrupts
*/
sts = inl(DE4X5_STS);
outl(sts, DE4X5_STS);
dev->trans_start = jiffies;
/*
** Unmask and enable DE4X5 board interrupts
*/
START_DE4X5;
/* Unmask and enable DE4X5 board interrupts */
imr = 0;
UNMASK_IRQs;
ENABLE_IRQs;
START_DE4X5;
/* Reset any pending (stale) interrupts */
sts = inl(DE4X5_STS);
outl(sts, DE4X5_STS);
ENABLE_IRQs;
}
if (de4x5_debug > 1) {
printk("\tsts: 0x%08x\n", inl(DE4X5_STS));
......@@ -703,70 +816,63 @@ de4x5_open(struct device *dev)
}
/*
** Initialize the DE4X5 operating conditions
** Initialize the DE4X5 operating conditions. NB: a chip problem with the
** DC21140 requires using perfect filtering mode for that chip. Since I can't
** see why I'd want > 14 multicast addresses, I may change all chips to use
** the perfect filtering mode. Keep the DMA burst length at 8: there seems
** to be data corruption problems if it is larger (UDP errors seen from a
** ttcp source).
*/
static int
de4x5_init(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
short iobase = dev->base_addr;
int offset, status = 0;
u_long i, j, bmr, omr;
char *pa;
int status = 0;
long i, j, bmr, omr;
/* Lock out other processes whilst setting up the hardware */
set_bit(0, (void *)&dev->tbusy);
/* Ensure a full reset */
RESET_DE4X5;
/* Set up automatic transmit polling every 1.6ms */
bmr = inl(DE4X5_BMR);
bmr |= TAP_1_6MS | CAL_16LONG;
bmr |= PBL_8 | DESC_SKIP_LEN | CACHE_ALIGN;
outl(bmr, DE4X5_BMR);
/* Set up imperfect filtering mode as default, turn off promiscuous mode */
omr = OMR_HP;
offset = IMPERF_PA_OFFSET;
/* Lock out other processes whilst setting up the hardware */
set_bit(0, (void *)&dev->tbusy);
/* Rewrite the descriptor lists' start addresses */
outl((u_long)lp->rx_ring, DE4X5_RRBA); /* Start of RX Descriptor List */
outl((u_long)lp->tx_ring, DE4X5_TRBA); /* Start of TX Descriptor List */
if (lp->chipset != DC21140) {
omr = TR_96;
lp->setup_f = HASH_PERF;
} else {
omr = OMR_SDP | OMR_SF;
lp->setup_f = PERFECT;
}
outl((long)lp->rx_ring, DE4X5_RRBA);
outl((long)lp->tx_ring, DE4X5_TRBA);
/* Reset the buffer pointers */
lp->rx_new = lp->rx_old = 0;
lp->tx_new = lp->tx_old = 0;
/* Initialize each descriptor ownership in the RX ring */
for (i = 0; i < lp->rxRingSize; i++) {
lp->rx_ring[i].status = R_OWN;
}
/* Initialize each descriptor ownership in the TX ring */
for (i = 0; i < lp->txRingSize; i++) {
lp->tx_ring[i].status = 0;
}
/* Initialise the setup frame prior to starting the receive process */
memset(lp->setup_frame, 0, SETUP_FRAME_LEN);
/* Build the setup frame depending on filtering mode */
SetMulticastFilter(dev, 0, NULL);
/* Insert the physical address */
for (pa=lp->setup_frame+offset, j=0; j<ETH_ALEN; j++) {
*(pa + j) = dev->dev_addr[j];
if (j & 0x01) pa += 2;
if (lp->chipset != DC21140) {
load_packet(dev, lp->setup_frame, HASH_F|TD_SET|SETUP_FRAME_LEN, NULL);
} else {
load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL);
}
/* Clear the multicast list */
set_multicast_list(dev, 0, NULL);
/* Tell the hardware there's a new packet to be sent */
load_packet(dev, lp->setup_frame, HASH_F | TD_SET | SETUP_FRAME_LEN, NULL);
/* Start the TX process */
outl(omr|OMR_ST, DE4X5_OMR);
/* Poll for completion of setup frame (interrupts are disabled for now) */
for (j=0, i=0;i<100 && j==0;i++) {
for (j=0, i=0;(i<100) && (j==0);i++) {
if (lp->tx_ring[lp->tx_new].status >= 0) j=1;
}
outl(omr, DE4X5_OMR); /* Stop everything! */
......@@ -777,7 +883,6 @@ de4x5_init(struct device *dev)
status = -EIO;
}
/* Update pointers */
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
lp->tx_old = lp->tx_new;
......@@ -807,13 +912,9 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
** The 'lostMedia' threshold accounts for transient errors that
** were noticed when switching media.
*/
if (dev->tbusy || (lp->lostMedia > 3)) {
if (dev->tbusy || (lp->lostMedia > LOST_MEDIA_THRESHOLD)) {
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 10 && !lp->lostMedia) {
/* Check if TX ring is full or not - 'tbusy' cleared if not full. */
if ((TX_BUFFS_AVAIL > 0) && dev->tbusy) {
dev->tbusy = 0;
}
if (tickssofar < 10 && (lp->lostMedia <= LOST_MEDIA_THRESHOLD)) {
status = -1;
} else {
printk("%s: transmit timed out, status %08x, tbusy:%d, lostMedia:%d tickssofar:%d, resetting.\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, tickssofar);
......@@ -825,21 +926,21 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
/* Unmask DE4X5 board interrupts */
if (!status) {
/* Start here to clean stale interrupts later */
dev->interrupt = UNMASK_INTERRUPTS;
dev->start = 1;
dev->tbusy = 0;
dev->trans_start = jiffies;
START_DE4X5;
/* Unmask DE4X5 board interrupts */
imr = 0;
UNMASK_IRQs;
/* Clear any pending (stale) interrupts */
sts = inl(DE4X5_STS);
outl(sts, DE4X5_STS);
/* Unmask DE4X5 board interrupts */
imr = 0;
UNMASK_IRQs;
dev->interrupt = UNMASK_INTERRUPTS;
dev->start = 1;
dev->tbusy = 0;
ENABLE_IRQs;
} else {
printk("%s: hardware initialisation failure, status %08x.\n",
......@@ -857,20 +958,18 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
if (set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
if (TX_BUFFS_AVAIL > 0) { /* Fill in a Tx ring entry */
if (((u_long)skb->data & ~0x03) != (u_long)skb->data) {
printk("%s: TX skb buffer alignment prob..\n", dev->name);
}
if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */
load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
if (lp->tx_enable) {
outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
}
lp->tx_new = (++lp->tx_new) % lp->txRingSize; /* Ensure a wrap */
dev->trans_start = jiffies;
}
if (TX_BUFFS_AVAIL > 0) {
if (TX_BUFFS_AVAIL) {
dev->tbusy = 0; /* Another pkt may be queued */
}
}
......@@ -882,12 +981,12 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
** The DE4X5 interrupt handler.
*/
static void
de4x5_interrupt(int irq, struct pt_regs * regs)
de4x5_interrupt(int irq, struct pt_regs *regs)
{
struct device *dev = (struct device *)(irq2dev_map[irq]);
struct de4x5_private *lp;
int iobase;
u_long imr, sts;
u_long imr, omr, sts;
if (dev == NULL) {
printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq);
......@@ -909,19 +1008,22 @@ de4x5_interrupt(int irq, struct pt_regs * regs)
sts = inl(DE4X5_STS);
MASK_IRQs;
/*
** Acknowledge the DE4X5 board interrupts
*/
outl(sts, DE4X5_STS);
outl(sts, DE4X5_STS); /* Reset the board interrupts */
if (sts & STS_RI) /* Rx interrupt (packet[s] arrived) */
if (sts & (STS_RI | STS_RU)) /* Rx interrupt (packet[s] arrived) */
de4x5_rx(dev);
if (sts & STS_TI) /* Tx interrupt (packet sent) */
if (sts & (STS_TI | STS_TU)) /* Tx interrupt (packet sent) */
de4x5_tx(dev);
if ((TX_BUFFS_AVAIL > 0) && dev->tbusy) { /* any resources available? */
dev->tbusy = 0; /* clear TX busy flag */
if (sts & STS_SE) { /* Bus Error */
STOP_DE4X5;
printk("%s: Fatal bus error occurred, sts=0x%08lx, device stopped.\n",
dev->name, sts);
}
if (TX_BUFFS_AVAIL && dev->tbusy) {/* Any resources available? */
dev->tbusy = 0; /* Clear TX busy flag */
mark_bh(NET_BH);
}
......@@ -941,7 +1043,6 @@ de4x5_rx(struct device *dev)
volatile long status;
char *buf;
/* Loop over any new packets for sending up the stack */
for (entry = lp->rx_new; lp->rx_ring[entry].status >= 0;entry = lp->rx_new) {
status = lp->rx_ring[entry].status;
......@@ -957,7 +1058,7 @@ de4x5_rx(struct device *dev)
if (status & RD_OF) lp->stats.rx_fifo_errors++;
} else { /* A valid frame received */
struct sk_buff *skb;
short pkt_len = (short)(lp->rx_ring[entry].status >> 16);
short pkt_len = (short)(lp->rx_ring[entry].status >> 16) - 4;
if ((skb = alloc_skb(pkt_len, GFP_ATOMIC)) != NULL) {
skb->len = pkt_len;
......@@ -982,7 +1083,7 @@ de4x5_rx(struct device *dev)
*/
lp->stats.rx_packets++;
for (i=1; i<DE4X5_PKT_STAT_SZ-1; i++) {
if (pkt_len < i*DE4X5_PKT_BIN_SZ) {
if (pkt_len < (i*DE4X5_PKT_BIN_SZ)) {
lp->pktStats.bins[i]++;
i = DE4X5_PKT_STAT_SZ;
}
......@@ -1034,7 +1135,7 @@ de4x5_tx(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int entry, iobase = dev->base_addr;
volatile long status;
long status;
for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
status = lp->tx_ring[entry].status;
......@@ -1100,6 +1201,12 @@ de4x5_close(struct device *dev)
MOD_DEC_USE_COUNT;
/* Put the adapter to sleep to save power */
if (lp->chipset == DC21041) {
outl(0, DE4X5_SICR);
outl(CFDA_PSM, PCI_CFDA);
}
return 0;
}
......@@ -1109,7 +1216,7 @@ de4x5_get_stats(struct device *dev)
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int iobase = dev->base_addr;
lp->stats.rx_missed_errors = (int) inl(DE4X5_MFC);
lp->stats.rx_missed_errors = (int) (inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR));
return &lp->stats;
}
......@@ -1128,42 +1235,39 @@ static void load_packet(struct device *dev, char *buf, u_long flags, struct sk_b
}
/*
** Set or clear the multicast filter for this adaptor.
** num_addrs == -1 Promiscuous mode, receive all packets
** num_addrs == -1 Promiscuous mode, receive all packets - not supported.
** Use the ioctls.
** num_addrs == 0 Normal mode, clear multicast list
** num_addrs > 0 Multicast mode, receive normal and MC packets, and do
** best-effort filtering.
** num_addrs == HASH_TABLE_LEN
** Set all multicast bits
** Set all multicast bits (pass all multicasts).
*/
static void
set_multicast_list(struct device *dev, int num_addrs, void *addrs)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int iobase = dev->base_addr;
u_long omr;
/* First, double check that the adapter is open */
if (irq2dev_map[dev->irq] != NULL) {
omr = inl(DE4X5_OMR);
if (num_addrs >= 0) {
SetMulticastFilter(dev, num_addrs, (char *)addrs, lp->setup_frame);
/* Tell the hardware that there's a new packet to be sent */
load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET |
SetMulticastFilter(dev, num_addrs, (char *)addrs);
if (lp->setup_f == HASH_PERF) {
load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET |
SETUP_FRAME_LEN, NULL);
} else {
load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
SETUP_FRAME_LEN, NULL);
}
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
omr &= ~OMR_PR;
omr |= OMR_PM;
outl(omr, DE4X5_OMR);
} else { /* set promiscuous mode */
omr |= OMR_PR;
omr &= ~OMR_PM;
outl(omr, DE4X5_OMR);
dev->trans_start = jiffies;
}
}
return;
}
/*
......@@ -1171,49 +1275,58 @@ set_multicast_list(struct device *dev, int num_addrs, void *addrs)
** from a list of ethernet multicast addresses.
** Little endian crc one liner from Matt Thomas, DEC.
*/
static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs, char *multicast_table)
static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs)
{
char j, bit, byte;
long *p = (long *) multicast_table;
int i;
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int i, j, bit, byte, iobase = dev->base_addr;
u_short hashcode;
u_long crc, poly = CRC_POLYNOMIAL_LE;
u_long crc, omr, poly = CRC_POLYNOMIAL_LE;
char *pa;
if (num_addrs == HASH_TABLE_LEN) {
for (i=0; i<(HASH_TABLE_LEN >> 4); i++) {
*p++ = 0x0000ffff;
}
} else {
/* Clear the multicast table except for the broadcast bit */
memset(multicast_table, 0, (HASH_TABLE_LEN >> 2));
*(multicast_table + (HASH_TABLE_LEN >> 3) - 3) = 0x80;
/* Now update the table */
for (i=0;i<num_addrs;i++) { /* for each address in the list */
if ((*addrs & 0x01) == 1) { /* multicast address? */
crc = 0xffffffff; /* init CRC for each address */
for (byte=0;byte<ETH_ALEN;byte++) { /* for each address byte */
omr = inl(DE4X5_OMR);
pa = build_setup_frame(dev, ALL); /* Build the basic frame */
if (lp->setup_f == HASH_PERF) {
if (num_addrs == HASH_TABLE_LEN) { /* Pass all multicasts */
omr |= OMR_PM;
} else {
omr &= ~OMR_PM;
/* Now update the MCA table */
for (i=0;i<num_addrs;i++) { /* for each address in the list */
if ((*addrs & 0x01) == 1) { /* multicast address? */
crc = 0xffffffff; /* init CRC for each address */
for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
/* process each address bit */
for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
}
}
}
hashcode = crc & ((1 << 9) - 1); /* hashcode is 9 LSb of CRC */
hashcode = crc & HASH_BITS; /* hashcode is 9 LSb of CRC */
byte = hashcode >> 3; /* bit[3-8] -> byte in filter */
bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */
byte = hashcode >> 3; /* bit[3-8] -> byte in filter */
bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */
byte <<= 1; /* calc offset into setup frame */
if (byte & 0x02) {
byte -= 1;
byte <<= 1; /* calc offset into setup frame */
if (byte & 0x02) {
byte -= 1;
}
lp->setup_frame[byte] |= bit;
} else { /* skip this address */
addrs += ETH_ALEN;
}
multicast_table[byte] |= bit;
} else { /* skip this address */
addrs += ETH_ALEN;
}
}
} else { /* Perfect filtering */
omr &= ~OMR_PM;
for (j=0; j<num_addrs; j++) {
for (i=0; i<ETH_ALEN; i++) {
*(pa + (i&1)) = *addrs++;
if (i & 0x01) pa += 4;
}
}
}
outl(omr, DE4X5_OMR);
return;
}
......@@ -1226,8 +1339,10 @@ static void eisa_probe(struct device *dev, short ioaddr)
{
int i, maxSlots;
int status;
u_short iobase;
u_short vendor, device, iobase;
struct bus_type *lp = &bus;
char name[DE4X5_STRLEN];
long cfid;
if (!ioaddr && autoprobed) return ; /* Been here before ! */
if ((ioaddr < 0x1000) && (ioaddr > 0)) return; /* PCI MODULE special */
......@@ -1244,17 +1359,30 @@ static void eisa_probe(struct device *dev, short ioaddr)
maxSlots = i + 1;
}
for (status = -ENODEV; i<maxSlots && dev!=NULL; i++, iobase+=EISA_SLOT_INC) {
if ((DevicePresent(EISA_APROM) == 0) || is_zynx) {
if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
if ((dev = alloc_device(dev, iobase)) != NULL) {
if ((status = de4x5_hw_init(dev, iobase)) == 0) {
num_de4x5s++;
}
for (status = -ENODEV; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
if (EISA_signature(name, EISA_ID)) {
cfid = inl(PCI_CFID);
device = (u_short)(cfid >> 16);
vendor = (u_short) cfid;
lp->bus = EISA;
lp->chipset = device;
if (DevicePresent(EISA_APROM) == 0) {
/* Write the PCI Configuration Registers */
outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
outl(0x00004000, PCI_CFLT);
outl((u_long)iobase, PCI_CBIO);
if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
if ((dev = alloc_device(dev, iobase)) != NULL) {
if ((status = de4x5_hw_init(dev, iobase)) == 0) {
num_de4x5s++;
}
num_eth++;
}
} else if (autoprobed) {
printk("%s: region already allocated at 0x%04x.\n", dev->name, iobase);
}
} else if (autoprobed) {
printk("%s: region already allocated at 0x%04x.\n", dev->name, iobase);
}
}
}
......@@ -1295,15 +1423,18 @@ static void pci_probe(struct device *dev, short ioaddr)
dev_last = PCI_LAST_DEV;
}
for (; dev_num < dev_last && dev != NULL; dev_num++) {
for (; (dev_num < dev_last) && (dev != NULL); dev_num++) {
pcibios_read_config_dword(pb, PCI_DEVICE, PCI_CLASS_REVISION, &class);
if (class != 0xffffffff) {
pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &device);
if ((vendor == DC21040_VID) && (device == DC21040_DID)) {
if (is_DC21040 || is_DC21041 || is_DC21140) {
/* Set the device number information */
lp->device = dev_num;
/* Set the chipset information */
lp->chipset = device;
/* Get the board I/O address */
pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase);
iobase &= CBIO_MASK;
......@@ -1317,7 +1448,7 @@ static void pci_probe(struct device *dev, short ioaddr)
pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
/* If there is a device and I/O region is open, initialise dev. */
if ((DevicePresent(DE4X5_APROM) == 0) || is_zynx) {
if ((DevicePresent(DE4X5_APROM) == 0) || is_not_dec) {
if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
if ((dev = alloc_device(dev, iobase)) != NULL) {
dev->irq = irq;
......@@ -1457,120 +1588,322 @@ static struct device *alloc_device(struct device *dev, int iobase)
static int autoconf_media(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int media, entry, iobase = dev->base_addr;
char frame[64];
u_long i, omr, sisr, linkBad;
/* u_long t_330ms = 920000;*/
u_long t_3s = 8000000;
int iobase = dev->base_addr;
/* Set up for TP port, with LEDs */
media = TP;
RESET_SIA;
outl(SICR_OE57 | SICR_SEL | SICR_SRL, DE4X5_SICR);
if (lp->chipset == DC21040) {
lp->media = (lp->autosense == AUTO ? TP : lp->autosense);
dc21040_autoconf(dev);
} else if (lp->chipset == DC21041) {
lp->media = (lp->autosense == AUTO ? TP_NW : lp->autosense);
dc21041_autoconf(dev);
} else if (lp->chipset == DC21140) {
/* Force 10Mb/s (_100Mb for 100Mb/s) */
lp->media = (lp->autosense == AUTO ? _10Mb : lp->autosense);
dc21140_autoconf(dev);
}
/* Test the TP port */
for (linkBad=1,i=0;i<t_3s && linkBad;i++) {
if (((sisr = inl(DE4X5_SISR)) & SISR_LKF) == 0) linkBad = 0;
if (sisr & SISR_NCR) break;
if (de4x5_debug >= 1 ) {
if (lp->chipset != DC21140) {
printk("%s: Media is %s\n",dev->name,
(lp->media == NC ? "unconnected!" :
(lp->media == TP ? "TP." :
(lp->media == ANS ? "TP/Nway." :
(lp->media == BNC ? "BNC." :
(lp->media == AUI ? "AUI." :
"BNC/AUI."
))))));
} else {
printk("%s: Mode is forced to %s\n",dev->name,
(lp->media == NC ? "link down.":
(lp->media == _100Mb ? "100Mb/s." :
(lp->media == _10Mb ? "10Mb/s." :
"\?\?\?"
))));
}
}
if (linkBad) {
/* Set up for BNC (Thinwire) port, with LEDs */
media = BNC;
RESET_SIA;
outl(SIGR_JCK | SIGR_HUJ, DE4X5_SIGR);
outl(STRR_CLD | STRR_CSQ | STRR_RSQ | STRR_DREN | STRR_ECEN, DE4X5_STRR);
outl(SICR_OE57| SICR_OE24 | SICR_OE13 | SICR_SEL |
SICR_AUI | SICR_SRL, DE4X5_SICR);
/* Wait 330ms */
if (lp->media) {
lp->lostMedia = 0;
inl(DE4X5_MFC); /* Zero the lost frames counter */
}
dce_ms_delay(10);
return (lp->media);
}
static void dc21040_autoconf(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int iobase = dev->base_addr;
u_long i, sisr = 0, linkBad;
u_long t_3s = 3000;
switch (lp->media) {
case TP:
reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
for (linkBad=1,i=0;(i<t_3s) && linkBad && !(sisr & SISR_NCR);i++) {
if (((sisr = inl(DE4X5_SISR)) & SISR_LKF) == 0) linkBad = 0;
dce_ms_delay(1);
}
if (linkBad && (lp->autosense == AUTO)) {
lp->media = BNC_AUI;
dc21040_autoconf(dev);
}
break;
case BNC:
case AUI:
case BNC_AUI:
reset_init_sia(dev, 0x8f09, 0x0705, 0x0006);
dce_ms_delay(330);
/* for (i=0; i<t_330ms; i++) {
sisr = inl(DE4X5_SISR);
linkBad = ping_media(dev);
if (linkBad && (lp->autosense == AUTO)) {
lp->media = NC;
dc21040_autoconf(dev);
}
break;
case NC:
reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
break;
}
return;
}
/*
** Autoconfigure the media when using the DC21041. AUI needs to be tested
** before BNC, because the BNC port will indicate activity if it's not
** terminated correctly. The only way to test for that is to place a loopback
** packet onto the network and watch for errors.
*/
/* Make up a dummy packet with CRC error */
create_packet(dev, frame, sizeof(frame));
static void dc21041_autoconf(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int iobase = dev->base_addr;
u_long sts, irqs, irq_mask, omr;
switch (lp->media) {
case TP_NW:
omr = inl(DE4X5_OMR); /* Set up full duplex for the autonegotiate */
outl(omr | OMR_FD, DE4X5_OMR);
irqs = STS_LNF | STS_LNP;
irq_mask = IMR_LFM | IMR_LPM;
sts = test_media(dev, irqs, irq_mask, 0xef01, 0xffff, 0x0008, 2400);
if (sts & STS_LNP) {
lp->media = ANS;
} else {
lp->media = AUI;
}
dc21041_autoconf(dev);
break;
/* Setup the packet descriptor */
entry = lp->tx_new; /* Remember the ring position */
load_packet(dev, frame, TD_LS | TD_FS | TD_AC | sizeof(frame), NULL);
case ANS:
irqs = STS_LNP;
irq_mask = IMR_LPM;
sts = test_ans(dev, irqs, irq_mask, 3000);
if (!(sts & STS_LNP) && (lp->autosense == AUTO)) {
lp->media = TP;
dc21041_autoconf(dev);
}
break;
/* Start the TX process */
omr = inl(DE4X5_OMR);
outl(omr|OMR_ST, DE4X5_OMR);
case TP:
omr = inl(DE4X5_OMR); /* Set up half duplex for TP */
outl(omr & ~OMR_FD, DE4X5_OMR);
irqs = STS_LNF | STS_LNP;
irq_mask = IMR_LFM | IMR_LPM;
sts = test_media(dev, irqs, irq_mask, 0xef01, 0xff3f, 0x0008, 2400);
if (!(sts & STS_LNP) && (lp->autosense == AUTO)) {
if (inl(DE4X5_SISR) & SISR_NRA) { /* Non selected port activity */
lp->media = AUI;
} else {
lp->media = BNC;
}
dc21041_autoconf(dev);
}
break;
/* Update pointers */
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
lp->tx_old = lp->tx_new;
case AUI:
omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */
outl(omr & ~OMR_FD, DE4X5_OMR);
irqs = 0;
irq_mask = 0;
sts = test_media(dev, irqs, irq_mask, 0xef09, 0xf7fd, 0x000e, 1000);
if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
lp->media = BNC;
dc21041_autoconf(dev);
}
break;
/*
** Poll for completion of frame (interrupts are disabled for now)...
** Allow upto 3 seconds to complete.
*/
for (linkBad=1,i=0;i<t_3s && linkBad;i++) {
if ((inl(DE4X5_SISR) & SISR_NCR) == 1) break;
if (lp->tx_ring[entry].status >= 0) linkBad=0;
case BNC:
omr = inl(DE4X5_OMR); /* Set up half duplex for BNC */
outl(omr & ~OMR_FD, DE4X5_OMR);
irqs = 0;
irq_mask = 0;
sts = test_media(dev, irqs, irq_mask, 0xef09, 0xf7fd, 0x0006, 1000);
if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
lp->media = NC;
} else { /* Ensure media connected */
if (ping_media(dev)) lp->media = NC;
}
outl(omr, DE4X5_OMR); /* Stop everything! */
if (linkBad || (lp->tx_ring[entry].status & TD_ES)) {
/* Set up for AUI (Thickwire) port, with LEDs */
media = AUI;
RESET_SIA;
outl(SIGR_JCK | SIGR_HUJ, DE4X5_SIGR);
outl(STRR_CLD | STRR_CSQ | STRR_RSQ | STRR_DREN | STRR_ECEN, DE4X5_STRR);
outl(SICR_OE57| SICR_SEL | SICR_AUI | SICR_SRL, DE4X5_SICR);
/* Wait 330ms */
dce_ms_delay(330);
break;
/* Setup the packet descriptor */
entry = lp->tx_new; /* Remember the ring position */
load_packet(dev, frame, TD_LS | TD_FS | TD_AC | sizeof(frame), NULL);
/* Start the TX process */
omr = inl(DE4X5_OMR);
outl(omr|OMR_ST, DE4X5_OMR);
case NC:
omr = inl(DE4X5_OMR); /* Set up full duplex for the autonegotiate */
outl(omr | OMR_FD, DE4X5_OMR);
reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */
break;
}
/* Update pointers */
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
lp->tx_old = lp->tx_new;
return;
}
/*
** Poll for completion of frame (interrupts are disabled for now)...
** Allow 3 seconds to complete.
*/
for (linkBad=1,i=0;i<t_3s && linkBad;i++) {
if ((inl(DE4X5_SISR) & SISR_NCR) == 1) break;
if (lp->tx_ring[entry].status >= 0) linkBad=0;
}
outl(omr, DE4X5_OMR); /* Stop everything! */
/*
** Reduced feature version (temporary I hope)
*/
static void dc21140_autoconf(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int iobase = dev->base_addr;
u_long omr;
if (linkBad || (lp->tx_ring[entry].status & TD_ES)) {
/* Reset the SIA */
outl(SICR_RESET, DE4X5_SICR); /* Reset SIA connectivity regs */
outl(STRR_RESET, DE4X5_STRR); /* Write reset values */
outl(SIGR_RESET, DE4X5_SIGR); /* Write reset values */
switch(lp->media) {
case _100Mb: /* Set 100Mb/s, MII Port with PCS Function and Scrambler */
omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);
outl(GEP_FDXD | GEP_MODE, DE4X5_GEP);
break;
media = NC;
}
}
case _10Mb: /* Set conventional 10Mb/s ENDEC interface */
omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
outl(omr | OMR_TTM, DE4X5_OMR);
outl(GEP_FDXD, DE4X5_GEP);
break;
}
if (de4x5_debug >= 1 ) {
printk("%s: Media is %s.\n",dev->name,
(media == NC ? "unconnected to this device" :
(media == TP ? "TP" :
(media == BNC ? "BNC" :
"AUI"))));
return;
}
static long test_media(struct device *dev, long irqs, long irq_mask, long csr13, long csr14, long csr15, long msec)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int iobase = dev->base_addr;
long sts, time, csr12;
reset_init_sia(dev, csr13, csr14, csr15);
/* Set link_fail_inhibit_timer */
load_ms_timer(dev, msec);
/* clear all pending interrupts */
sts = inl(DE4X5_STS);
outl(sts, DE4X5_STS);
/* clear csr12 NRA and SRA bits */
csr12 = inl(DE4X5_SISR);
outl(csr12, DE4X5_SISR);
/* Poll for timeout - timer interrupt doesn't work correctly */
do {
time = inl(DE4X5_GPT) & GPT_VAL;
sts = inl(DE4X5_STS);
} while ((time != 0) && !(sts & irqs));
sts = inl(DE4X5_STS);
return sts;
}
/*
** Send a packet onto the media and watch for send errors that indicate the
** media is bad or unconnected.
*/
static long ping_media(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int entry, iobase = dev->base_addr;
char frame[64];
long i, linkBad, omr;
u_long t_3s = 3000;
create_packet(dev, frame, sizeof(frame));
entry = lp->tx_new; /* Remember the ring position */
load_packet(dev, frame, TD_LS | TD_FS | sizeof(frame),NULL);
omr = inl(DE4X5_OMR);
outl(omr|OMR_ST, DE4X5_OMR);
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
lp->tx_old = lp->tx_new;
/* Poll for completion of frame (interrupts are disabled for now)... */
for (linkBad=1,i=0;(i<t_3s) && linkBad;i++) {
if ((inl(DE4X5_SISR) & SISR_NCR) == 1) break;
if (lp->tx_ring[entry].status >= 0) linkBad=0;
dce_ms_delay(1);
}
outl(omr, DE4X5_OMR);
if (media) lp->lostMedia = 0;
return ((linkBad || (lp->tx_ring[entry].status & TD_ES)) ? 1 : 0);
}
return media;
/*
** Check the Auto Negotiation State. Return OK when a link pass interrupt
** is received and the auto-negotiation status is NWAY OK.
*/
static int test_ans(struct device *dev, long irqs, long irq_mask, long msec)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int iobase = dev->base_addr;
long sts, ans;
outl(irq_mask, DE4X5_IMR);
/* Set timeout limit */
load_ms_timer(dev, msec);
/* clear all pending interrupts */
sts = inl(DE4X5_STS);
outl(sts, DE4X5_STS);
/* Poll for interrupts */
do {
ans = inl(DE4X5_SISR) & SISR_ANS;
sts = inl(DE4X5_STS);
} while (!(sts & irqs) && (ans ^ ANS_NWOK) != 0);
return ((sts & STS_LNP) && ((ans ^ ANS_NWOK) == 0) ? STS_LNP : 0);
}
/*
**
*/
static void reset_init_sia(struct device *dev, long sicr, long strr, long sigr)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int iobase = dev->base_addr;
RESET_SIA;
outl(sigr, DE4X5_SIGR);
outl(strr, DE4X5_STRR);
outl(sicr, DE4X5_SICR);
return;
}
/*
** Load the timer on the DC21041 and 21140. Max time is 13.42 secs.
*/
static void load_ms_timer(struct device *dev, u_long msec)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int iobase = dev->base_addr;
outl((long)(msec * 10000)/2048, DE4X5_GPT);
return;
}
/*
......@@ -1578,7 +1911,7 @@ static int autoconf_media(struct device *dev)
*/
static void create_packet(struct device *dev, char *frame, int len)
{
int i, j;
int i;
char *buf = frame;
for (i=0; i<ETH_ALEN; i++) { /* Use this source address */
......@@ -1587,58 +1920,25 @@ static void create_packet(struct device *dev, char *frame, int len)
for (i=0; i<ETH_ALEN; i++) { /* Use this destination address */
*buf++ = dev->dev_addr[i];
}
for (j=1; j>=0; j--) { /* Packet length (2 bytes) */
*buf++ = (char) ((len >> 8*j) & 0xff);
}
*buf++ = 0; /* Data */
for (i=len-4; i<len; i++) { /* CRC */
buf[i] = 0;
}
*buf++ = 0; /* Packet length (2 bytes) */
*buf++ = 1;
return;
}
/*
** Get the timer ticks from the PIT
*/
static u_short dce_get_ticks(void)
{
u_short ticks = 0;
/* Command 8254 to latch T0's count */
outb(TIMER_PORT, TIMER_LATCH);
/* Read the counter */
ticks = inb(TIMER_READ);
ticks |= (inb(TIMER_READ) << 8);
return ticks;
}
/*
** Known delay in microseconds
*/
static void dce_us_delay(u_long usec)
{
u_long i, start, now, quant=(DELAY_QUANT*1000)/TIMER_TICK+1;
for (i=0; i<usec/DELAY_QUANT; i++) {
start=dce_get_ticks();
for (now=start; (start-now)<quant;) {
now=dce_get_ticks();
if (now > start) { /* Wrapped counter counting down */
quant -= start;
start = (1 << TIMER_WIDTH);
}
}
}
udelay(usec);
return;
}
/*
** Known delay in milliseconds
** Known delay in milliseconds, in millisecond steps.
*/
static void dce_ms_delay(u_long msec)
{
......@@ -1655,18 +1955,19 @@ static void dce_ms_delay(u_long msec)
/*
** Look for a particular board name in the EISA configuration space
*/
static void EISA_signature(char *name, short iobase)
int EISA_signature(char *name, long eisa_id)
{
unsigned long i;
char *signatures[] = DE4X5_SIGNATURE;
char ManCode[8];
char ManCode[DE4X5_STRLEN];
union {
u_long ID;
u_char Id[4];
long ID;
char Id[4];
} Eisa;
int status = 0;
strcpy(name, "");
Eisa.ID = inl(iobase);
*name = '\0';
Eisa.ID = inl(eisa_id);
ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40);
ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40);
......@@ -1675,13 +1976,14 @@ static void EISA_signature(char *name, short iobase)
ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30);
ManCode[5]='\0';
for (i=0;*signatures[i] != '\0' && *name == '\0';i++) {
for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) {
if (strstr(ManCode, signatures[i]) != NULL) {
strcpy(name,ManCode);
status = 1;
}
}
return; /* return the device name string */
return status; /* return the device name string */
}
/*
......@@ -1715,26 +2017,34 @@ static int DevicePresent(short aprom_addr)
dev.llsig.b = ETH_PROM_SIG;
sigLength = sizeof(long) << 1;
for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
if (lp->bus == PCI) {
while ((tmp = inl(aprom_addr)) < 0);
data = (char)tmp;
} else {
data = inb(aprom_addr);
}
if (dev.Sig[j] == data) { /* track signature */
j++;
} else { /* lost signature; begin search again */
if (data == dev.Sig[0]) {
j=1;
if (lp->chipset == DC21040) {
for (i=0,j=0;(j<sigLength) && (i<PROBE_LENGTH+sigLength-1);i++) {
if (lp->bus == PCI) {
while ((tmp = inl(aprom_addr)) < 0);
data = (char)tmp;
} else {
j=0;
data = inb(aprom_addr);
}
if (dev.Sig[j] == data) { /* track signature */
j++;
} else { /* lost signature; begin search again */
if (data == dev.Sig[0]) {
j=1;
} else {
j=0;
}
}
}
}
if (j!=sigLength) {
status = -ENODEV; /* search failed */
if (j!=sigLength) {
status = -ENODEV; /* search failed */
}
} else { /* use new srom */
short *p = (short *)&lp->srom;
for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) {
*p++ = srom_rd(aprom_addr, i);
}
}
return status;
......@@ -1753,12 +2063,17 @@ static int aprom_crc(struct device *dev)
if (k > 0xffff) k-=0xffff;
if (lp->bus == PCI) {
while ((tmp = inl(DE4X5_APROM)) < 0);
k += (u_char) tmp;
dev->dev_addr[i++] = (u_char) tmp;
while ((tmp = inl(DE4X5_APROM)) < 0);
k += (u_short) (tmp << 8);
dev->dev_addr[i++] = (u_char) tmp;
if (lp->chipset == DC21040) {
while ((tmp = inl(DE4X5_APROM)) < 0);
k += (u_char) tmp;
dev->dev_addr[i++] = (u_char) tmp;
while ((tmp = inl(DE4X5_APROM)) < 0);
k += (u_short) (tmp << 8);
dev->dev_addr[i++] = (u_char) tmp;
} else {
dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++;
dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++;
}
} else {
k += (u_char) (tmp = inb(EISA_APROM));
dev->dev_addr[i++] = (u_char) tmp;
......@@ -1771,20 +2086,157 @@ static int aprom_crc(struct device *dev)
if (k == 0xffff) k=0;
if (lp->bus == PCI) {
while ((tmp = inl(DE4X5_APROM)) < 0);
chksum = (u_char) tmp;
while ((tmp = inl(DE4X5_APROM)) < 0);
chksum |= (u_short) (tmp << 8);
if (lp->chipset == DC21040) {
while ((tmp = inl(DE4X5_APROM)) < 0);
chksum = (u_char) tmp;
while ((tmp = inl(DE4X5_APROM)) < 0);
chksum |= (u_short) (tmp << 8);
if (k != chksum) status = -1;
}
} else {
chksum = (u_char) inb(EISA_APROM);
chksum |= (u_short) (inb(EISA_APROM) << 8);
if (k != chksum) status = -1;
}
if (k != chksum) status = -1;
return status;
}
/*
** SROM Read
*/
static short srom_rd(u_short addr, u_char offset)
{
sendto_srom(SROM_RD | SROM_SR, addr);
srom_latch(SROM_RD | SROM_SR | DT_CS, addr);
srom_command(SROM_RD | SROM_SR | DT_IN | DT_CS, addr);
srom_address(SROM_RD | SROM_SR | DT_CS, addr, offset);
return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
}
static void srom_latch(u_long command, u_short addr)
{
sendto_srom(command, addr);
sendto_srom(command | DT_CLK, addr);
sendto_srom(command, addr);
return;
}
static void srom_command(u_long command, u_short addr)
{
srom_latch(command, addr);
srom_latch(command, addr);
srom_latch((command & 0x0000ff00) | DT_CS, addr);
return;
}
static void srom_address(u_long command, u_short addr, u_char offset)
{
long i;
char a;
a = (char)(offset << 2);
for (i=0; i<6; i++, a <<= 1) {
srom_latch(command | ((a < 0) ? DT_IN : 0), addr);
}
dce_us_delay(1);
i = (getfrom_srom(addr) >> 3) & 0x01;
if (i != 0) {
printk("Bad SROM address phase.....\n");
}
return;
}
static short srom_data(u_long command, u_short addr)
{
int i;
short word = 0;
long tmp;
for (i=0; i<16; i++) {
sendto_srom(command | DT_CLK, addr);
tmp = getfrom_srom(addr);
sendto_srom(command, addr);
word = (word << 1) | ((tmp >> 3) & 0x01);
}
sendto_srom(command & 0x0000ff00, addr);
return word;
}
/*
static void srom_busy(u_long command, u_short addr)
{
sendto_srom((command & 0x0000ff00) | DT_CS, addr);
while (!((getfrom_srom(addr) >> 3) & 0x01)) {
dce_ms_delay(1);
}
sendto_srom(command & 0x0000ff00, addr);
return;
}
*/
static void sendto_srom(u_long command, u_short addr)
{
outl(command, addr);
dce_us_delay(1);
return;
}
static long getfrom_srom(u_short addr)
{
long tmp;
tmp = inl(addr);
dce_us_delay(1);
return tmp;
}
static char *build_setup_frame(struct device *dev, int mode)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int i;
char *pa = lp->setup_frame;
/* Initialise the setup frame */
if (mode == ALL) {
memset(lp->setup_frame, 0, SETUP_FRAME_LEN);
}
if (lp->setup_f == HASH_PERF) {
for (pa=lp->setup_frame+IMPERF_PA_OFFSET, i=0; i<ETH_ALEN; i++) {
*(pa + i) = dev->dev_addr[i]; /* Host address */
if (i & 0x01) pa += 2;
}
*(lp->setup_frame + (HASH_TABLE_LEN >> 3) - 3) = 0x80; /* B'cast address */
} else {
for (i=0; i<ETH_ALEN; i++) { /* Host address */
*(pa + (i&1)) = dev->dev_addr[i];
if (i & 0x01) pa += 4;
}
for (i=0; i<ETH_ALEN; i++) { /* Broadcast address */
*(pa + (i&1)) = (char) 0xff;
if (i & 0x01) pa += 4;
}
}
return pa; /* Points to the next entry */
}
/*
** Perform IOCTL call functions here. Some are privileged operations and the
** effective uid is checked in those cases.
......@@ -1812,29 +2264,20 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
break;
case DE4X5_SET_HWADDR: /* Set the hardware address */
if (suser()) {
int offset;
char *pa;
u_long omr;
memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
for (i=0; i<ETH_ALEN; i++) {
dev->dev_addr[i] = tmp.addr[i];
}
omr = inl(DE4X5_OMR);
if (omr & OMR_HP) {
offset = IMPERF_PA_OFFSET;
} else {
offset = PERF_PA_OFFSET;
}
/* Insert the physical address */
for (pa=lp->setup_frame+offset, i=0; i<ETH_ALEN; i++) {
*(pa + i) = dev->dev_addr[i];
if (i & 0x01) pa += 2;
}
build_setup_frame(dev, PHYS_ADDR_ONLY);
/* Set up the descriptor and give ownership to the card */
while (set_bit(0, (void *)&dev->tbusy) != 0); /* Wait for lock to free */
load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET |
if (lp->setup_f == HASH_PERF) {
load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET |
SETUP_FRAME_LEN, NULL);
} else {
load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
SETUP_FRAME_LEN, NULL);
}
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
dev->tbusy = 0; /* Unlock the TX ring */
......@@ -1848,7 +2291,6 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
if (suser()) {
omr = inl(DE4X5_OMR);
omr |= OMR_PR;
omr &= ~OMR_PM;
outl(omr, DE4X5_OMR);
} else {
status = -EPERM;
......@@ -1893,11 +2335,10 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
break;
case DE4X5_MCA_EN: /* Enable multicast addressing */
case DE4X5_MCA_EN: /* Enable pass all multicast addressing */
if (suser()) {
omr = inl(DE4X5_OMR);
omr |= OMR_PM;
omr &= ~OMR_PR;
outl(omr, DE4X5_OMR);
} else {
status = -EPERM;
......@@ -2049,9 +2490,9 @@ cleanup_module(void)
DE4X5_PCI_TOTAL_SIZE :
DE4X5_EISA_TOTAL_SIZE));
if (lp) {
kfree_s(lp->rx_ring[0].buf, RX_BUFF_SZ * NUM_RX_DESC + LWPAD);
kfree_s(lp->rx_ring[0].buf, RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
}
kfree_s(thisDE4X5.priv, sizeof(struct de4x5_private) + LWPAD);
kfree_s(thisDE4X5.priv, sizeof(struct de4x5_private) + ALIGN);
thisDE4X5.priv = NULL;
unregister_netdev(&thisDE4X5);
......
......@@ -23,8 +23,12 @@
#define DE4X5_IMR iobase+(0x038 << lp->bus) /* Interrupt Mask Register */
#define DE4X5_MFC iobase+(0x040 << lp->bus) /* Missed Frame Counter */
#define DE4X5_APROM iobase+(0x048 << lp->bus) /* Ethernet Address PROM */
#define DE4X5_BROM iobase+(0x048 << lp->bus) /* Boot ROM Register */
#define DE4X5_SROM iobase+(0x048 << lp->bus) /* Serial ROM Register */
#define DE4X5_DDR iobase+(0x050 << lp->bus) /* Data Diagnostic Register */
#define DE4X5_FDR iobase+(0x058 << lp->bus) /* Full Duplex Register */
#define DE4X5_GPT iobase+(0x058 << lp->bus) /* General Purpose Timer Reg.*/
#define DE4X5_GEP iobase+(0x060 << lp->bus) /* General Purpose Register */
#define DE4X5_SISR iobase+(0x060 << lp->bus) /* SIA Status Register */
#define DE4X5_SICR iobase+(0x068 << lp->bus) /* SIA Connectivity Register */
#define DE4X5_STRR iobase+(0x070 << lp->bus) /* SIA TX/RX Register */
......@@ -54,7 +58,9 @@
#define PCI_CFLT iobase+0x001c /* PCI Latency Timer Register */
#define PCI_CBIO iobase+0x0028 /* PCI Base I/O Register */
#define PCI_CBMA iobase+0x002c /* PCI Base Memory Address Register */
#define PCI_CFIT iobase+0x0038 /* PCI Configuration Interrupt Register */
#define PCI_CBER iobase+0x0030 /* PCI Expansion ROM Base Address Reg. */
#define PCI_CFIT iobase+0x003c /* PCI Configuration Interrupt Register */
#define PCI_CFDA iobase+0x0040 /* PCI Driver Area Register */
/*
** EISA Configuration Register 0 bit definitions
......@@ -94,6 +100,21 @@
#define CFID_VID 0x00ff /* Vendor ID */
#define DC21040_DID 0x0002 /* Unique Device ID # */
#define DC21040_VID 0x1011 /* DC21040 Manufacturer */
#define DC21041_DID 0x0014 /* Unique Device ID # */
#define DC21041_VID 0x1011 /* DC21041 Manufacturer */
#define DC21140_DID 0x0009 /* Unique Device ID # */
#define DC21140_VID 0x1011 /* DC21140 Manufacturer */
/*
** Chipset defines
*/
#define DC21040 DC21040_DID
#define DC21041 DC21041_DID
#define DC21140 DC21140_DID
#define is_DC21040 ((vendor == DC21040_VID) && (device == DC21040_DID))
#define is_DC21041 ((vendor == DC21041_VID) && (device == DC21041_DID))
#define is_DC21140 ((vendor == DC21140_VID) && (device == DC21140_DID))
/*
** PCI Configuration Command/Status Register (PCI_CFCS)
......@@ -135,10 +156,22 @@
#define CBIO_MASK 0x0000ff80 /* Base I/O Address Mask */
#define CBIO_IOSI 0x00000001 /* I/O Space Indicator (RO, value is 1) */
/*
** PCI Configuration Expansion ROM Base Address Register (PCI_CBER)
*/
#define CBER_MASK 0xfffffc00 /* Expansion ROM Base Address Mask */
#define CBER_ROME 0x00000001 /* ROM Enable */
/*
** PCI Configuration Driver Area Register (PCI_CFDA)
*/
#define CFDA_PSM 0x80000000 /* Power Saving Mode */
/*
** DC21040 Bus Mode Register (DE4X5_BMR)
*/
#define BMR_TAP 0x00060000 /* Transmit Automatic Polling */
#define BMR_DBO 0x00100000 /* Descriptor Byte Ordering (Endian) */
#define BMR_TAP 0x000e0000 /* Transmit Automatic Polling */
#define BMR_DAS 0x00010000 /* Diagnostic Address Space */
#define BMR_CAL 0x0000c000 /* Cache Alignment */
#define BMR_PBL 0x00003f00 /* Programmable Burst Length */
......@@ -151,6 +184,10 @@
#define TAP_200US 0x00020000 /* TX automatic polling every 200us */
#define TAP_800US 0x00040000 /* TX automatic polling every 800us */
#define TAP_1_6MS 0x00060000 /* TX automatic polling every 1.6ms */
#define TAP_12_8US 0x00080000 /* TX automatic polling every 12.8us */
#define TAP_25_6US 0x000a0000 /* TX automatic polling every 25.6us */
#define TAP_51_2US 0x000c0000 /* TX automatic polling every 51.2us */
#define TAP_102_4US 0x000e0000 /* TX automatic polling every 102.4us */
#define CAL_NOUSE 0x00000000 /* Not used */
#define CAL_8LONG 0x00004000 /* 8-longword alignment */
......@@ -165,6 +202,7 @@
#define PBL_16 0x00001000 /* 16 longwords DMA burst length */
#define PBL_32 0x00002000 /* 32 longwords DMA burst length */
#define DSL_0 0x00000000 /* 0 longword / descriptor */
#define DSL_1 0x00000004 /* 1 longword / descriptor */
#define DSL_2 0x00000008 /* 2 longwords / descriptor */
#define DSL_4 0x00000010 /* 4 longwords / descriptor */
......@@ -195,20 +233,23 @@
/*
** DC21040 Status Register (DE4X5_STS)
*/
#define STS_EB 0x03800000 /* Error Bits */
#define STS_BE 0x03800000 /* Bus Error Bits */
#define STS_TS 0x00700000 /* Transmit Process State */
#define STS_RS 0x000e0000 /* Receive Process State */
#define STS_NIS 0x00010000 /* Normal Interrupt Summary */
#define STS_AIS 0x00008000 /* Abnormal Interrupt Summary */
#define STS_ER 0x00004000 /* Early Receive */
#define STS_SE 0x00002000 /* System Error */
#define STS_LNF 0x00001000 /* Link Fail */
#define STS_FD 0x00000800 /* Full-Duplex Short Frame Received */
#define STS_TM 0x00000800 /* Timer Expired (DC21041) */
#define STS_AT 0x00000400 /* AUI/TP Pin */
#define STS_RWT 0x00000200 /* Receive Watchdog Time-Out */
#define STS_RPS 0x00000100 /* Receive Process Stopped */
#define STS_RU 0x00000080 /* Receive Buffer Unavailable */
#define STS_RI 0x00000040 /* Receive Interrupt */
#define STS_UNF 0x00000020 /* Transmit Underflow */
#define STS_LNP 0x00000010 /* Link Pass */
#define STS_TJT 0x00000008 /* Transmit Jabber Time-Out */
#define STS_TU 0x00000004 /* Transmit Buffer Unavailable */
#define STS_TPS 0x00000002 /* Transmit Process Stopped */
......@@ -243,6 +284,13 @@
/*
** DC21040 Operation Mode Register (DE4X5_OMR)
*/
#define OMR_SDP 0x02000000 /* SD Polarity - MUST BE ASSERTED */
#define OMR_SCR 0x01000000 /* Scrambler Mode */
#define OMR_PCS 0x00800000 /* PCS Function */
#define OMR_TTM 0x00400000 /* Transmit Threshold Mode */
#define OMR_SF 0x00200000 /* Store and Forward */
#define OMR_HBD 0x00080000 /* HeartBeat Disable */
#define OMR_PS 0x00040000 /* Port Select */
#define OMR_CA 0x00020000 /* Capture Effect Enable */
#define OMR_BP 0x00010000 /* Back Pressure */
#define OMR_TR 0x0000c000 /* Threshold Control Bits */
......@@ -270,15 +318,18 @@
*/
#define IMR_NIM 0x00010000 /* Normal Interrupt Summary Mask */
#define IMR_AIM 0x00008000 /* Abnormal Interrupt Summary Mask */
#define IMR_ERM 0x00004000 /* Early Receive Mask */
#define IMR_SEM 0x00002000 /* System Error Mask */
#define IMR_LFM 0x00001000 /* Link Fail Mask */
#define IMR_FDM 0x00000800 /* Full-Duplex Mask */
#define IMR_FDM 0x00000800 /* Full-Duplex (Short Frame) Mask */
#define IMR_TMM 0x00000800 /* Timer Expired Mask (DC21041) */
#define IMR_ATM 0x00000400 /* AUI/TP Switch Mask */
#define IMR_RWM 0x00000200 /* Receive Watchdog Time-Out Mask */
#define IMR_RSM 0x00000100 /* Receive Stopped Mask */
#define IMR_RUM 0x00000080 /* Receive Buffer Unavailable Mask */
#define IMR_RIM 0x00000040 /* Receive Interrupt Mask */
#define IMR_UNM 0x00000020 /* Underflow Interrupt Mask */
#define IMR_LPM 0x00000010 /* Link Pass */
#define IMR_TJM 0x00000008 /* Transmit Time-Out Jabber Mask */
#define IMR_TUM 0x00000004 /* Transmit Buffer Unavailable Mask */
#define IMR_TSM 0x00000002 /* Transmission Stopped Mask */
......@@ -296,28 +347,90 @@
#define APROM_DN 0x80000000 /* Data Not Valid */
#define APROM_DT 0x000000ff /* Address Byte */
/*
** DC21041 Boot/Ethernet Address ROM (DE4X5_BROM)
*/
#define BROM_MODE 0x00008000 /* MODE_1: 0, MODE_0: 1 (read only) */
#define BROM_RD 0x00004000 /* Read from Boot ROM */
#define BROM_WR 0x00002000 /* Write to Boot ROM */
#define BROM_BR 0x00001000 /* Select Boot ROM when set */
#define BROM_SR 0x00000800 /* Select Serial ROM when set */
#define BROM_REG 0x00000400 /* External Register Select */
#define BROM_DT 0x000000ff /* Data Byte */
/*
** DC21041 Serial/Ethernet Address ROM (DE4X5_SROM)
*/
#define SROM_MODE 0x00008000 /* MODE_1: 0, MODE_0: 1 (read only) */
#define SROM_RD 0x00004000 /* Read from Boot ROM */
#define SROM_WR 0x00002000 /* Write to Boot ROM */
#define SROM_BR 0x00001000 /* Select Boot ROM when set */
#define SROM_SR 0x00000800 /* Select Serial ROM when set */
#define SROM_REG 0x00000400 /* External Register Select */
#define SROM_DT 0x000000ff /* Data Byte */
#define DT_OUT 0x00000008 /* Serial Data Out */
#define DT_IN 0x00000004 /* Serial Data In */
#define DT_CLK 0x00000002 /* Serial ROM Clock */
#define DT_CS 0x00000001 /* Serial ROM Chip Select */
/*
** DC21040 Full Duplex Register (DE4X5_FDR)
*/
#define FDR_FDACV 0x0000ffff /* Full Duplex Auto Configuration Value */
#define FDR_FDACV 0x0000ffff /* Full Duplex Auto Configuration Value */
/*
** DC21040 SIA Status Register (DE4X5_SISR)
** DC21041 General Purpose Timer Register (DE4X5_GPT)
*/
#define GPT_CON 0x00010000 /* One shot: 0, Continuous: 1 */
#define GPT_VAL 0x0000ffff /* Timer Value */
/*
** DC21140 General Purpose Register (DE4X5_GEP) (hardware dependent bits)
*/
#define SISR_DAO 0x00000080 /* PLL All One */
#define SISR_DAZ 0x00000040 /* PLL All Zero */
#define SISR_DSP 0x00000020 /* PLL Self-Test Pass */
#define SISR_DSD 0x00000010 /* PLL Self-Test Done */
#define SISR_APS 0x00000008 /* Auto Polarity State */
#define SISR_LKF 0x00000004 /* Link Fail Status */
#define SISR_NCR 0x00000002 /* Network Connection Error */
#define SISR_PAUI 0x00000001 /* AUI_TP Indication */
/* Valid ONLY for DE500 hardware */
#define GEP_LNP 0x00000080 /* Link Pass (input) */
#define GEP_SLNK 0x00000040 /* SYM LINK (input) */
#define GEP_SDET 0x00000020 /* Signal Detect (input) */
#define GEP_FDXD 0x00000008 /* Full Duplex Disable (output) */
#define GEP_PHYL 0x00000004 /* PHY Loopback (output) */
#define GEP_FLED 0x00000002 /* Force Activity LED on (output) */
#define GEP_MODE 0x00000001 /* 0: 10Mb/s, 1: 100Mb/s */
#define GEP_INIT 0x0000010f /* Setup inputs (0) and outputs (1) */
#define SIA_RESET 0x00000000 /* SIA Reset */
/*
** DC21040 SIA Status Register (DE4X5_SISR)
*/
#define SISR_LPC 0xffff0000 /* Link Partner's Code Word */
#define SISR_LPN 0x00008000 /* Link Partner Negotiable */
#define SISR_ANS 0x00007000 /* Auto Negotiation Arbitration State */
#define SISR_NSN 0x00000800 /* Non Stable NLPs Detected */
#define SISR_ANR_FDS 0x00000400 /* Auto Negotiate Restart/Full Duplex Sel.*/
#define SISR_NRA 0x00000200 /* Non Selected Port Receive Activity */
#define SISR_SRA 0x00000100 /* Selected Port Receive Activity */
#define SISR_DAO 0x00000080 /* PLL All One */
#define SISR_DAZ 0x00000040 /* PLL All Zero */
#define SISR_DSP 0x00000020 /* PLL Self-Test Pass */
#define SISR_DSD 0x00000010 /* PLL Self-Test Done */
#define SISR_APS 0x00000008 /* Auto Polarity State */
#define SISR_LKF 0x00000004 /* Link Fail Status */
#define SISR_NCR 0x00000002 /* Network Connection Error */
#define SISR_PAUI 0x00000001 /* AUI_TP Indication */
#define SIA_RESET 0x00000000 /* SIA Reset */
#define ANS_NDIS 0x00000000 /* Nway disable */
#define ANS_TDIS 0x00001000 /* Transmit Disable */
#define ANS_ADET 0x00002000 /* Ability Detect */
#define ANS_ACK 0x00003000 /* Acknowledge */
#define ANS_CACK 0x00004000 /* Complete Acknowledge */
#define ANS_NWOK 0x00005000 /* Nway OK - FLP Link Good */
#define ANS_LCHK 0x00006000 /* Link Check */
/*
** DC21040 SIA Connectivity Register (DE4X5_SICR)
*/
#define SICR_SDM 0xffff0000 /* SIA Diagnostics Mode */
#define SICR_OE57 0x00008000 /* Output Enable 5 6 7 */
#define SICR_OE24 0x00004000 /* Output Enable 2 4 */
#define SICR_OE13 0x00002000 /* Output Enable 1 3 */
......@@ -343,6 +456,7 @@
/*
** DC21040 SIA Transmit and Receive Register (DE4X5_STRR)
*/
#define STRR_TAS 0x00008000 /* 10Base-T/AUI Autosensing Enable */
#define STRR_SPP 0x00004000 /* Set Polarity Plus */
#define STRR_APE 0x00002000 /* Auto Polarity Enable */
#define STRR_LTE 0x00001000 /* Link Test Enable */
......@@ -350,6 +464,8 @@
#define STRR_CLD 0x00000400 /* Collision Detect Enable */
#define STRR_CSQ 0x00000200 /* Collision Squelch Enable */
#define STRR_RSQ 0x00000100 /* Receive Squelch Enable */
#define STRR_ANE 0x00000080 /* Auto Negotiate Enable */
#define STRR_HDE 0x00000040 /* Half Duplex Enable */
#define STRR_CPEN 0x00000030 /* Compensation Enable */
#define STRR_LSE 0x00000008 /* Link Pulse Send Enable */
#define STRR_DREN 0x00000004 /* Driver Enable */
......@@ -360,13 +476,19 @@
/*
** DC21040 SIA General Register (DE4X5_SIGR)
*/
#define SIGR_LV2 0x00008000 /* General Purpose LED2 value */
#define SIGR_LE2 0x00004000 /* General Purpose LED2 enable */
#define SIGR_FRL 0x00002000 /* Force Receiver Low */
#define SIGR_DPST 0x00001000 /* PLL Self Test Start */
#define SIGR_LSD 0x00000800 /* LED Stretch Disable */
#define SIGR_FLF 0x00000400 /* Force Link Fail */
#define SIGR_FUSQ 0x00000200 /* Force Unsquelch */
#define SIGR_TSCK 0x00000100 /* Test Clock */
#define SIGR_LV1 0x00000080 /* General Purpose LED1 value */
#define SIGR_LE1 0x00000040 /* General Purpose LED1 enable */
#define SIGR_RWR 0x00000020 /* Receive Watchdog Release */
#define SIGR_RWD 0x00000010 /* Receive Watchdog Disable */
#define SIGR_ABM 0x00000008 /* BNC: 0, AUI:1 */
#define SIGR_JCK 0x00000004 /* Jabber Clock */
#define SIGR_HUJ 0x00000002 /* Host Unjab */
#define SIGR_JBD 0x00000001 /* Jabber Disable */
......@@ -431,27 +553,64 @@
#define INVERSE_F TD_FT1
#define HASH_O_F TD_FT1| TD_F0
/*
** Media / mode state machine definitions
*/
#define NC 0x0000 /* No Connection */
#define TP 0x0001 /* 10Base-T */
#define TP_NW 0x0002 /* 10Base-T with Nway */
#define BNC 0x0004 /* Thinwire */
#define AUI 0x0008 /* Thickwire */
#define BNC_AUI 0x0010 /* BNC/AUI on DC21040 indistinguishable */
#define ANS 0x0020 /* Intermediate AutoNegotiation State */
#define _10Mb 0x0040 /* 10Mb/s Ethernet */
#define _100Mb 0x0080 /* 100Mb/s Ethernet */
#define SYM_WAIT 0x0100 /* Wait for SYM_LINK */
#define INIT 0x0200 /* Initial state */
#define AUTO 0x4000 /* Auto sense the media or speed */
/*
** Miscellaneous
*/
#define PCI 0
#define EISA 1
#define NC 0 /* No Connection */
#define TP 1 /* 10Base-T */
#define BNC 2 /* Thinwire */
#define AUI 3 /* Thickwire */
#define HASH_TABLE_LEN 512 /* Bits */
#define HASH_BITS 0x01ff /* 9 LS bits */
#define SETUP_FRAME_LEN 192 /* Bytes */
#define PERF_PA_OFFSET 180 /* Bytes */
#define IMPERF_PA_OFFSET 156 /* Bytes */
#define POLL_DEMAND 1
#define POLL_DEMAND 1
#define LOST_MEDIA_THRESHOLD 3
#define MASK_INTERRUPTS 1
#define UNMASK_INTERRUPTS 0
#define DE4X5_STRLEN 8
/*
** Address Filtering Modes
*/
#define PERFECT 0 /* 16 perfect physical addresses */
#define HASH_PERF 1 /* 1 perfect, 512 multicast addresses */
#define PERFECT_REJ 2 /* Reject 16 perfect physical addresses */
#define ALL_HASH 3 /* Hashes all physical & multicast addrs */
#define ALL 0 /* Clear out all the setup frame */
#define PHYS_ADDR_ONLY 1 /* Update the physical address only */
/*
** Booleans
*/
#define NO 0
#define FALSE 0
#define MASK_INTERRUPTS 1
#define UNMASK_INTERRUPTS 0
#define YES !0
#define TRUE !0
/*
** Include the IOCTL stuff
......
......@@ -608,7 +608,7 @@ lance_open(struct device *dev)
outw(((int)&lp->init_block) >> 16, ioaddr+LANCE_DATA);
outw(0x0004, ioaddr+LANCE_ADDR);
outw(0x0d15, ioaddr+LANCE_DATA);
outw(0x0915, ioaddr+LANCE_DATA);
outw(0x0000, ioaddr+LANCE_ADDR);
outw(0x0001, ioaddr+LANCE_DATA);
......
......@@ -50,7 +50,7 @@ static char *version =
/* Do we implement the read before write bugfix ? */
/* #define CONFIG_NE_RW_BUGFIX */
/* ---- No user-servicable parts below ---- */
/* ---- No user-serviceable parts below ---- */
extern struct device *init_etherdev(struct device *dev, int sizeof_private,
unsigned long *mem_startp);
......@@ -86,7 +86,7 @@ bad_clone_list[] = {
#define NESM_START_PG 0x40 /* First page of TX buffer */
#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
#define NE_RDC_TIMEOUT 0x03 /* Max wait in jiffies for Tx RDC */
#define NE_RDC_TIMEOUT 0x02 /* Max wait in jiffies for Tx RDC */
int ne_probe(struct device *dev);
static int ne_probe1(struct device *dev, int ioaddr);
......@@ -462,7 +462,6 @@ ne_block_output(struct device *dev, int count,
SLOW_DOWN_IO;
#endif /* rw_bugfix */
dma_start = jiffies;
outb_p(ENISR_RDC, nic_base + EN0_ISR);
/* Now the normal output. */
......@@ -478,6 +477,8 @@ ne_block_output(struct device *dev, int count,
outsb(NE_BASE + NE_DATAPORT, buf, count);
}
dma_start = jiffies;
#ifdef CONFIG_NE_SANITY
/* This was for the ALPHA version only, but enough people have
been encountering problems so it is still here. */
......
......@@ -31,6 +31,7 @@
/* #define NET02D -* */
#define NEW_TTY_DRIVERS /* */
#define OPTIMIZE_FLAG_TIME ((HZ * 3)/2) /* */
#define CHECK_CHARACTERS
#ifdef MODULE
#include <linux/module.h>
......@@ -469,8 +470,8 @@ ppp_release(struct ppp *ppp)
#endif
if (ppp->dev) {
ppp->dev->flags &= ~IFF_UP; /* down the device */
ppp->dev->flags |= IFF_POINTOPOINT;
dev_close (ppp->dev);
ppp->dev->flags = 0;
}
kfree (ppp->xbuff);
......@@ -953,14 +954,14 @@ static void ppp_receive_buf(struct tty_struct *tty, unsigned char *cp,
#ifdef CHECK_CHARACTERS
if (c & 0x80)
sc->sc_flags |= SC_RCV_B7_1;
ppp->flags |= SC_RCV_B7_1;
else
sc->sc_flags |= SC_RCV_B7_0;
ppp->flags |= SC_RCV_B7_0;
if (paritytab[c >> 5] & (1 << (c & 0x1F)))
sc->sc_flags |= SC_RCV_ODDP;
ppp->flags |= SC_RCV_ODDP;
else
sc->sc_flags |= SC_RCV_EVNP;
ppp->flags |= SC_RCV_EVNP;
#endif
switch (c) {
......@@ -1005,6 +1006,7 @@ ppp_doframe(struct ppp *ppp)
if (ppp->toss) {
PRINTKN (1, (KERN_WARNING "ppp_toss: tossing frame, reason = %d\n",
ppp->toss));
slhc_toss (ppp->slcomp);
ppp->stats.rerrors++;
return;
}
......@@ -1018,6 +1020,7 @@ ppp_doframe(struct ppp *ppp)
if (count < 4) {
PRINTKN (1,(KERN_WARNING "ppp: got runt ppp frame, %d chars\n", count));
slhc_toss (ppp->slcomp);
ppp->stats.runts++;
return;
}
......@@ -1025,6 +1028,7 @@ ppp_doframe(struct ppp *ppp)
/* check PPP error detection field */
if (!ppp_check_fcs(ppp)) {
PRINTKN (1,(KERN_WARNING "ppp: frame with bad fcs\n"));
slhc_toss (ppp->slcomp);
ppp->stats.rerrors++;
return;
}
......@@ -1067,6 +1071,7 @@ ppp_doframe(struct ppp *ppp)
/* couldn't cope. */
PRINTKN (1,(KERN_WARNING
"ppp: dropping packet on the floor: nobody could take it.\n"));
slhc_toss (ppp->slcomp);
ppp->stats.tossed++;
}
......@@ -1109,6 +1114,7 @@ ppp_do_ip (struct ppp *ppp, unsigned short proto, unsigned char *c,
PRINTKN (1,(KERN_NOTICE
"ppp: no space to decompress VJ compressed TCP header.\n"));
ppp->stats.roverrun++;
slhc_toss (ppp->slcomp);
return 1;
}
......@@ -1116,6 +1122,7 @@ ppp_do_ip (struct ppp *ppp, unsigned short proto, unsigned char *c,
if (count <= 0) {
ppp->stats.rerrors++;
PRINTKN (1,(KERN_NOTICE "ppp: error in VJ decompression\n"));
slhc_toss (ppp->slcomp);
return 1;
}
ppp->stats.rcomp++;
......@@ -1126,6 +1133,7 @@ ppp_do_ip (struct ppp *ppp, unsigned short proto, unsigned char *c,
if (slhc_remember(ppp->slcomp, c, count) <= 0) {
ppp->stats.rerrors++;
PRINTKN (1,(KERN_NOTICE "ppp: error in VJ memorizing\n"));
slhc_toss (ppp->slcomp);
return 1;
}
ppp->stats.runcomp++;
......@@ -1709,7 +1717,12 @@ ppp_xmit(struct sk_buff *skb, struct device *dev)
PRINTKN(4,(KERN_DEBUG "ppp_xmit [%s]: skb %lX busy %d\n", dev->name,
(unsigned long int) skb, ppp->sending));
CHECK_PPP(0);
/* avoid race conditions when the link fails */
if (!ppp->inuse) {
dev_kfree_skb(skb, FREE_WRITE);
dev_close (dev);
return 0;
}
if (tty == NULL) {
PRINTKN(1,(KERN_ERR "ppp_xmit: %s not connected to a TTY!\n", dev->name));
......@@ -1726,7 +1739,7 @@ ppp_xmit(struct sk_buff *skb, struct device *dev)
/* get length from IP header as per Alan Cox bugfix for slip.c */
if (len < sizeof(struct iphdr)) {
PRINTKN(0,(KERN_ERR "ppp_xmit: given runt packet, ignoring\n"));
return 1;
goto done;
}
len = ntohs( ((struct iphdr *)(skb->data)) -> tot_len );
......@@ -1750,8 +1763,8 @@ ppp_xmit(struct sk_buff *skb, struct device *dev)
/* try to compress, if VJ compression mode is on */
if (ppp->flags & SC_COMP_TCP) {
/* NOTE: last 0 argument says never to compress connection ID */
len = slhc_compress(ppp->slcomp, p, len, ppp->cbuff, &p, 0);
len = slhc_compress(ppp->slcomp, p, len, ppp->cbuff, &p,
!(ppp->flags & SC_NO_TCP_CCID));
if (p[0] & SL_TYPE_COMPRESSED_TCP)
proto = PROTO_VJCOMP;
else {
......@@ -2055,10 +2068,25 @@ static struct device dev_ppp[PPP_NRUNIT] = {
0, 0, 0, 0, /* memory */
0, 0, /* base, irq */
0, 0, 0, NULL, ppp_init,
},
{ "ppp1" , 0, 0, 0, 0, 1, 0, 0, 0, 0, NULL, ppp_init },
{ "ppp2" , 0, 0, 0, 0, 2, 0, 0, 0, 0, NULL, ppp_init },
{ "ppp3" , 0, 0, 0, 0, 3, 0, 0, 0, 0, NULL, ppp_init },
}
, { "ppp1" , 0, 0, 0, 0, 1, 0, 0, 0, 0, NULL, ppp_init }
, { "ppp2" , 0, 0, 0, 0, 2, 0, 0, 0, 0, NULL, ppp_init }
, { "ppp3" , 0, 0, 0, 0, 3, 0, 0, 0, 0, NULL, ppp_init }
#ifdef PPP_PPP_LOTS
, { "ppp4" , 0, 0, 0, 0, 4, 0, 0, 0, 0, NULL, ppp_init }
, { "ppp5" , 0, 0, 0, 0, 5, 0, 0, 0, 0, NULL, ppp_init }
, { "ppp6" , 0, 0, 0, 0, 6, 0, 0, 0, 0, NULL, ppp_init }
, { "ppp7" , 0, 0, 0, 0, 7, 0, 0, 0, 0, NULL, ppp_init }
, { "ppp8" , 0, 0, 0, 0, 8, 0, 0, 0, 0, NULL, ppp_init }
, { "ppp9" , 0, 0, 0, 0, 9, 0, 0, 0, 0, NULL, ppp_init }
, { "ppp10" , 0, 0, 0, 0, 10, 0, 0, 0, 0, NULL, ppp_init }
, { "ppp11" , 0, 0, 0, 0, 11, 0, 0, 0, 0, NULL, ppp_init }
, { "ppp12" , 0, 0, 0, 0, 12, 0, 0, 0, 0, NULL, ppp_init }
, { "ppp13" , 0, 0, 0, 0, 13, 0, 0, 0, 0, NULL, ppp_init }
, { "ppp14" , 0, 0, 0, 0, 14, 0, 0, 0, 0, NULL, ppp_init }
, { "ppp15" , 0, 0, 0, 0, 15, 0, 0, 0, 0, NULL, ppp_init }
#endif
};
int
......
......@@ -1046,6 +1046,13 @@ slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
}
}
static int sl_open_dev(struct device *dev)
{
struct slip *sl = &sl_ctrl[dev->base_addr];
if(sl->tty==NULL)
return -ENODEV;
return 0;
}
/* Initialize the SLIP driver. Called by DDI. */
int
......@@ -1103,7 +1110,7 @@ slip_init(struct device *dev)
/* Finish setting up the DEVICE info. */
dev->mtu = SL_MTU;
dev->hard_start_xmit = sl_xmit;
dev->open = sl_open;
dev->open = sl_open_dev;
dev->stop = sl_close;
dev->hard_header = sl_header;
dev->type_trans = sl_type_trans;
......
......@@ -1242,7 +1242,8 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
sti();
timeout = jiffies + 50; /* arbitrary */
while ((hostdata->test_completed == -1) && jiffies < timeout);
while ((hostdata->test_completed == -1) && jiffies < timeout)
barrier();
failed = 1;
if (hostdata->test_completed == -1)
......@@ -1330,7 +1331,8 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
sti();
timeout = jiffies + 500; /* arbitrary */
while ((hostdata->test_completed == -1) && jiffies < timeout);
while ((hostdata->test_completed == -1) && jiffies < timeout)
barrier();
NCR53c7x0_write32 (DSA_REG, 0);
if (hostdata->test_completed == 2) {
......
......@@ -636,7 +636,8 @@ static int NCR5380_probe_irq (struct Scsi_Host *instance, int possible) {
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA |
ICR_ASSERT_SEL);
while (probe_irq == IRQ_NONE && jiffies < timeout);
while (probe_irq == IRQ_NONE && jiffies < timeout)
barrier();
NCR5380_write(SELECT_ENABLE_REG, 0);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
......@@ -2147,8 +2148,8 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) {
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
while ((NCR5380_read(STATUS_REG) & SR_BSY) &&
!hostdata->connected);
while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
barrier();
return;
case MESSAGE_REJECT:
/* Accept message by clearing ACK */
......@@ -2187,8 +2188,8 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) {
/* Enable reselect interrupts */
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/* Wait for bus free to avoid nasty timeouts */
while ((NCR5380_read(STATUS_REG) & SR_BSY) &&
!hostdata->connected);
while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
barrier();
return;
/*
* The SCSI data pointer is *IMPLICITLY* saved on a disconnect
......
......@@ -968,7 +968,7 @@ int aha152x_abort( Scsi_Cmnd *SCpnt)
/* sleep until the abortion is complete */
while(!abortion_complete)
;
barrier();
aborting=0;
return abort_result;
}
......
......@@ -681,7 +681,8 @@ int aha1542_command(Scsi_Cmnd * SCpnt)
aha1542_queuecommand(SCpnt, internal_done);
SCpnt->SCp.Status = 0;
while (!SCpnt->SCp.Status);
while (!SCpnt->SCp.Status)
barrier();
return SCpnt->result;
}
......
......@@ -788,7 +788,7 @@ int buslogic_command(Scsi_Cmnd *scpnt)
scpnt->SCp.Status = 0;
while (!scpnt->SCp.Status)
continue;
barrier();
return scpnt->result;
}
#endif
......
......@@ -462,7 +462,8 @@ int in2000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
if ( in2000_SCptr )
{
printk("in2000_queue_command waiting for free command block!\n");
while ( in2000_SCptr );
while ( in2000_SCptr )
barrier();
}
for ( timeout = jiffies + 5; timeout > jiffies; )
{
......
......@@ -18,7 +18,7 @@
Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
(you can reference it, but it is incomplete and inaccurate in places)
Version 0.41
Version 0.43 4/6/95 - kernel 1.2.0+, pcmcia 2.5.4+
Functions as standalone, loadable, and PCMCIA driver, the latter from
Dave Hind's PCMCIA package.
......@@ -29,6 +29,11 @@
/*----------------------------------------------------------------*/
/* Configuration */
/* Set the following to 2 to use normal interrupt (active high/totempole-
tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
drain */
#define QL_INT_ACTIVE_HIGH 2
/* Set the following to 1 to enable the use of interrupts. Note that 0 tends
to be more stable, but slower (or ties up the system more) */
#define QL_USE_IRQ 1
......@@ -100,6 +105,8 @@
/*----------------------------------------------------------------*/
#ifdef PCMCIA
#undef QL_INT_ACTIVE_HIGH
#define QL_INT_ACTIVE_HIGH 0
#define MODULE
#endif
......@@ -143,7 +150,7 @@ static int qlcfgc = ( FASTCLK << 3 ) | ( FASTSCSI << 4 );
/*----------------------------------------------------------------*/
/* The qlogic card uses two register maps - These macros select which one */
#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd ))
#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb6 , qbase + 0xd ))
#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd ))
/* following is watchdog timeout in microseconds */
#define WATCHDOG 5000000
......@@ -262,8 +269,10 @@ rtrc(7)
static int ql_wai(void)
{
int i,k;
k = 0;
i = jiffies + WATCHDOG;
while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0));
while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0))
barrier();
if (i <= jiffies)
return (DID_TIME_OUT);
if (qabort)
......@@ -420,8 +429,10 @@ rtrc(1)
return (k << 16);
/* should get bus service interrupt and disconnect interrupt */
i = inb(qbase + 5); /* should be bus service */
while (!qabort && ((i & 0x20) != 0x20))
while (!qabort && ((i & 0x20) != 0x20)) {
barrier();
i |= inb(qbase + 5);
}
rtrc(0)
if (qabort)
return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
......@@ -493,7 +504,8 @@ int qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
cmd->scsi_done = done;
/* wait for the last command's interrupt to finish */
while (qlcmd != NULL);
while (qlcmd != NULL)
barrier();
ql_icmd(cmd);
return 0;
}
......@@ -556,7 +568,6 @@ unsigned long flags;
outb(0x40 | qlcfg8 | qinitid, qbase + 8); /* (ini) bus id, disable scsi rst */
outb(qlcfg5, qbase + 5); /* select timer */
outb(qlcfg9, qbase + 9); /* prescaler */
qlirq = -1;
#if QL_RESET_AT_START
outb( 3 , qbase + 3 );
REG1;
......@@ -565,6 +576,7 @@ unsigned long flags;
#endif
#if QL_USE_IRQ
/* IRQ probe - toggle pin and check request pending */
if( qlirq == -1 ) {
save_flags( flags );
cli();
......@@ -575,21 +587,24 @@ unsigned long flags;
outb(10, 0x20); /* access pending interrupt map */
outb(10, 0xa0);
while (j--) {
outb(0xb2 , qbase + 0xd); /* int pin off */
outb(0xb0 | QL_INT_ACTIVE_HIGH , qbase + 0xd); /* int pin off */
i &= ~(inb(0x20) | (inb(0xa0) << 8)); /* find IRQ off */
outb(0xb6 , qbase + 0xd); /* int pin on */
outb(0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd); /* int pin on */
i &= inb(0x20) | (inb(0xa0) << 8); /* find IRQ on */
}
REG0;
while (inb(qbase + 5)); /* purge int */
j = -1;
while (i) /* find on bit */
i >>= 1, qlirq++; /* should check for exactly 1 on */
if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogic"))
host->can_queue = 1;
i >>= 1, j++; /* should check for exactly 1 on */
qlirq = j;
restore_flags( flags );
}
else
printk( "Ql: Using preset IRQ of %d\n", qlirq );
printk( "Ql: Using preset IRQ %d\n", qlirq );
if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogic"))
host->can_queue = 1;
#endif
request_region( qbase , 0x10 ,"qlogic");
hreg = scsi_register( host , 0 ); /* no host data */
......@@ -599,7 +614,7 @@ unsigned long flags;
if( qlirq != -1 )
hreg->irq = qlirq;
sprintf(qinfo, "Qlogic Driver version 0.41, chip %02X at %03X, IRQ %d, TPdma:%d",
sprintf(qinfo, "Qlogic Driver version 0.43, chip %02X at %03X, IRQ %d, TPdma:%d",
qltyp, qbase, qlirq, QL_TURBO_PDMA );
host->name = qinfo;
......
......@@ -369,7 +369,7 @@ void scan_scsis (struct Scsi_Host * shpnt)
do it right and use a mutex */
if (current == task[0])
while (SCpnt->request.dev != 0xfffe);
while (SCpnt->request.dev != 0xfffe) barrier();
else if (SCpnt->request.dev != 0xfffe) {
struct semaphore sem = MUTEX_LOCKED;
......@@ -421,7 +421,7 @@ void scan_scsis (struct Scsi_Host * shpnt)
256, scan_scsis_done, SCSI_TIMEOUT, 3);
if (current == task[0])
while (SCpnt->request.dev != 0xfffe);
while (SCpnt->request.dev != 0xfffe) barrier();
else if (SCpnt->request.dev != 0xfffe) {
struct semaphore sem = MUTEX_LOCKED;
......@@ -584,7 +584,7 @@ void scan_scsis (struct Scsi_Host * shpnt)
SCSI_TIMEOUT, 3);
if (current == task[0])
while (SCpnt->request.dev != 0xfffe);
while (SCpnt->request.dev != 0xfffe) barrier();
else if (SCpnt->request.dev != 0xfffe) {
struct semaphore sem = MUTEX_LOCKED;
......@@ -1551,7 +1551,8 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid)
if (SCpnt->internal_timeout & IN_ABORT)
{
restore_flags(flags);
while (SCpnt->internal_timeout & IN_ABORT);
while (SCpnt->internal_timeout & IN_ABORT)
barrier();
}
else
{
......@@ -1644,7 +1645,8 @@ int scsi_reset (Scsi_Cmnd * SCpnt)
if (SCpnt->internal_timeout & IN_RESET)
{
restore_flags(flags);
while (SCpnt->internal_timeout & IN_RESET);
while (SCpnt->internal_timeout & IN_RESET)
barrier();
}
else
{
......
......@@ -89,7 +89,8 @@ static int sd_open(struct inode * inode, struct file * filp)
/* Make sure that only one process can do a check_change_disk at one time.
This is also used to lock out further access when the partition table is being re-read. */
while (rscsi_disks[target].device->busy);
while (rscsi_disks[target].device->busy)
barrier();
if(rscsi_disks[target].device->removable) {
check_disk_change(inode->i_rdev);
......@@ -879,7 +880,7 @@ static int sd_init_onedisk(int i)
512, sd_init_done, SD_TIMEOUT,
MAX_RETRIES);
while(SCpnt->request.dev != 0xfffe);
while(SCpnt->request.dev != 0xfffe) barrier();
the_result = SCpnt->result;
......@@ -905,7 +906,7 @@ static int sd_init_onedisk(int i)
512, sd_init_done, SD_TIMEOUT,
MAX_RETRIES);
while(SCpnt->request.dev != 0xfffe);
while(SCpnt->request.dev != 0xfffe) barrier();
spintime = jiffies;
};
......@@ -941,7 +942,7 @@ static int sd_init_onedisk(int i)
MAX_RETRIES);
if (current == task[0])
while(SCpnt->request.dev != 0xfffe);
while(SCpnt->request.dev != 0xfffe) barrier();
else
if (SCpnt->request.dev != 0xfffe){
struct semaphore sem = MUTEX_LOCKED;
......
......@@ -926,7 +926,7 @@ static void get_sectorsize(int i){
MAX_RETRIES);
if (current == task[0])
while(SCpnt->request.dev != 0xfffe);
while(SCpnt->request.dev != 0xfffe) barrier();
else
if (SCpnt->request.dev != 0xfffe){
struct semaphore sem = MUTEX_LOCKED;
......
......@@ -320,9 +320,9 @@ static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
#if 0
for (; i; --i) {
while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY);
while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY) barrier();
#else
while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY);
while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY) barrier();
for (; i; --i) {
#endif
*d++ = *reg;
......@@ -363,9 +363,9 @@ static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src
#if 0
for (; i; --i) {
while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY);
while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY) barrier();
#else
while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY);
while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY) barrier();
for (; i; --i) {
#endif
*reg = *s++;
......
......@@ -733,13 +733,13 @@ int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
retry:
if (config.slot)
while (inb(config.ogm_address - 1) != 0 &&
config.aborted[mscp_index] == 0xff);
config.aborted[mscp_index] == 0xff) barrier();
/* else??? */
while ((inb(LCL_DOORBELL_INTR(config.doorbell_address)) &
(config.slot ? 2 : 1))
&& config.aborted[mscp_index] == 0xff);
&& config.aborted[mscp_index] == 0xff) barrier();
/* To avoid race conditions, make the code to write to the adapter
atomic. This simplifies the abort code. */
......
......@@ -941,7 +941,7 @@ int wd7000_command(Scsi_Cmnd *SCpnt)
{
wd7000_queuecommand(SCpnt, wd7000_scsi_done);
while (SCpnt->SCp.phase > 0); /* phase counts scbs down to 0 */
while (SCpnt->SCp.phase > 0) barrier(); /* phase counts scbs down to 0 */
return SCpnt->result;
}
......@@ -964,7 +964,8 @@ int wd7000_diagnostics( Adapter *host, int code )
*/
mail_out(host, (struct scb *) &icb);
timeout = jiffies + WAITnexttimeout; /* wait up to 2 seconds */
while (icb.phase && jiffies < timeout) /* wait for completion */;
while (icb.phase && jiffies < timeout)
barrier(); /* wait for completion */
if (icb.phase) {
printk("wd7000_diagnostics: timed out.\n");
......@@ -1074,7 +1075,8 @@ void wd7000_revision(Adapter *host)
* which in turn means that scatter/gather will be disabled.
*/
mail_out(host, (struct scb *) &icb);
while (icb.phase) /* wait for completion */;
while (icb.phase)
barrier(); /* wait for completion */
host->rev1 = icb.primary;
host->rev2 = icb.secondary;
}
......
......@@ -3,7 +3,10 @@
*/
/*
* the definitions for the first controller can get overridden by
* Attention! This file contains user-serviceable parts!
* I recommend to make use of it...
*
* The definitions for the first controller can get overridden by
* the kernel command line ("lilo boot option").
* Examples:
* sbpcd=0x230,SoundBlaster
......@@ -12,65 +15,98 @@
* or
* sbpcd=0x330,SPEA
*
* These strings are case sensitive !!!
* If sbpcd gets used as a module, you can load it with
* insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x230,1
* or
* insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x300,0
* or
* insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x330,2
* respective to override the configured address and type.
*/
/*
* put your CDROM port base address into CDROM_PORT
* and specify the type of your interface in SBPRO.
* define your CDROM port base address as CDROM_PORT
* and specify the type of your interface card as SBPRO.
*
* SBPRO addresses typically are 0x0230 (=0x220+0x10), 0x0250, ...
* LASERMATE (CI-101P, WDH-7001C) addresses typically are 0x0300, 0x0310, ...
* SPEA addresses are 0x320, 0x330, 0x340, 0x350
* there are some soundcards on the market with 0x0630, 0x0650, ...
* Read linux/drivers/block/README.sbpcd if you are in doubt about the
* type of your interface card (you should do that anyway).
*
* example: if your SBPRO audio address is 0x220, specify 0x230.
* address:
* ========
* SBPRO type addresses typically are 0x0230 (=0x220+0x10), 0x0250, ...
* LASERMATE type (CI-101P, WDH-7001C) addresses typically are 0x0300, ...
* SPEA addresses are from the LASERMATE type and range.
* There are some soundcards on the market with 0x0630, 0x0650, ...; their
* type is not obvious (both types are possible).
*
* example: if your SBPRO audio address is 0x220, specify 0x230 and SBPRO 1.
* if your soundcard has its CDROM port above 0x300, specify
* that address and try SBPRO 0 first.
*
* interface type:
* ===============
* set SBPRO to 1 for "true" SoundBlaster card
* set SBPRO to 0 for "poor" (no sound) interface cards
* and for "compatible" soundcards.
* set SBPRO to 0 for "compatible" soundcards and
* for "poor" (no sound) interface cards.
* set SBPRO to 2 for the SPEA Media FX card
*
* most "compatible" sound boards like Galaxy need to set SBPRO to 0 !!!
* if SBPRO gets set wrong, the drive will get found - but any
* Almost all "compatible" sound boards need to set SBPRO to 0.
* If SBPRO is set wrong, the drives will get found - but any
* data access will give errors (audio access will work).
* The OmniCD interface card from CreativeLabs needs SBPRO 1.
* The "OmniCD" no-sound 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.
*/
#if !(SBPCD_ISSUE-1) /* first (or if you have only one) interface board: */
#define CDROM_PORT 0x0340
#define SBPRO 0
#endif
/*
* If you have a "compatible" soundcard of type "SBPRO 0" or "SBPRO 2",
* enter your sound card's base address here if you want sbpcd to turn
* the CD sound channels on.
* mail to emoenke@gwdg.de if you have a "compatible" sound card which
* in fact needs to set SBPRO to 1 (not any known at time).
*
* sound base:
* ===========
* The SOUND_BASE definition tells if we should try to turn the CD sound
* channels on. It will only be of use regarding soundcards with a SbPro
* compatible mixer.
*
* Example: #define SOUND_BASE 0x220 enables the sound card's CD channels
* #define SOUND_BASE 0 leaves the soundcard untouched
*/
#define SOUND_BASE 0x220
/* ignore the rest if you have only one interface board & driver */
#if !(SBPCD_ISSUE-2) /* second interface board: */
#define CDROM_PORT 0x0320
#define SBPRO 0
#if !(SBPCD_ISSUE-1) /* first (or if you have only one) interface board: */
#define CDROM_PORT 0x340 /* <-----------<< port address */
#define SBPRO 0 /* <-----------<< interface type */
#define SOUND_BASE 0x220 /* <-----------<< sound address of this card or 0 */
#endif
#if !(SBPCD_ISSUE-2) /* ==================== second interface board: === */
#define CDROM_PORT 0x344 /* <-----------<< port address */
#define SBPRO 0 /* <-----------<< interface type */
#define SOUND_BASE 0x000 /* <-----------<< sound address of this card or 0 */
#endif
#if !(SBPCD_ISSUE-3) /* third interface board: */
#define CDROM_PORT 0x0630
#define SBPRO 1
#if !(SBPCD_ISSUE-3) /* ===================== third interface board: === */
#define CDROM_PORT 0x634 /* <-----------<< port address */
#define SBPRO 1 /* <-----------<< interface type */
#define SOUND_BASE 0x240 /* <-----------<< sound address of this card or 0 */
#endif
#if !(SBPCD_ISSUE-4) /* fourth interface board: */
#define CDROM_PORT 0x0634
#define SBPRO 0
#if !(SBPCD_ISSUE-4) /* ==================== fourth interface board: === */
#define CDROM_PORT 0x634 /* <-----------<< port address */
#define SBPRO 0 /* <-----------<< interface type */
#define SOUND_BASE 0x000 /* <-----------<< sound address of this card or 0 */
#endif
/*
* some more or less user dependent definitions - service them!
*/
/* Set this to 0 after you have configured your interface definitions right. */
#define DISTRIBUTION 1
/* max. number of audio frames to read with one */
/* request (allocates n* 2352 bytes kernel memory!) */
/* may be freely adjusted, f.e. 75 (= 1 sec.), at */
/* runtime by use of the CDROMAUDIOBUFSIZ ioctl. */
#define READ_AUDIO 0
/* tray control: eject tray if no disk is in (0 or 1) */
#define JUKEBOX 1
/* tray control: eject tray after last use (0 or 1) */
#define EJECT 1
/*==========================================================================*/
/*==========================================================================*/
/*
......@@ -79,49 +115,65 @@
#ifndef _LINUX_SBPCD_H
#define _LINUX_SBPCD_H
/*==========================================================================*/
/*==========================================================================*/
#define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */
#undef FUTURE
#define TEST_UPC 0
#define SPEA_TEST 0
#define TEST_STI 0
#undef PATH_CHECK
/*==========================================================================*/
/*
* DDI interface definitions
* "invented" by Fred N. van Kempen..
*/
#define DDIOCSDBG 0x9000
#define DPRINTF(x) sbpcd_dprintf x
/*==========================================================================*/
/*
* "private" IOCTL functions
*/
#define CDROMRESET 0x5380 /* hard-rest the drive */
#define CDROMVOLREAD 0x5381 /* let the drive tell its volume settings */
#define CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */
/*==========================================================================*/
/*
* Debug output levels
*/
#define DBG_INF 1 /* necessary information */
#define DBG_BSZ 2 /* BLOCK_SIZE 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_IOS 19 /* ioctl trace: "subchannel" */
#define DBG_IO2 20 /* ioctl trace: general */
#define DBG_UPC 21 /* show UPC information */
#define DBG_XA 22 /* XA mode debugging */
#define DBG_LCK 23 /* door (un)lock info */
#define DBG_SQ 24 /* dump SubQ frame */
#define DBG_AUD 25 /* "read audio" debugging */
#define DBG_SEQ 26 /* Sequoia interface configuration trace */
#define DBG_LCS 27 /* Longshine LCS-7260 debugging trace */
#define DBG_CD2 28 /* MKE CD200 debugging trace */
#define DBG_000 29 /* unnecessary information */
#define DBG_INF 1 /* necessary information */
#define DBG_BSZ 2 /* BLOCK_SIZE 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 /* cc_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_IDX 14 /* test code for drive_id !=0 */
#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_IOS 19 /* ioctl trace: subchannel functions */
#define DBG_IO2 20 /* ioctl trace: general */
#define DBG_UPC 21 /* show UPC information */
#define DBG_XA1 22 /* XA mode debugging */
#define DBG_LCK 23 /* door (un)lock info */
#define DBG_SQ1 24 /* dump SubQ frame */
#define DBG_AUD 25 /* READ AUDIO debugging */
#define DBG_SEQ 26 /* Sequoia interface configuration trace */
#define DBG_LCS 27 /* Longshine LCS-7260 debugging trace */
#define DBG_CD2 28 /* MKE CD200 debugging trace */
#define DBG_TEA 29 /* TEAC CD-55A debugging trace */
#define DBG_TE2 30 /* TEAC CD-55A 2nd debugging level */
#define DBG_000 31 /* unnecessary information */
/*==========================================================================*/
/*==========================================================================*/
......@@ -154,35 +206,41 @@
/*
* disk states (bits of diskstate_flags):
*/
#define upc_valid (DriveStruct[d].diskstate_flags&upc_bit)
#define volume_valid (DriveStruct[d].diskstate_flags&volume_bit)
#define toc_valid (DriveStruct[d].diskstate_flags&toc_bit)
#define cd_size_valid (DriveStruct[d].diskstate_flags&cd_size_bit)
#define subq_valid (DriveStruct[d].diskstate_flags&subq_bit)
#define frame_size_valid (DriveStruct[d].diskstate_flags&frame_size_bit)
#define upc_valid (D_S[d].diskstate_flags&upc_bit)
#define volume_valid (D_S[d].diskstate_flags&volume_bit)
#define toc_valid (D_S[d].diskstate_flags&toc_bit)
#define cd_size_valid (D_S[d].diskstate_flags&cd_size_bit)
#define subq_valid (D_S[d].diskstate_flags&subq_bit)
#define frame_size_valid (D_S[d].diskstate_flags&frame_size_bit)
/*
* the status_bits variable
*/
#define p_success 0x100
#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_disk_ok 0x01
/*
* bits of the status_byte (result of xx_ReadStatus):
* LCS-7260 special status result bits:
*/
#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 /* hopefully unused now */
#define p_lcs_door_locked 0x02 /* new use of old bit */
#define p_disk_ok 0x01
#define p_lcs_door_closed 0x01 /* new use of old bit */
#define p_lcs_door_locked 0x02
#define p_lcs_door_closed 0x01
/*
* "old" drives status result bits:
* CR-52x special status result bits:
*/
#define p_caddin_old 0x40
#define p_success_old 0x08
#define p_busy_old 0x04
#define p_caddin_old 0x40
#define p_success_old 0x08
#define p_busy_old 0x04
#define p_bit_1 0x02 /* hopefully unused now */
/*
* "generation specific" defs of the status_byte:
* "generation specific" defs of the status result bits:
*/
#define p0_door_closed 0x80
#define p0_caddy_in 0x40
......@@ -193,6 +251,14 @@
#define p0_bit_1 0x02 /* unused */
#define p0_disk_ok 0x01
#define pL_disk_in 0x40
#define pL_spinning 0x20
#define pL_check 0x10
#define pL_success 0x08 /* unused ?? */
#define pL_busy 0x04
#define pL_door_locked 0x02
#define pL_door_closed 0x01
#define p1_door_closed 0x80
#define p1_disk_in 0x40
#define p1_spinning 0x20
......@@ -214,60 +280,66 @@
/*
* used drive states:
*/
#define st_door_closed (DriveStruct[d].status_byte&p_door_closed)
#define st_caddy_in (DriveStruct[d].status_byte&p_caddy_in)
#define st_spinning (DriveStruct[d].status_byte&p_spinning)
#define st_check (DriveStruct[d].status_byte&p_check)
#define st_busy (DriveStruct[d].status_byte&p_busy_new)
#define st_door_locked (DriveStruct[d].status_byte&p_door_locked)
#define st_diskok (DriveStruct[d].status_byte&p_disk_ok)
#define st_door_closed (D_S[d].status_bits&p_door_closed)
#define st_caddy_in (D_S[d].status_bits&p_caddy_in)
#define st_spinning (D_S[d].status_bits&p_spinning)
#define st_check (D_S[d].status_bits&p_check)
#define st_busy (D_S[d].status_bits&p_busy_new)
#define st_door_locked (D_S[d].status_bits&p_door_locked)
#define st_diskok (D_S[d].status_bits&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" */
#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)
#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_fam0 0x08 /* CR-52x family */
#define drv_199 (drv_fam0+0x01) /* <200 */
#define drv_200 (drv_fam0+0x02) /* <201 */
#define drv_201 (drv_fam0+0x03) /* <210 */
#define drv_210 (drv_fam0+0x04) /* <211 */
#define drv_211 (drv_fam0+0x05) /* <300 */
#define drv_300 (drv_fam0+0x06) /* >=300 */
#define drv_famL 0x10 /* Longshine family */
#define drv_260 (drv_famL+0x01) /* LCS-7260 */
#define drv_fam1 0x20 /* CR-56x family */
#define drv_099 (drv_fam1+0x01) /* <100 */
#define drv_100 (drv_fam1+0x02) /* >=100 */
#define drv_fam2 0x80 /* CD200 family */
#define fam0_drive (DriveStruct[d].drv_type&drv_fam0)
#define famL_drive (DriveStruct[d].drv_type&drv_famL)
#define fam1_drive (DriveStruct[d].drv_type&drv_fam1)
#define fam2_drive (DriveStruct[d].drv_type&drv_fam2)
#define fam0L_drive (DriveStruct[d].drv_type&(drv_fam0|drv_famL))
#define fam1L_drive (DriveStruct[d].drv_type&(drv_fam1|drv_famL))
#define fam01_drive (DriveStruct[d].drv_type&(drv_fam0|drv_fam1))
#define drv_fam0 0x08 /* CR-52x family */
#define drv_199 (drv_fam0+0x01) /* <200 */
#define drv_200 (drv_fam0+0x02) /* <201 */
#define drv_201 (drv_fam0+0x03) /* <210 */
#define drv_210 (drv_fam0+0x04) /* <211 */
#define drv_211 (drv_fam0+0x05) /* <300 */
#define drv_300 (drv_fam0+0x06) /* >=300 */
#define drv_famL 0x10 /* Longshine family */
#define drv_260 (drv_famL+0x01) /* LCS-7260 */
#define drv_e1 (drv_famL+0x01) /* LCS-7260, firmware "A E1" */
#define drv_f4 (drv_famL+0x02) /* LCS-7260, firmware "A4F4" */
#define drv_fam1 0x20 /* CR-56x family */
#define drv_099 (drv_fam1+0x01) /* <100 */
#define drv_100 (drv_fam1+0x02) /* >=100, only 5.00 known here */
#define drv_famT 0x40 /* TEAC CD-55A */
#define drv_fam2 0x80 /* CD200 family */
#define fam0_drive (D_S[d].drv_type&drv_fam0)
#define famL_drive (D_S[d].drv_type&drv_famL)
#define fam1_drive (D_S[d].drv_type&drv_fam1)
#define fam2_drive (D_S[d].drv_type&drv_fam2)
#define famT_drive (D_S[d].drv_type&drv_famT)
#define fam0L_drive (D_S[d].drv_type&(drv_fam0|drv_famL))
#define fam1L_drive (D_S[d].drv_type&(drv_fam1|drv_famL))
#define fam01_drive (D_S[d].drv_type&(drv_fam0|drv_fam1))
#define fam12_drive (D_S[d].drv_type&(drv_fam1|drv_fam2))
#define fam2T_drive (D_S[d].drv_type&(drv_fam2|drv_famT))
/*
* audio states:
*/
#define audio_playing 2
#define audio_pausing 1
#define audio_playing 2
#define audio_pausing 1
/*
* drv_pattern, drv_options:
......@@ -280,10 +352,10 @@
/*
* values of cmd_type (0 else):
*/
#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 */
#define READ_AU 0x08 /* "audio frame": 2352 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 */
#define READ_AU 0x08 /* "audio frame": 2352 bytes per frame */
/*
* sense_byte:
......@@ -314,32 +386,27 @@
/*
* highest allowed drive number (MINOR+1)
*/
#define NR_SBPCD 4
#define NR_SBPCD 4
/*
* we try to never disable interrupts - seems to work
*/
#define SBPCD_DIS_IRQ 0
#define SBPCD_DIS_IRQ 0
/*
* "write byte to port"
*/
#define OUT(x,y) outb(y,x)
/*
* use "REP INSB" for strobing the data in:
*/
#define READ_DATA(port, buf, nr) insb(port, buf, nr)
#define OUT(x,y) outb(y,x)
/*==========================================================================*/
#define MIXER_CD_Volume 0x28 /* internal SB Pro register address */
#define MIXER_CD_Volume 0x28 /* internal SB Pro register address */
/*==========================================================================*/
/*
* Creative Labs Programmers did this:
*/
#define MAX_TRACKS 120 /* why more than 99? */
#define MAX_TRACKS 120 /* why more than 99? */
/*==========================================================================*/
/*
......@@ -347,17 +414,15 @@
*/
typedef union _msf
{
u_int n;
u_char c[4];
}
MSF;
u_int n;
u_char c[4];
} MSF;
typedef union _blk
{
u_int n;
u_char c[4];
}
BLK;
u_int n;
u_char c[4];
} BLK;
/*==========================================================================*/
......@@ -519,111 +584,177 @@ Read XA Parameter:
* CR-56x: CMD1_
* CD200: CMD2_
* LCS-7260: CMDL_
* TEAC CD-55A: CMDT_
*/
#define CMD1_RESET 0x0a
#define CMD2_RESET 0x01
#define CMDT_RESET 0xc0
#define CMD1_LOCK_CTL 0x0c
#define CMD2_LOCK_CTL 0x1e
#define CMDT_LOCK_CTL CMD2_LOCK_CTL
#define CMDL_LOCK_CTL 0x0e
#define CMD1_TRAY_CTL 0x07
#define CMD2_TRAY_CTL 0x1b
#define CMDT_TRAY_CTL CMD2_TRAY_CTL
#define CMDL_TRAY_CTL 0x0d
#define CMD1_MULTISESS 0x8d
#define CMDL_MULTISESS 0x8c
#define CMD1_SUBCHANINF 0x11
#define CMD2_SUBCHANINF 0x
#define CMD2_SUBCHANINF 0x??
#define CMD2_x02 0x02
#define CMD1_x08 0x08
#define CMD2_x08 0x08
#define CMDT_x08 0x08
#define CMD2_SETSPEED 0xda
#define CMD0_PATH_CHECK 0x00
#define CMD1_PATH_CHECK 0x00
#define CMD2_PATH_CHECK 0x
#define CMDL_PATH_CHECK 0x00
#define CMD1_PATH_CHECK 0x???
#define CMD2_PATH_CHECK 0x???
#define CMDT_PATH_CHECK 0x???
#define CMDL_PATH_CHECK CMD0_PATH_CHECK
#define CMD0_SEEK 0x01
#define CMD1_SEEK 0x01
#define CMD1_SEEK CMD0_SEEK
#define CMD2_SEEK 0x2b
#define CMDL_SEEK 0x01
#define CMDT_SEEK CMD2_SEEK
#define CMDL_SEEK CMD0_SEEK
#define CMD0_READ 0x02
#define CMD1_READ 0x10
#define CMD2_READ 0x28
#define CMDL_READ 0x02
#define CMDT_READ CMD2_READ
#define CMDL_READ CMD0_READ
#define CMD0_READ_XA 0x03
#define CMD2_READ_XA 0xd4
#define CMDL_READ_XA 0x03 /* really ?? */
#define CMDL_READ_XA CMD0_READ_XA /* really ?? */
#define CMD0_READ_HEAD 0x04
#define CMD0_SPINUP 0x05
#define CMD1_SPINUP 0x02
#define CMD2_SPINUP CMD2_TRAY_CTL
#define CMDL_SPINUP 0x05
#define CMDL_SPINUP CMD0_SPINUP
#define CMD0_SPINDOWN 0x06 /* really??? */
#define CMD1_SPINDOWN 0x06
#define CMD2_SPINDOWN CMD2_TRAY_CTL
#define CMDL_SPINDOWN 0x0d
#define CMD0_DIAG 0x07
#define CMD0_READ_UPC 0x08
#define CMD1_READ_UPC 0x88
#define CMD2_READ_UPC 0x
#define CMDL_READ_UPC 0x08
#define CMD2_READ_UPC 0x???
#define CMDL_READ_UPC CMD0_READ_UPC
#define CMD0_READ_ISRC 0x09
#define CMD0_PLAY 0x0a
#define CMD1_PLAY 0x
#define CMD2_PLAY 0x
#define CMDL_PLAY 0x0a
#define CMD1_PLAY 0x???
#define CMD2_PLAY 0x???
#define CMDL_PLAY CMD0_PLAY
#define CMD0_PLAY_MSF 0x0b
#define CMD1_PLAY_MSF 0x0e
#define CMD2_PLAY_MSF 0x47
#define CMDL_PLAY_MSF 0x
#define CMDT_PLAY_MSF CMD2_PLAY_MSF
#define CMDL_PLAY_MSF 0x???
#define CMD0_PLAY_TI 0x0c
#define CMD0_STATUS 0x81
#define CMD1_STATUS 0x05
#define CMD2_STATUS 0x00
#define CMDL_STATUS 0x81
#define CMDT_STATUS CMD2_STATUS
#define CMDL_STATUS CMD0_STATUS
#define CMD0_READ_ERR 0x82
#define CMD1_READ_ERR 0x82
#define CMD1_READ_ERR CMD0_READ_ERR
#define CMD2_READ_ERR 0x03
#define CMDL_READ_ERR 0x82
#define CMDT_READ_ERR CMD2_READ_ERR /* get audio status */
#define CMDL_READ_ERR CMD0_READ_ERR
#define CMD0_READ_VER 0x83
#define CMD1_READ_VER 0x83
#define CMD1_READ_VER CMD0_READ_VER
#define CMD2_READ_VER 0x12
#define CMDL_READ_VER 0x83
#define CMDT_READ_VER CMD2_READ_VER /* really ?? */
#define CMDL_READ_VER CMD0_READ_VER
#define CMD0_SETMODE 0x84
#define CMD1_SETMODE 0x09
#define CMD2_SETMODE 0x55
#define CMDL_SETMODE 0x84
#define CMDT_SETMODE CMD2_SETMODE
#define CMDL_SETMODE CMD0_SETMODE
#define CMD0_GETMODE 0x85
#define CMD1_GETMODE 0x84
#define CMD2_GETMODE 0x5a
#define CMDL_GETMODE 0x85
#define CMDT_GETMODE CMD2_GETMODE
#define CMDL_GETMODE CMD0_GETMODE
#define CMD0_SET_XA 0x86
#define CMD0_GET_XA 0x87
#define CMD0_CAPACITY 0x88
#define CMD1_CAPACITY 0x85
#define CMD2_CAPACITY 0x25
#define CMDL_CAPACITY 0x88
#define CMDL_CAPACITY CMD0_CAPACITY /* missing in some firmware versions */
#define CMD0_READSUBQ 0x89
#define CMD1_READSUBQ 0x87
#define CMD2_READSUBQ 0x42
#define CMDL_READSUBQ 0x89
#define CMDT_READSUBQ CMD2_READSUBQ
#define CMDL_READSUBQ CMD0_READSUBQ
#define CMD0_DISKCODE 0x8a
#define CMD0_DISKINFO 0x8b
#define CMD1_DISKINFO 0x8b
#define CMD1_DISKINFO CMD0_DISKINFO
#define CMD2_DISKINFO 0x43
#define CMDL_DISKINFO 0x8b
#define CMDT_DISKINFO CMD2_DISKINFO
#define CMDL_DISKINFO CMD0_DISKINFO
#define CMD0_READTOC 0x8c
#define CMD1_READTOC 0x8c
#define CMD2_READTOC 0x
#define CMDL_READTOC 0x8c
#define CMD1_READTOC CMD0_READTOC
#define CMD2_READTOC 0x???
#define CMDL_READTOC CMD0_READTOC
#define CMD0_PAU_RES 0x8d
#define CMD1_PAU_RES 0x0d
#define CMD2_PAU_RES 0x4b
#define CMDL_PAU_RES 0x8d
#define CMDT_PAUSE CMD2_PAU_RES
#define CMDL_PAU_RES CMD0_PAU_RES
#define CMD0_PACKET 0x8e
#define CMD1_PACKET 0x8e
#define CMD2_PACKET 0x
#define CMDL_PACKET 0x8e
#define CMD1_PACKET CMD0_PACKET
#define CMD2_PACKET 0x???
#define CMDL_PACKET CMD0_PACKET
/*==========================================================================*/
/*==========================================================================*/
#endif _LINUX_SBPCD_H
/*==========================================================================*/
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 8
* c-brace-imaginary-offset: 0
* c-brace-offset: -8
* c-argdecl-indent: 8
* c-label-offset: -8
* c-continued-statement-offset: 8
* c-continued-brace-offset: 0
* End:
*/
......@@ -77,6 +77,8 @@ extern int nr_running, nr_tasks;
#ifdef __KERNEL__
#define barrier() __asm__("": : :"memory")
extern void sched_init(void);
extern void show_state(void);
extern void trap_init(void);
......
......@@ -255,6 +255,7 @@ struct tty_struct {
#define TTY_DEBUG 4
#define TTY_DO_WRITE_WAKEUP 5
#define TTY_PUSH 6
#define TTY_CLOSING 7
#define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
......
......@@ -321,7 +321,6 @@ struct symbol_table symbol_table = {
X(n_tty_ioctl),
X(tty_register_ldisc),
X(kill_fasync),
X(tty_hung_up_p),
#endif
#ifdef CONFIG_SCSI
/* Supports loadable scsi drivers */
......
......@@ -15,6 +15,7 @@
* AX.25 now works right, and SPX is feasible.
* Alan Cox : Fixed write select of non IP protocol crash.
* Florian La Roche: Changed for my new skbuff handling.
* Darryl Miles : Fixed non-blocking SOCK_SEQPACKET.
*
* Note:
* A lot of this will change when the protocol/socket separation
......@@ -191,6 +192,11 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
return(0);
case SEL_OUT:
if (sk->type==SOCK_SEQPACKET && sk->state==TCP_SYN_SENT)
{
/* Connection still in progress */
return(0);
}
if (sk->prot && sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
{
return(1);
......
......@@ -2854,7 +2854,7 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
buff = newsk->prot->wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
if (buff == NULL)
{
sk->err = -ENOMEM;
sk->err = ENOMEM;
newsk->dead = 1;
newsk->state = TCP_CLOSE;
/* And this will destroy it */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment