Commit 111bb14a authored by Linus Torvalds's avatar Linus Torvalds

Import 1.3.27

parent 39a57ddd
VERSION = 1
PATCHLEVEL = 3
SUBLEVEL = 26
SUBLEVEL = 27
ARCH = i386
......
......@@ -226,13 +226,13 @@ if [ "$CONFIG_CD_NO_IDESCSI" = "y" ]; then
tristate 'Sony CDU31A/CDU33A CDROM support' CONFIG_CDU31A n
tristate 'Standard Mitsumi [no XA/Multisession] CDROM support' CONFIG_MCD n
tristate 'Experimental Mitsumi [XA/MultiSession] support' CONFIG_MCDX n
tristate 'Matsushita/Panasonic CDROM support' CONFIG_SBPCD n
tristate 'Matsushita/Panasonic/Creative, Longshine, TEAC CDROM support' CONFIG_SBPCD n
if [ "$CONFIG_SBPCD" = "y" ]; then
bool 'Matsushita/Panasonic second CDROM controller support' CONFIG_SBPCD2 n
bool 'Matsushita/Panasonic, ... second CDROM controller support' CONFIG_SBPCD2 n
if [ "$CONFIG_SBPCD2" = "y" ]; then
bool 'Matsushita/Panasonic third CDROM controller support' CONFIG_SBPCD3 n
bool 'Matsushita/Panasonic, ... third CDROM controller support' CONFIG_SBPCD3 n
if [ "$CONFIG_SBPCD3" = "y" ]; then
bool 'Matsushita/Panasonic fourth CDROM controller support' CONFIG_SBPCD4 n
bool 'Matsushita/Panasonic, ... fourth CDROM controller support' CONFIG_SBPCD4 n
fi
fi
fi
......@@ -266,6 +266,11 @@ tristate 'SMB filesystem (to mount WfW shares etc..) support' CONFIG_SMB_FS n
comment 'character devices'
bool 'Cyclades async mux support' CONFIG_CYCLADES n
bool 'Stallion multiport serial support' CONFIG_STALDRV n
if [ "$CONFIG_STALDRV" = "y" ]; then
tristate ' Stallion EasyIO or EC8/32 support' CONFIG_STALLION n
tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION n
fi
tristate 'Parallel printer support' CONFIG_PRINTER n
tristate 'Logitech busmouse support' CONFIG_BUSMOUSE n
tristate 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n
......
This README belongs to release 3.7 or newer of the SoundBlaster Pro
This README belongs to release 3.9 or newer of the SoundBlaster Pro
(Matsushita, Kotobuki, Panasonic, CreativeLabs, Longshine and TEAC)
CD-ROM driver for Linux.
The driver is able to drive the whole family of "traditional" IDE-style (that
Sbpcd really, really is NOT for ANY IDE/ATAPI drive!
Not even if you have an "original" SoundBlaster card with an IDE interface!
So, you better have a look into README.ide if your port address is 0x1F0,
0x170, 0x1E8, 0x168 or similar.
I get tons of mails from IDE/ATAPI drive users - I really can't continue
any more to answer them all. So, if your drive/interface information sheets
mention "IDE" (primary, secondary, tertiary, quaternary) and the DOS driver
invoking line within your CONFIG.SYS is using an address below 0x230:
DON'T ROB MY LAST NERVE - jumper your interface to address 0x170 and IRQ 15
(that is the "secondary IDE" configuration), set your drive to "master" and
use ide-cd as your driver. If you do not have a second IDE hard disk, use the
LILO commands
hdb=noprobe hdc=cdrom
and get lucky.
To make it fully clear to you: if you mail me about IDE/ATAPI drive problems,
my answer is above, and I simply will discard your mail, hoping to stop the
flood and to find time to lead my 12-years old son towards happy computing.
The driver is able to drive the whole family of "traditional" AT-style (that
is NOT the new "Enhanced IDE" or "ATAPI" drive standard) Matsushita,
Kotobuki, Panasonic drives, sometimes labelled as "CreativeLabs". The
well-known drives are CR-521, CR-522, CR-523, CR-562, CR-563.
CR-574 is an IDE/ATAPI drive.
The Longshine LCS-7260 is a double-speed drive which uses the "old"
Matsushita command set. It is supported now - with help by Serge Robyns.
Matsushita command set. It is supported - with help by Serge Robyns.
There exists an "IBM External ISA CD-ROM Drive" which in fact is a CR-563
with a special controller board. This drive is supported (the interface is
......@@ -16,39 +35,72 @@ 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).
CreativeLabs has a new drive "CD-200". Support is under construction.
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).
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.
CreativeLabs has a new drive "CD200" and a similar drive "CD200F". The latter
is made by Funai and sometimes named "E2550UA". Support is under construction
- CD200F should work, CD200 is still giving problems.
Drive detection and playing audio should work. I need qualified feedback
about the bugs within the data functions or a drive (I never saw a CD200).
The quad-speed TEAC CD-55A drive is supported, but still does not reach "full
speed". The data rate already reaches 500 kB/sec if you set SBP_BUFFER_FRAMES
to 64 (it is not recommended to do that for normal "file access" usage, but it
can speed up things a lot if you use something like "dd" to read from the
drive; I use it for verifying self-written CDs this way).
The drive itself is able to deliver 600 kB/sec, so this has to get a point of
work; with the normal setup, the performance currently is not even as good as
double-speed.
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.
and again: this driver is in no way usable for any IDE/ATAPI drive. If you
think your drive should work and it doesn't: send me the DOS driver for your
beast (gzipped + uuencoded) and your CONFIG.SYS if you want to ask me for help,
and include an original log message excerpt, and try to give all information
a complete idiot needs to understand your hassle already with your first
mail. And if you want to say "as I have mailed you before", be sure that I
don't remember your "case" by such remarks; at the moment, I have some
hundreds open correspondences about Linux CDROM questions (hope to reduce if
the IDE/ATAPI user questions disappear).
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,
WDH-7001C, Longshine LCS-6853, older Aztech cards, ...).
It should work too now with the "configurable" interface "Sequoia S-1000",
which is found on the Spea Media FX sound card. I still need feedback about
this, or such a card. Anyways, the procedure "boot DOS and wait until
CONFIG.SYS is done, then use CTL-ALT-DEL to boot Linux" should make it
work.
This driver will work with the soundcard interfaces (SB Pro, SB 16, Galaxy,
SoundFX, Mozart, ...) and with the "no-sound" cards (Panasonic CI-101P,
LaserMate, WDH-7001C, Longshine LCS-6853, TEAC ...).
It finally works now with the "configurable" interface "Sequoia S-1000", too,
which is found on the Spea Media FX and Ensonic Soundscape sound cards. You
have to specify the type "SBPRO 2" and the true CDROM port address with it,
not the "configuration port" address.
If you have a sound card which needs a "configuration driver" instead of
jumpers for interface types and addresses (like Mozart cards) - those
drivers get invoked before the DOS CDROM driver in your CONFIG.SYS, typical
names are "cdsetup.sys" and "mztinit.sys" -, let the sound driver do the
CDROM port configuration (the leading comments within
linux/drivers/sound/mad16.c are just for you!). Hannu Savolainen's mad16.c
code is able to set up my Mozart card - I simply had to add
#define MAD16_CONF 0x06
#define MAD16_CDSEL 0x03
to configure the CDROM interface for type "Panasonic" (LaserMate) and address
0x340.
The interface type has to get configured in /usr/include/linux/sbpcd.h,
because the behavior of some sound card interfaces is different.
because the register layout is different between the "SoundBlaster" and the
"LaserMate" type.
With some TEAC drives I have seen interface cards which seem to lack the
"drive select" lines; always drive 0 gets addressed. To avoid "mirror drives"
with such interface cards, set MAX_DRIVES to 1 and jumper your drive to ID 0.
I got a report that the TEAC interface card "I/F E117098" is of type
"SoundBlaster" (i.e. you have to set SBPRO to 1) even with the addresses
0x300 and above. This is unusual, and it can't get covered by the auto
probing scheme.
If auto-probing found the drive, the address is correct. The reported type
may be wrong. A "mount" will give success only if the interface type is set
right. Playing audio should work with a wrong set interface type, too.
With some TEAC and some CD200 drives I have seen interface cards which seem
to lack the "drive select" lines; always drive 0 gets addressed. To avoid
"mirror drives" (four drives detected where you only have one) with such
interface cards, set MAX_DRIVES to 1 and jumper your drive to ID 0 (if
possible).
The driver respects all known drive firmware releases - my old drive is a 2.11,
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
......@@ -104,13 +156,15 @@ 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, 300 kB/sec with
double-speed drives, and about 500 kB/sec with quad speed drives.
The transfer rate will reach 150 kB/sec with CR-52x drives, 300 kB/sec with
CR-56x drives, and currently not more than 500 kB/sec (usually less than
250 kB/sec) with the TEAC 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 release consists of
- this README file
- the driver file linux/drivers/block/sbpcd.c
- the stub files linux/drivers/block/sbpcd[234].c
- the header file linux/include/linux/sbpcd.h.
......@@ -119,21 +173,27 @@ To install:
1. Setup your hardware parameters. Though the driver does "auto-probing" at a
lot of (not all possible!) addresses, this step is recommended for
every-day use.
every-day use. You should let sbpcd auto-probe once and use the reported
address if a drive got found. The reported type may be incorrect; it is
correct if you can mount a data CD. There is no choice for you with the
type; only one is the right, the others are deadly wrong.
a. Go into /usr/src/linux/include/linux/sbpcd.h and configure it for your
hardware (near the beginning):
a1. Set it up for the appropriate type of interface board.
"Original" CreativeLabs sound cards need "SBPRO 1".
Most "compatible" sound cards (for example "Highscreen", "SoundFX"
and "Galaxy") need "SBPRO 0".
Most "compatible" sound cards (almost all "non-CreativeLabs" cards)
need "SBPRO 0".
The "no-sound" board from OmniCd needs the "SBPRO 1" setup.
All other "no-sound" boards need the "SBPRO 0" setup.
Possibly some TEAC "no-sound" boards need the "SBPRO 1" setup.
The Spea Media FX sound card needs "SBPRO 2".
sbpcd.c holds some examples in its auto-probe list.
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.
a3. If 4 drives get found, but you have only one, set MAX_DRIVES to 1.
a4. 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
......@@ -142,16 +202,23 @@ To install:
or
sbpcd=0x330,SPEA
This is especially useful if you install a fresh distribution.
If the second parameter is a number, it gets taken as the type
setting; 0 is "LaserMate", 1 is "SoundBlaster".
So, for example
sbpcd=0x230,1
is equivalent to
sbpcd=0x230,SoundBlaster
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
second, third, or fourth controller installed, do not say "y" to the
secondary Matsushita CD-ROM questions.
SCSI and/or SCSI CD-ROM support is not needed.
3. Then do a "make dep", then make the kernel image ("make zlilo" or else).
4. Make the device file(s). The driver uses definitely and exclusive the
MAJOR 25, so do
4. Make the device file(s). This step usually already has been done by the
MAKEDEV script.
The driver uses MAJOR 25, so, if necessary, do
mknod /dev/sbpcd b 25 0 (if you have only one drive)
and/or
mknod /dev/sbpcd0 b 25 0
......@@ -160,10 +227,8 @@ To install:
mknod /dev/sbpcd3 b 25 3
to make the node(s).
The driver no longer uses the "AT bus style" device numbering; the SCSI
scheme is used now; that means, the "first found" drive gets MINOR 0
(regardless to its jumpered ID), the "next found" (at the same cable)
gets MINOR 1, ...
The "first found" drive gets MINOR 0 (regardless to its jumpered ID), the
"next found" (at the same cable) gets MINOR 1, ...
For a second interface board, you have to make nodes like
mknod /dev/sbpcd4 b 26 0
......@@ -179,11 +244,12 @@ To install:
You should now be able to do
mkdir /CD
and
mount -t iso9660 -o ro /dev/sbpcd /CD
mount -rt iso9660 /dev/sbpcd /CD
or
mount -t iso9660 -o ro,block=2048 /dev/sbpcd /CD
and see the contents of your CD in the /CD directory, and/or hear music with
"workman -c /dev/sbpcd &".
mount -rt iso9660 -o block=2048 /dev/sbpcd /CD
and see the contents of your CD in the /CD directory.
To use audio CDs, a mounting is not recommended (and it would fail if the
first track is not a data track).
Using sbpcd as a "loadable module":
......@@ -214,6 +280,8 @@ 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").
Don't forget to reflect what you do; enabling all DBG_xxx switches at once
may crash your system.
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
......@@ -225,13 +293,13 @@ distribution) which MUST get handled with a block_size of 1024. Generally,
one can say all the CDs which hold files of the name YMTRANS.TBL are defective;
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.
Within sbpcd.h, you will find some "#define"s (f.e. EJECT and JUKEBOX). With
that, you can configure the driver for some special things.
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
There is an 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
"cdtester" program illustrates how to call it.
......@@ -284,8 +352,8 @@ If your I/O port address is not 0x340, you have to look for the #defines near
the beginning of sbpcd.h and configure them: set SBPRO to 0 or 1 or 2, and
change CDROM_PORT to the address of your CDROM I/O port.
Most of the "SoundBlaster compatible" cards behave like the no-sound
interfaces!
Almost all of the "SoundBlaster compatible" cards behave like the no-sound
interfaces, i.e. need SBPRO 0!
With "original" SB Pro cards, an initial setting of CD_volume through the
sound cards MIXER register gets done.
......@@ -790,6 +858,21 @@ main(int argc, char *argv[])
rc=ioctl(drive,CDROMPLAYMSF,&msf);
if (rc<0) printf("CDROMPLAYMSF: rc=%d.\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;
#ifdef AZT_PRIVATE_IOCTLS /*not supported by every CDROM driver*/
case 'd':
printf("Address (min:sec:frm) ");
......@@ -955,21 +1038,6 @@ main(int argc, char *argv[])
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);
......@@ -978,20 +1046,4 @@ main(int argc, char *argv[])
}
}
/*==========================================================================*/
/*
* 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:
*/
......@@ -10,9 +10,9 @@
* detailed bug reports).
* Also for the TEAC CD-55A drive.
* Not for Sanyo drives (but sjcd is there...).
* Not for Funai drives.
* Not for any other Funai drives than E2550UA (="CD200" with "F").
*
* NOTE: This is release 3.8.
* NOTE: This is release 3.9.
*
* VERSION HISTORY
*
......@@ -217,12 +217,19 @@
*
* 3.8 Elongated max_latency for CR-56x drives.
*
* 3.9 Finally fixed the long-known SoundScape/SPEA/Sequoia S-1000 interface
* configuration bug.
* Now Corey, Heiko, Ken, Leo, Vadim/Eric & Werner are invited to copy
* the config_spea() routine into their drivers. ;-)
*
*
* TODO
*
* disk change detection
* allow & synchronize multi-activity
* synchronize multi-activity
* (data + audio + ioctl + disk change, multiple drives)
* implement "read all subchannel data" (96 bytes per frame)
* check if CDROMPLAYMSF can cause a hang
*
* special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine
* elaborated speed-up experiments (and the fabulous results!), for
......@@ -298,7 +305,7 @@ char kernel_version[]=UTS_RELEASE;
#include "blk.h"
#define VERSION "v3.8 Eberhard Moenkeberg <emoenke@gwdg.de>"
#define VERSION "v3.9 Eberhard Moenkeberg <emoenke@gwdg.de>"
/*==========================================================================*/
/*
......@@ -364,9 +371,9 @@ static int sbpcd[] =
0x270, 1, /* Soundblaster 16 */
0x670, 0, /* "sound card #9" */
0x690, 0, /* "sound card #9" */
0x330, 2, /* SPEA Media FX (default) */
0x320, 2, /* SPEA Media FX */
0x340, 2, /* SPEA Media FX */
0x338, 2, /* SPEA Media FX, Ensonic SoundScape (default) */
0x328, 2, /* SPEA Media FX */
0x348, 2, /* SPEA Media FX */
0x634, 0, /* some newer sound cards */
0x638, 0, /* some newer sound cards */
0x230, 1, /* some newer sound cards */
......@@ -380,7 +387,7 @@ static int sbpcd[] =
*/
0x330, 0, /* Lasermate, CI-101P, WDH-7001C */
0x350, 0, /* Lasermate, CI-101P */
0x350, 2, /* SPEA Media FX */
0x358, 2, /* SPEA Media FX */
0x370, 0, /* Lasermate, CI-101P */
0x290, 1, /* Soundblaster 16 */
0x310, 0, /* Lasermate, CI-101P, WDH-7001C */
......@@ -499,6 +506,8 @@ static const char *str_sb_l = "soundblaster";
static const char *str_lm = "LaserMate";
static const char *str_sp = "SPEA";
static const char *str_sp_l = "spea";
static const char *str_ss = "SoundScape";
static const char *str_ss_l = "soundscape";
const char *type;
#if !(SBPCD_ISSUE-1)
......@@ -608,6 +617,7 @@ static struct {
u_int lba_multi;
int first_session;
int last_session;
int track_of_last_session;
u_char audio_state;
u_int pos_audio_start;
......@@ -634,7 +644,6 @@ static struct {
u_char UPC_ctl_adr;
u_char UPC_buf[7];
int CDsize_blk;
int frame_size;
int CDsize_frm;
......@@ -730,20 +739,26 @@ static int sbpcd_dbg_ioctl(unsigned long arg, int level)
static void mark_timeout_delay(u_long i)
{
timed_out_delay=1;
#if 0
msg(DBG_TIM,"delay timer expired.\n");
#endif
}
/*==========================================================================*/
static void mark_timeout_data(u_long i)
{
timed_out_data=1;
#if 0
msg(DBG_TIM,"data timer expired.\n");
#endif
}
/*==========================================================================*/
#if 0
static void mark_timeout_audio(u_long i)
{
timed_out_audio=1;
#if 0
msg(DBG_TIM,"audio timer expired.\n");
#endif
}
#endif
/*==========================================================================*/
......@@ -775,7 +790,7 @@ static void sbp_sleep(u_int time)
*/
static INLINE void lba2msf(int lba, u_char *msf)
{
lba += CD_BLOCK_OFFSET;
lba += CD_MSF_OFFSET;
msf[0] = lba / (CD_SECS*CD_FRAMES);
lba %= CD_SECS*CD_FRAMES;
msf[1] = lba / CD_FRAMES;
......@@ -797,8 +812,8 @@ static INLINE u_int blk2msf(u_int blk)
u_int mm;
msf.c[3] = 0;
msf.c[2] = (blk + CD_BLOCK_OFFSET) / (CD_SECS * CD_FRAMES);
mm = (blk + CD_BLOCK_OFFSET) % (CD_SECS * CD_FRAMES);
msf.c[2] = (blk + CD_MSF_OFFSET) / (CD_SECS * CD_FRAMES);
mm = (blk + CD_MSF_OFFSET) % (CD_SECS * CD_FRAMES);
msf.c[1] = mm / CD_FRAMES;
msf.c[0] = mm % CD_FRAMES;
return (msf.n);
......@@ -835,7 +850,7 @@ static INLINE int msf2blk(int msfx)
int i;
msf.n=msfx;
i=(msf.c[2] * CD_SECS + msf.c[1]) * CD_FRAMES + msf.c[0] - CD_BLOCK_OFFSET;
i=(msf.c[2] * CD_SECS + msf.c[1]) * CD_FRAMES + msf.c[0] - CD_MSF_OFFSET;
if (i<0) return (0);
return (i);
}
......@@ -847,7 +862,7 @@ static INLINE int msf2lba(u_char *msf)
{
int i;
i=(msf[0] * CD_SECS + msf[1]) * CD_FRAMES + msf[2] - CD_BLOCK_OFFSET;
i=(msf[0] * CD_SECS + msf[1]) * CD_FRAMES + msf[2] - CD_MSF_OFFSET;
if (i<0) return (0);
return (i);
}
......@@ -928,7 +943,7 @@ static int CDi_stat_loop(void)
if (!(j&s_not_result_ready)) return (j);
if (fam0L_drive) if (j&s_attention) return (j);
}
sbp_sleep(HZ/100);
sbp_sleep(1);
i = 1;
}
#else
......@@ -950,7 +965,7 @@ static int CDi_stat_loop(void)
if (!(j&s_not_result_ready)) return (j);
if (fam0L_drive) if (j&s_attention) return (j);
}
sbp_sleep(HZ/100);
sbp_sleep(1);
i = 1;
}
#endif MODULE
......@@ -1025,7 +1040,7 @@ static int ResponseInfo(void)
if (!(st&s_not_result_ready)) break;
}
if ((j!=0)||(timeout<=jiffies)) break;
sbp_sleep(HZ/100);
sbp_sleep(1);
j = 1;
}
if (timeout<=jiffies) break;
......@@ -1181,7 +1196,7 @@ static int ResponseStatus(void)
if (!(i&s_not_result_ready)) break;
}
if ((j!=0)||(timeout<jiffies)) break;
sbp_sleep(HZ/100);
sbp_sleep(1);
j = 1;
}
while (1);
......@@ -1358,7 +1373,7 @@ static int cmd_out_T(void)
drvcmd[0]=CMDT_READ_ERR;
j=cmd_out_T(); /* !!! recursive here !!! */
--recursion;
sbp_sleep(HZ/100);
sbp_sleep(1);
}
while (j<0);
D_S[d].error_state=infobuf[2];
......@@ -1917,7 +1932,7 @@ static int DriveReset(void)
i=GetStatus();
if ((i<0)&&(i!=-615)) return (-2); /* i!=-615 is from sta2err */
if (!st_caddy_in) break;
sbp_sleep(HZ/100);
sbp_sleep(1);
}
while (!st_diskok);
#if 000
......@@ -2075,7 +2090,7 @@ static int UnLockDoor(void)
{
i=cc_LockDoor(0);
--j;
sbp_sleep(HZ/100);
sbp_sleep(1);
}
while ((i<0)&&(j));
if (i<0)
......@@ -2095,7 +2110,7 @@ static int LockDoor(void)
{
i=cc_LockDoor(1);
--j;
sbp_sleep(HZ/100);
sbp_sleep(1);
}
while ((i<0)&&(j));
if (j==0)
......@@ -2106,7 +2121,7 @@ static int LockDoor(void)
{
i=cc_LockDoor(1);
--j;
sbp_sleep(HZ/100);
sbp_sleep(1);
}
while ((i<0)&&(j));
}
......@@ -2256,12 +2271,12 @@ static int cc_ModeSense(void)
i=cmd_out();
if (i<0) return (i);
i=0;
D_S[d].sense_byte=0;
if (fam1_drive) D_S[d].sense_byte=infobuf[i++];
else if (fam0L_drive) D_S[d].sense_byte=0;
else if (famT_drive)
{
D_S[d].sense_byte=0;
if (infobuf[4]==0x01) D_S[d].xa_byte=0x20; /* wrong!!!! */
if (infobuf[4]==0x01) D_S[d].xa_byte=0x20;
else D_S[d].xa_byte=0;
i=2;
}
D_S[d].frame_size=make16(infobuf[i],infobuf[i+1]);
......@@ -2459,7 +2474,8 @@ static int cc_ReadCapacity(void)
{
int i, j;
if (famL_drive) return (0);
if (famL_drive) return (0); /* some firmware lacks this command */
if (famT_drive) return (0); /* done with cc_ReadTocDescr() */
D_S[d].diskstate_flags &= ~cd_size_bit;
for (j=3;j>0;j--)
{
......@@ -2482,31 +2498,15 @@ static int cc_ReadCapacity(void)
response_count=5;
flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
}
else if (famT_drive)
{
response_count=12;
drvcmd[0]=CMDT_DISKINFO;
drvcmd[1]=0x02;
drvcmd[6]=CDROM_LEADOUT;
drvcmd[8]=response_count;
drvcmd[9]=0x00;
}
i=cmd_out();
if (i>=0) break;
msg(DBG_000,"cc_ReadCapacity: cmd_out: err %d\n", i);
cc_ReadError();
}
if (j==0) return (i);
if (fam1_drive) D_S[d].CDsize_frm=msf2blk(make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2])))+CD_BLOCK_OFFSET;
if (fam1_drive) D_S[d].CDsize_frm=msf2blk(make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2])))+CD_MSF_OFFSET;
else if (fam0_drive) D_S[d].CDsize_frm=make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2]));
else if (fam2_drive) D_S[d].CDsize_frm=make32(make16(infobuf[0],infobuf[1]),make16(infobuf[2],infobuf[3]));
else if (famT_drive)
{
D_S[d].CDsize_frm=make32(make16(infobuf[8],infobuf[9]),make16(infobuf[10],infobuf[11]));
D_S[d].n_first_track=infobuf[2];
D_S[d].n_last_track=infobuf[3];
}
D_S[d].diskstate_flags |= cd_size_bit;
msg(DBG_000,"cc_ReadCapacity: %d frames.\n", D_S[d].CDsize_frm);
return (0);
......@@ -2605,6 +2605,7 @@ static int cc_ReadTocDescr(void)
{
D_S[d].size_msf=make32(make16(infobuf[8],infobuf[9]),make16(infobuf[10],infobuf[11]));
D_S[d].size_blk=msf2blk(D_S[d].size_msf);
D_S[d].CDsize_frm=D_S[d].size_blk+1;
D_S[d].n_first_track=infobuf[2];
D_S[d].n_last_track=infobuf[3];
}
......@@ -2759,7 +2760,7 @@ static int cc_ReadUPC(void)
D_S[d].diskstate_flags &= ~upc_bit;
#if TEST_UPC
for (block=CD_BLOCK_OFFSET+1;block<CD_BLOCK_OFFSET+200;block++)
for (block=CD_MSF_OFFSET+1;block<CD_MSF_OFFSET+200;block++)
{
#endif TEST_UPC
clr_cmdbuf();
......@@ -2888,7 +2889,14 @@ static int cc_CheckMultiSession(void)
drvcmd[9]=0x40;
i=cmd_out();
if (i<0) return (i);
D_S[d].lba_multi=msf2blk(make32(make16(0,infobuf[9]),make16(infobuf[10],infobuf[11])));
D_S[d].first_session=infobuf[2];
D_S[d].last_session=infobuf[3];
D_S[d].track_of_last_session=infobuf[6];
if (D_S[d].first_session!=D_S[d].last_session)
{
D_S[d].f_multisession=1;
D_S[d].lba_multi=msf2blk(make32(make16(0,infobuf[9]),make16(infobuf[10],infobuf[11])));
}
}
for (i=0;i<response_count;i++)
sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
......@@ -2947,7 +2955,9 @@ static void check_datarate(void)
delay_timer.expires=jiffies+11*HZ/10;
timed_out_delay=0;
add_timer(&delay_timer);
#if 0
msg(DBG_TIM,"delay timer started (11*HZ/10).\n");
#endif
do
{
i=inb(CDi_status);
......@@ -2958,7 +2968,9 @@ static void check_datarate(void)
}
while (!timed_out_delay);
del_timer(&delay_timer);
#if 0
msg(DBG_TIM,"datarate: %04X\n", datarate);
#endif
if (datarate<65536) datarate=65536;
maxtim16=datarate*16;
maxtim04=datarate*4;
......@@ -2969,8 +2981,9 @@ static void check_datarate(void)
#else
maxtim_data=datarate/300;
#endif LONG_TIMING
msg(DBG_TIM,"maxtim_8 %d, maxtim_data %d.\n",
maxtim_8, maxtim_data);
#if 0
msg(DBG_TIM,"maxtim_8 %d, maxtim_data %d.\n", maxtim_8, maxtim_data);
#endif
}
/*==========================================================================*/
#if 0
......@@ -3263,14 +3276,14 @@ static int check_version(void)
else
{
D_S[d].drv_type=drv_100;
if ((j!=500)||(j!=102)) ask_mail();
if ((j!=500)&&(j!=102)) ask_mail();
}
}
else if (fam2_drive)
{
msg(DBG_INF,"new drive CD200 (%s)detected.\n", D_S[d].firmware_version);
msg(DBG_INF,"support is not fulfilled yet - audio should work.\n");
if ((j!=101)&&(j!=35)) ask_mail(); /* only 1.01 and 0.35 known at time */
msg(DBG_INF,"CD200 is not fully supported yet - CD200F should work.\n");
if ((j!=1)&&(j!=101)&&(j!=35)) ask_mail(); /* unknown version at time */
}
}
msg(DBG_LCS,"drive type %02X\n",D_S[d].drv_type);
......@@ -3654,7 +3667,7 @@ static int DiskInfo(void)
if ((fam0L_drive) && (D_S[d].xa_byte==0x20))
{
/* XA disk with old drive */
cc_ModeSelect(CD_FRAMESIZE_XA);
cc_ModeSelect(CD_FRAMESIZE_RAW1);
cc_ModeSense();
}
if (famT_drive) cc_prep_mode_T();
......@@ -4081,7 +4094,7 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
case CDROMREADMODE2: /* not usable at the moment */
msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n");
cc_ModeSelect(CD_FRAMESIZE_XA);
cc_ModeSelect(CD_FRAMESIZE_RAW1);
cc_ModeSense();
D_S[d].mode=READ_M2;
return (0);
......@@ -4156,7 +4169,7 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
flags_cmd_out |= f_respo3;
cc_ReadStatus();
if (sbp_status() != 0) break;
sbp_sleep(HZ/100); /* wait a bit, try again */
sbp_sleep(1); /* wait a bit, try again */
}
if (status_tries == 0)
{
......@@ -4211,7 +4224,7 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
if (try != 0 || timeout <= jiffies) break;
if (data_retrying == 0) data_waits++;
data_retrying = 1;
sbp_sleep(HZ/100);
sbp_sleep(1);
try = 1;
}
if (try==0)
......@@ -4971,12 +4984,15 @@ static struct file_operations sbpcd_fops =
* or
* sbpcd=0x300,LaserMate
* or
* sbpcd=0x330,SPEA
* sbpcd=0x330,SoundScape
*
* (upper/lower case sensitive here!!!).
* (upper/lower case sensitive here - but all-lowercase is ok!!!).
*
* the address value has to be the TRUE CDROM PORT ADDRESS -
* the address value has to be the CDROM PORT ADDRESS -
* not the soundcard base address.
* For the SPEA/SoundScape setup, DO NOT specify the "configuration port"
* address, but the address which is really used for the CDROM (usually 8
* bytes above).
*
*/
#if (SBPCD_ISSUE-1)
......@@ -4986,11 +5002,14 @@ void sbpcd_setup(const char *s, int *p)
{
setup_done++;
msg(DBG_INI,"sbpcd_setup called with %04X,%s\n",p[1], s);
sbpro_type=0;
sbpro_type=0; /* default: "LaserMate" */
if (p[0]>1) sbpro_type=p[2];
if (!strcmp(s,str_sb)) sbpro_type=1;
else if (!strcmp(s,str_sb_l)) sbpro_type=1;
else if (!strcmp(s,str_sp)) sbpro_type=2;
else if (!strcmp(s,str_sp_l)) sbpro_type=2;
else if (!strcmp(s,str_ss)) sbpro_type=2;
else if (!strcmp(s,str_ss_l)) sbpro_type=2;
if (p[0]>0) sbpcd_ioaddr=p[1];
CDo_command=sbpcd_ioaddr;
......@@ -5010,24 +5029,32 @@ void sbpcd_setup(const char *s, int *p)
/*==========================================================================*/
/*
* Sequoia S-1000 CD-ROM Interface Configuration
* as used within SPEA Media FX card
* The SPEA soundcard has to get configured for
* -> interface type "Matsushita/Panasonic" (not Sony or Mitsumi)
* -> I/O base address (0x320, 0x330, 0x340, 0x350)
* as used within SPEA Media FX, Ensonic SoundScape and some Reveal cards
* The soundcard has to get jumpered for the interface type "Panasonic"
* (not Sony or Mitsumi) and to get soft-configured for
* -> configuration port address
* -> CDROM port offset (num_ports): has to be 8 here. Possibly this
* offset value determines the interface type (none, Panasonic,
* Mitsumi, Sony).
* The interface uses a configuration port (0x320, 0x330, 0x340, 0x350)
* some bytes below the real CDROM address.
*
* For the Panasonic style (LaserMate) interface and the configuration
* port 0x330, we have to use an offset of 8; so, the real CDROM port
* address is 0x338.
*/
static int config_spea(void)
{
int n_ports=0x10; /* 2:0x00, 8:0x10, 16:0x20, 32:0x30 */
/* What is n_ports? Number of addresses or base address offset? */
int irq_number=0; /* 2:0x01, 7:0x03, 12:0x05, 15:0x07, OFF:0x00 */
int dma_channel=0; /* 0:0x08, 1:0x18, 3:0x38, 5:0x58, 6:0x68, 7:0x78, OFF: 0x00 */
/* base address offset between configuration port and CDROM port */
int irq_number=0; /* off:0x00, 2:0x01, 7:0x03, 12:0x05, 15:0x07 */
int dma_channel=0; /* off: 0x00, 0:0x08, 1:0x18, 3:0x38, 5:0x58, 6:0x68 */
int dack_polarity=0; /* L:0x00, H:0x80 */
int drq_polarity=0x40; /* L:0x00, H:0x40 */
int i;
#define SPEA_REG_1 sbpcd_ioaddr+4
#define SPEA_REG_2 sbpcd_ioaddr+5
#define SPEA_REG_1 sbpcd_ioaddr-0x08+4
#define SPEA_REG_2 sbpcd_ioaddr-0x08+5
OUT(SPEA_REG_1,0xFF);
i=inb(SPEA_REG_1);
......@@ -5056,7 +5083,7 @@ static int config_spea(void)
OUT(SPEA_REG_2,i);
sbpro_type = 0; /* acts like a LaserMate interface now */
msg(DBG_SEQ,"found SPEA interface at %04X.\n", sbpcd_ioaddr);
msg(DBG_SEQ,"found SoundScape interface at %04X.\n", sbpcd_ioaddr);
return (0);
}
/*==========================================================================*/
......@@ -5080,18 +5107,18 @@ int init_module(void)
#if DISTRIBUTION
if (!setup_done)
{
msg(DBG_INF,"Looking for Matsushita/Panasonic, CreativeLabs, IBM, Longshine, TEAC CD-ROM drives\n");
msg(DBG_INF,"\n= = = = = = = = = = W A R N I N G = = = = = = = = = =\n");
msg(DBG_INF,"Auto-Probing can cause a hang (f.e. touching an ethernet card).\n");
msg(DBG_INF,"Looking for Matsushita/Panasonic, CreativeLabs, Longshine, TEAC CD-ROM drives\n");
msg(DBG_INF,"= = = = = = = = = = W A R N I N G = = = = = = = = = =\n");
msg(DBG_INF,"Auto-Probing can cause a hang (f.e. touching an NE2000 card).\n");
msg(DBG_INF,"If that happens, you have to reboot and use the\n");
msg(DBG_INF,"LILO (kernel) command line feature like:\n");
msg(DBG_INF," LILO boot: ... sbpcd=0x230,SoundBlaster\n");
msg(DBG_INF,"or like:\n");
msg(DBG_INF," LILO boot: ... sbpcd=0x300,LaserMate\n");
msg(DBG_INF,"or like:\n");
msg(DBG_INF," LILO boot: ... sbpcd=0x330,SPEA\n");
msg(DBG_INF," LILO boot: ... sbpcd=0x338,SoundScape\n");
msg(DBG_INF,"with your REAL address.\n");
msg(DBG_INF,"= = = = = = = = = = END of WARNING = = = = = = = = = =\n\n");
msg(DBG_INF,"= = = = = = = = = = END of WARNING = = = = = == = = =\n");
}
#endif DISTRIBUTION
sbpcd[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */
......
......@@ -24,6 +24,22 @@ ifdef CONFIG_CYCLADES
L_OBJS += cyclades.o
endif
ifeq ($(CONFIG_STALLION),y)
L_OBJS += stallion.o
else
ifeq ($(CONFIG_STALLION),m)
M_OBJS += stallion.o
endif
endif
ifeq ($(CONFIG_ISTALLION),y)
L_OBJS += istallion.o
else
ifeq ($(CONFIG_ISTALLION),m)
M_OBJS += istallion.o
endif
endif
ifeq ($(CONFIG_ATIXL_BUSMOUSE),y)
M = y
L_OBJS += atixlmouse.o
......
......@@ -22,14 +22,13 @@
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/mouse.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/irq.h>
#include "mouse.h"
#define ATIXL_MOUSE_IRQ 5 /* H/W interrupt # set up on ATIXL board */
#define ATIXL_BUSMOUSE 3 /* Minor device # (mknod c 10 3 /dev/bm) */
......
......@@ -42,6 +42,7 @@
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/mouse.h>
#include <asm/io.h>
#include <asm/segment.h>
......@@ -243,7 +244,7 @@ struct file_operations bus_mouse_fops = {
fasync_mouse,
};
static struct mouse bus_mous = {
static struct mouse bus_mouse = {
LOGITECH_BUSMOUSE, "busmouse", &bus_mouse_fops
};
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -32,8 +32,6 @@
#include <linux/major.h>
#include <linux/malloc.h>
#include "mouse.h"
/*
* Head entry for the doubly linked mouse list
*/
......
#ifndef __MOUSE_H
#define __MOUSE_H
struct mouse {
int minor;
const char *name;
struct file_operations *fops;
struct mouse * next, * prev;
};
extern int mouse_register(struct mouse * mouse);
extern int mouse_deregister(struct mouse * mouse);
#endif
......@@ -43,6 +43,7 @@
#include <linux/busmouse.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/mouse.h>
#include <asm/io.h>
#include <asm/segment.h>
......
......@@ -45,6 +45,7 @@
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/malloc.h>
#include <linux/mouse.h>
#include <asm/io.h>
#include <asm/segment.h>
......@@ -52,8 +53,6 @@
#include <linux/config.h>
#include "mouse.h"
#define PSMOUSE_MINOR 1 /* minor device # for this mouse */
/* aux controller ports */
......
/*****************************************************************************/
/*
* stallion.c -- stallion multiport serial driver.
*
* Copyright (C) 1994,1995 Greg Ungerer (gerg@stallion.oz.au).
*
* This code is loosely based on the Linux serial driver, written by
* Linus Torvalds, Theodore T'so and others.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*****************************************************************************/
#ifdef MODULE
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#endif
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/interrupt.h>
#include <linux/termios.h>
#include <linux/fcntl.h>
#include <linux/tty_driver.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/cd1400.h>
#include <linux/string.h>
#include <linux/malloc.h>
#include <linux/ioport.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
#ifdef CONFIG_PCI
#include <linux/pci.h>
#include <linux/bios32.h>
#endif
/*****************************************************************************/
/*
* Define different board types. At the moment I have only declared
* those boards that this driver supports. But I will use the standard
* "assigned" board numbers. In the future this driver will support
* some of the other Stallion boards. Currently supported boards are
* abbreviated as EIO = EasyIO and ECH = EasyConnection 8/32.
*/
#define BRD_EASYIO 20
#define BRD_ECH 21
#define BRD_ECHMC 22
#define BRD_ECHPCI 26
/*
* Define a configuration structure to hold the board configuration.
* Need to set this up in the code (for now) with the boards that are
* to be configured into the system. This is what needs to be modified
* when adding/removing/modifying boards. Each line entry in the
* stl_brdconf[] array is a board. Each line contains io/irq/memory
* ranges for that board (as well as what type of board it is).
* Some examples:
* { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 }
* This line would configure an EasyIO board (4 or 8, no difference),
* at io addres 2a0 and irq 10.
* Another example:
* { BRD_ECH, 0x2a8, 0x280, 0, 12, 0 },
* This line will configure an EasyConnection 8/32 board at primary io
* addres 2a8, secondary io address 280 and irq 12.
* Enter as many lines into this array as you want (only the first 4
* will actually be used!). Any combination of EasyIO and EasyConnection
* boards can be specified. EasyConnection 8/32 boards can share their
* secondary io addresses between each other.
*
* NOTE: there is no need to put any entries in this table for PCI
* boards. They will be found automatically by the driver - provided
* PCI BIOS32 support is compiled into the kernel.
*/
typedef struct {
int brdtype;
int ioaddr1;
int ioaddr2;
unsigned long memaddr;
int irq;
int irqtype;
} stlconf_t;
static stlconf_t stl_brdconf[] = {
{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },
};
static int stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t);
/*****************************************************************************/
/*
* Define some important driver characteristics. Device major numbers
* allocated as per Linux Device Registery.
*/
#ifndef STL_SERIALMAJOR
#define STL_SERIALMAJOR 24
#endif
#ifndef STL_CALLOUTMAJOR
#define STL_CALLOUTMAJOR 25
#endif
#define STL_DRVTYPSERIAL 1
#define STL_DRVTYPCALLOUT 2
#define STL_MAXBRDS 4
#define STL_MAXPANELS 4
#define STL_PORTSPERPANEL 16
#define STL_MAXPORTS 64
#define STL_MAXDEVS (STL_MAXBRDS * STL_MAXPORTS)
/*
* I haven't really decided (or measured) what TX buffer size gives
* a good balance between performance and memory usage. These seem
* to work pretty well...
*/
#define STL_TXBUFLOW 256
#define STL_TXBUFSIZE 2048
/*****************************************************************************/
/*
* Define our local driver identity first. Set up stuff to deal with
* all the local structures required by a serial tty driver.
*/
static char *stl_drvname = "Stallion Multiport Serial Driver";
static char *stl_drvversion = "1.0.0";
static char *stl_serialname = "ttyE";
static char *stl_calloutname = "cue";
static struct tty_driver stl_serial;
static struct tty_driver stl_callout;
static struct tty_struct *stl_ttys[STL_MAXDEVS];
static struct termios *stl_termios[STL_MAXDEVS];
static struct termios *stl_termioslocked[STL_MAXDEVS];
static int stl_refcount = 0;
/*
* We will need to allocate a temporary write buffer for chars that
* come direct from user space. The problem is that a copy from user
* space might cause a page fault (typically on a system that is
* swapping!). All ports will share one buffer - since if the system
* is already swapping a shared buffer won't make things any worse.
*/
static char *stl_tmpwritebuf;
static struct semaphore stl_tmpwritesem = MUTEX;
/*
* Define a local default termios struct. All ports will be created
* with this termios initially. Basically all it defines is a raw port
* at 9600, 8 data bits, 1 stop bit.
*/
static struct termios stl_deftermios = {
0,
0,
(B9600 | CS8 | CREAD | HUPCL | CLOCAL),
0,
0,
INIT_C_CC
};
/*
* Keep track of what interrupts we have requested for us.
* We don't need to request an interrupt twice if it is being
* shared with another Stallion board.
*/
static int stl_gotintrs[STL_MAXBRDS];
static int stl_numintrs = 0;
/*****************************************************************************/
/*
* Define a set of structures to hold all the board/panel/port info
* for our ports. These will be dynamically allocated as required.
*/
/*
* Define a ring queue structure for each port. This will hold the
* TX data waiting to be output. Characters are fed into this buffer
* from the line discipline (or even direct from user space!) and
* then fed into the UARTs during interrupts. Will use a clasic ring
* queue here for this. The good thing about this type of ring queue
* is that the head and tail pointers can be updated without interrupt
* protection - since "write" code only needs to change the head, and
* interrupt code only needs to change the tail.
*/
typedef struct {
char *buf;
char *head;
char *tail;
} stlrq_t;
/*
* Port, panel and board structures to hold status info about each.
* The board structure contains pointers to structures for each panel
* connected to it, and in turn each panel structure contains pointers
* for each port structure for each port on that panel. Note that
* the port structure also contains the board and panel number that it
* is associated with, this makes it (fairly) easy to get back to the
* board/panel info for a port.
*/
typedef struct {
int portnr;
int panelnr;
int brdnr;
int ioaddr;
int uartaddr;
int pagenr;
int istate;
int flags;
int baud_base;
int custom_divisor;
int close_delay;
int closing_wait;
int refcount;
int openwaitcnt;
int brklen;
long session;
long pgrp;
unsigned int sigs;
unsigned int rxignoremsk;
unsigned int rxmarkmsk;
struct tty_struct *tty;
struct wait_queue *open_wait;
struct wait_queue *close_wait;
struct termios normaltermios;
struct termios callouttermios;
struct tq_struct tqueue;
stlrq_t tx;
} stlport_t;
typedef struct {
int panelnr;
int brdnr;
int pagenr;
int nrports;
int iobase;
unsigned int ackmask;
stlport_t *ports[STL_PORTSPERPANEL];
} stlpanel_t;
typedef struct {
int brdnr;
int brdtype;
int state;
int nrpanels;
int nrports;
int irq;
int irqtype;
unsigned int ioaddr1;
unsigned int ioaddr2;
unsigned int iostatus;
unsigned int ioctrl;
unsigned int ioctrlval;
stlpanel_t *panels[STL_MAXPANELS];
} stlbrd_t;
static stlbrd_t *stl_brds[STL_MAXBRDS];
/*
* Per board state flags. Used with the state field of the board struct.
* Not really much here yet!
*/
#define BRD_FOUND 0x1
/*
* Define the port structure istate flags. These set of flags are
* modified at interrupt time - so setting and reseting them needs
* to be atomic. Use the bit clear/setting routines for this.
*/
#define ASYI_TXBUSY 1
#define ASYI_TXLOW 2
#define ASYI_DCDCHANGE 3
/*
* Define an array of board names as printable strings. Handy for
* referencing boards when printing trace and stuff.
*/
static char *stl_brdnames[] = {
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
(char *) NULL,
"EasyIO",
"EC8/32-AT",
"EC8/32-MC",
(char *) NULL,
(char *) NULL,
(char *) NULL,
"EC8/32-PCI",
};
/*****************************************************************************/
/*
* Hardware ID bits for the EasyIO and ECH boards. These defines apply
* to the directly accessable io ports of these boards (not the cd1400
* uarts - they are in cd1400.h).
*/
#define EIO_8PORTRS 0x04
#define EIO_4PORTRS 0x05
#define EIO_8PORTDI 0x00
#define EIO_8PORTM 0x06
#define EIO_IDBITMASK 0x07
#define EIO_INTRPEND 0x08
#define EIO_INTEDGE 0x00
#define EIO_INTLEVEL 0x08
#define ECH_ID 0xa0
#define ECH_IDBITMASK 0xe0
#define ECH_BRDENABLE 0x08
#define ECH_BRDDISABLE 0x00
#define ECH_INTENABLE 0x01
#define ECH_INTDISABLE 0x00
#define ECH_INTLEVEL 0x02
#define ECH_INTEDGE 0x00
#define ECH_INTRPEND 0x01
#define ECH_BRDRESET 0x01
#define ECHMC_INTENABLE 0x01
#define ECHMC_BRDRESET 0x02
#define ECH_PNLSTATUS 2
#define ECH_PNL16PORT 0x20
#define ECH_PNLIDMASK 0x07
#define ECH_PNLINTRPEND 0x80
#define ECH_ADDR2MASK 0x1e0
/*
* Define the offsets within the register bank for all io registers.
* These io address offsets are common to both the EIO and ECH.
*/
#define EREG_ADDR 0
#define EREG_DATA 4
#define EREG_RXACK 5
#define EREG_TXACK 6
#define EREG_MDACK 7
#define EREG_BANKSIZE 8
/*
* Define the vector mapping bits for the programmable interrupt board
* hardware. These bits encode the interrupt for the board to use - it
* is software selectable (except the EIO-8M).
*/
static unsigned char stl_vecmap[] = {
0xff, 0xff, 0xff, 0x04, 0x06, 0x05, 0xff, 0x07,
0xff, 0xff, 0x00, 0x02, 0x01, 0xff, 0xff, 0x03
};
/*
* Set up enable and disable macros for the ECH boards. They require
* the secondary io address space to be activated and deactivated.
* This way all ECH boards can share their secondary io region.
* If this is an ECH-PCI board then also need to set the page pointer
* to point to the correct page.
*/
#define BRDENABLE(brdnr,pagenr) \
if (stl_brds[(brdnr)]->brdtype == BRD_ECH) \
outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDENABLE), \
stl_brds[(brdnr)]->ioctrl); \
else if (stl_brds[(brdnr)]->brdtype == BRD_ECHPCI) \
outb((pagenr), stl_brds[(brdnr)]->ioctrl);
#define BRDDISABLE(brdnr) \
if (stl_brds[(brdnr)]->brdtype == BRD_ECH) \
outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDDISABLE), \
stl_brds[(brdnr)]->ioctrl);
/*
* Define the cd1400 baud rate clocks. These are used when calculating
* what clock and divisor to use for the required baud rate. Also
* define the maximum baud rate allowed, and the default base baud.
*/
static int stl_cd1400clkdivs[] = {
CD1400_CLK0, CD1400_CLK1, CD1400_CLK2, CD1400_CLK3, CD1400_CLK4
};
#define STL_MAXBAUD 230400
#define STL_BAUDBASE 115200
#define STL_CLOSEDELAY 50
/*****************************************************************************/
/*
* Define macros to extract a brd/port number from a minor number.
*/
#define MKDEV2BRD(min) (((min) & 0xc0) >> 6)
#define MKDEV2PORT(min) ((min) & 0x3f)
/*
* Define a baud rate table that converts termios baud rate selector
* into the actual baud rate value. All baud rate calculates are based
* on the actual baud rate required.
*/
static unsigned int stl_baudrates[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
9600, 19200, 38400, 57600, 115200, 230400
};
/*****************************************************************************/
/*
* Memory allocation vars. These keep track of what memory allocation
* we can currently use. They help deal with memory in a consistent
* way, whether during init or run-time.
*/
static int stl_meminited = 0;
static long stl_memend;
/*****************************************************************************/
/*
* Define some handy local macros...
*/
#ifndef MIN
#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
#endif
/*****************************************************************************/
/*
* Declare all those functions in this driver!
*/
#ifdef MODULE
int init_module(void);
void cleanup_module(void);
#else
static void stl_meminit(long base);
static long stl_memhalt(void);
#endif
static void *stl_memalloc(int len);
long stl_init(long kmem_start);
static int stl_open(struct tty_struct *tty, struct file *filp);
static void stl_close(struct tty_struct *tty, struct file *filp);
static int stl_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
static void stl_putchar(struct tty_struct *tty, unsigned char ch);
static void stl_flushchars(struct tty_struct *tty);
static int stl_writeroom(struct tty_struct *tty);
static int stl_charsinbuffer(struct tty_struct *tty);
static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
static void stl_settermios(struct tty_struct *tty, struct termios *old);
static void stl_throttle(struct tty_struct *tty);
static void stl_unthrottle(struct tty_struct *tty);
static void stl_stop(struct tty_struct *tty);
static void stl_start(struct tty_struct *tty);
static void stl_flushbuffer(struct tty_struct *tty);
static void stl_hangup(struct tty_struct *tty);
static int stl_initbrds(void);
static int stl_brdinit(stlbrd_t *brdp);
static int stl_initeio(stlbrd_t *brdp);
static int stl_initech(stlbrd_t *brdp);
static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp);
static int stl_mapirq(int irq);
static void stl_getserial(stlport_t *portp, struct serial_struct *sp);
static int stl_setserial(stlport_t *portp, struct serial_struct *sp);
static void stl_setreg(stlport_t *portp, int regnr, int value);
static int stl_getreg(stlport_t *portp, int regnr);
static int stl_updatereg(stlport_t *portp, int regnr, int value);
static void stl_setport(stlport_t *portp, struct termios *tiosp);
static void stl_getsignals(stlport_t *portp);
static void stl_setsignals(stlport_t *portp, int dtr, int rts);
static void stl_ccrwait(stlport_t *portp);
static void stl_enablerxtx(stlport_t *portp, int rx, int tx);
static void stl_startrxtx(stlport_t *portp, int rx, int tx);
static void stl_disableintrs(stlport_t *portp);
static void stl_sendbreak(stlport_t *portp, long len);
static int stl_waitcarrier(stlport_t *portp, struct file *filp);
static void stl_delay(int len);
static void stl_intr(int irq, struct pt_regs *regs);
static void stl_offintr(void *private);
#ifdef CONFIG_PCI
static int stl_findpcibrds(void);
#endif
/*****************************************************************************/
#ifdef MODULE
/*
* Use the kernel version number for modules.
*/
char kernel_version[] = UTS_RELEASE;
int init_module()
{
unsigned long flags;
#if DEBUG
printk("init_module()\n");
#endif
save_flags(flags);
cli();
stl_init(0);
restore_flags(flags);
return(0);
}
/*****************************************************************************/
void cleanup_module()
{
stlbrd_t *brdp;
stlpanel_t *panelp;
stlport_t *portp;
unsigned long flags;
int i, j, k;
#if DEBUG
printk("cleanup_module()\n");
#endif
printk("Unloading %s: version %s\n", stl_drvname, stl_drvversion);
save_flags(flags);
cli();
/*
* Free up all allocated resources used by the ports. This includes
* memory and interrupts. As part of this process we will also do
* a hangup on every open port - to try and flush out any processes
* hanging onto ports.
*/
i = tty_unregister_driver(&stl_serial);
j = tty_unregister_driver(&stl_callout);
if (i || j) {
printk("STALLION: failed to un-register tty driver, errno=%d,%d\n", -i, -j);
restore_flags(flags);
return;
}
if (stl_tmpwritebuf != (char *) NULL)
kfree_s(stl_tmpwritebuf, STL_TXBUFSIZE);
for (i = 0; (i < stl_nrbrds); i++) {
brdp = stl_brds[i];
for (j = 0; (j < STL_MAXPANELS); j++) {
panelp = brdp->panels[j];
if (panelp != (stlpanel_t *) NULL) {
for (k = 0; (k < STL_PORTSPERPANEL); k++) {
portp = panelp->ports[k];
if (portp != (stlport_t *) NULL) {
if (portp->tty != (struct tty_struct *) NULL)
stl_hangup(portp->tty);
if (portp->tx.buf != (char *) NULL)
kfree_s(portp->tx.buf, STL_TXBUFSIZE);
kfree_s(portp, sizeof(stlport_t));
}
}
kfree_s(panelp, sizeof(stlpanel_t));
}
}
if (brdp->brdtype == BRD_ECH) {
release_region(brdp->ioaddr1, 2);
release_region(brdp->ioaddr2, 32);
} else if (brdp->brdtype == BRD_ECHPCI) {
release_region(brdp->ioaddr1, 4);
release_region(brdp->ioaddr2, 8);
} else if (brdp->brdtype == BRD_ECHMC) {
release_region(brdp->ioaddr1, 64);
} else if (brdp->brdtype == BRD_EASYIO) {
release_region(brdp->ioaddr1, 8);
}
kfree_s(brdp, sizeof(stlbrd_t));
stl_brds[i] = (stlbrd_t *) NULL;
}
for (i = 0; (i < stl_numintrs); i++)
free_irq(stl_gotintrs[i]);
restore_flags(flags);
}
#endif
/*****************************************************************************/
/*
* Local memory allocation routines. These are used so we can deal with
* memory allocation at init time and during run-time in a consistent
* way. Everbody just calls the stl_memalloc routine to allocate
* memory and it will do the right thing.
*/
#ifndef MODULE
static void stl_meminit(long base)
{
stl_memend = base;
stl_meminited = 1;
}
static long stl_memhalt()
{
stl_meminited = 0;
return(stl_memend);
}
#endif
static void *stl_memalloc(int len)
{
void *mem;
if (stl_meminited) {
mem = (void *) stl_memend;
stl_memend += len;
} else {
mem = (void *) kmalloc(len, GFP_KERNEL);
}
return(mem);
}
/*****************************************************************************/
static int stl_open(struct tty_struct *tty, struct file *filp)
{
stlport_t *portp;
stlbrd_t *brdp;
unsigned int minordev;
int brdnr, panelnr, portnr, rc;
#if DEBUG
printk("stl_open(tty=%x,filp=%x): device=%x\n", (int) tty, (int) filp, tty->device);
#endif
minordev = MINOR(tty->device);
brdnr = MKDEV2BRD(minordev);
if (brdnr >= stl_nrbrds)
return(-ENODEV);
brdp = stl_brds[brdnr];
if (brdp == (stlbrd_t *) NULL)
return(-ENODEV);
minordev = MKDEV2PORT(minordev);
for (portnr = -1, panelnr = 0; (panelnr < STL_MAXPANELS); panelnr++) {
if (brdp->panels[panelnr] == (stlpanel_t *) NULL)
break;
if (minordev < brdp->panels[panelnr]->nrports) {
portnr = minordev;
break;
}
minordev -= brdp->panels[panelnr]->nrports;
}
if (portnr < 0)
return(-ENODEV);
portp = brdp->panels[panelnr]->ports[portnr];
if (portp == (stlport_t *) NULL)
return(-ENODEV);
/*
* On the first open of the device setup the port hardware, and
* initialize the per port data structure.
*/
portp->tty = tty;
tty->driver_data = portp;
portp->refcount++;
if ((portp->flags & ASYNC_INITIALIZED) == 0) {
if (portp->tx.buf == (char *) NULL) {
portp->tx.buf = (char *) stl_memalloc(STL_TXBUFSIZE);
if (portp->tx.buf == (char *) NULL)
return(-ENOMEM);
portp->tx.head = portp->tx.buf;
portp->tx.tail = portp->tx.buf;
}
stl_setport(portp, tty->termios);
stl_getsignals(portp);
stl_setsignals(portp, 1, 1);
stl_enablerxtx(portp, 1, 1);
stl_startrxtx(portp, 1, 0);
clear_bit(TTY_IO_ERROR, &tty->flags);
portp->flags |= ASYNC_INITIALIZED;
}
/*
* Check if this port is in the middle of closing. If so then wait
* until it is closed then return error status, based on flag settings.
* The sleep here does not need interrupt protection since the wakeup
* for it is done with the same context.
*/
if (portp->flags & ASYNC_CLOSING) {
interruptible_sleep_on(&portp->close_wait);
if (portp->flags & ASYNC_HUP_NOTIFY)
return(-EAGAIN);
return(-ERESTARTSYS);
}
/*
* Based on type of open being done check if it can overlap with any
* previous opens still in effect. If we are a normal serial device
* then also we might have to wait for carrier.
*/
if (tty->driver.subtype == STL_DRVTYPCALLOUT) {
if (portp->flags & ASYNC_NORMAL_ACTIVE)
return(-EBUSY);
if (portp->flags & ASYNC_CALLOUT_ACTIVE) {
if ((portp->flags & ASYNC_SESSION_LOCKOUT) &&
(portp->session != current->session))
return(-EBUSY);
if ((portp->flags & ASYNC_PGRP_LOCKOUT) &&
(portp->pgrp != current->pgrp))
return(-EBUSY);
}
portp->flags |= ASYNC_CALLOUT_ACTIVE;
} else {
if (filp->f_flags & O_NONBLOCK) {
if (portp->flags & ASYNC_CALLOUT_ACTIVE)
return(-EBUSY);
} else {
if ((rc = stl_waitcarrier(portp, filp)) != 0)
return(rc);
}
portp->flags |= ASYNC_NORMAL_ACTIVE;
}
if ((portp->refcount == 1) && (portp->flags & ASYNC_SPLIT_TERMIOS)) {
if (tty->driver.subtype == STL_DRVTYPSERIAL)
*tty->termios = portp->normaltermios;
else
*tty->termios = portp->callouttermios;
stl_setport(portp, tty->termios);
}
portp->session = current->session;
portp->pgrp = current->pgrp;
return(0);
}
/*****************************************************************************/
/*
* Possibly need to wait for carrier (DCD signal) to come high. Say
* maybe because if we are clocal then we don't need to wait...
*/
static int stl_waitcarrier(stlport_t *portp, struct file *filp)
{
unsigned long flags;
int rc;
#if DEBUG
printk("stl_waitcarrier(portp=%x,filp=%x)\n", (int) portp, (int) filp);
#endif
rc = 0;
save_flags(flags);
cli();
portp->openwaitcnt++;
if (portp->refcount > 0)
portp->refcount--;
for (;;) {
if ((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0)
stl_setsignals(portp, 1, 1);
if (tty_hung_up_p(filp) || ((portp->flags & ASYNC_INITIALIZED) == 0)) {
if (portp->flags & ASYNC_HUP_NOTIFY)
rc = -EBUSY;
else
rc = -ERESTARTSYS;
break;
}
if (((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) &&
((portp->flags & ASYNC_CLOSING) == 0) &&
((portp->tty->termios->c_cflag & CLOCAL) ||
(portp->sigs & TIOCM_CD))) {
break;
}
if (current->signal & ~current->blocked) {
rc = -ERESTARTSYS;
break;
}
interruptible_sleep_on(&portp->open_wait);
}
if (! tty_hung_up_p(filp))
portp->refcount++;
portp->openwaitcnt--;
restore_flags(flags);
return(rc);
}
/*****************************************************************************/
static void stl_close(struct tty_struct *tty, struct file *filp)
{
stlport_t *portp;
unsigned long flags;
#if DEBUG
printk("stl_close(tty=%x,filp=%x)\n", (int) tty, (int) filp);
#endif
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return;
save_flags(flags);
cli();
if (tty_hung_up_p(filp)) {
restore_flags(flags);
return;
}
if (portp->refcount-- > 1) {
restore_flags(flags);
return;
}
portp->refcount = 0;
portp->flags |= ASYNC_CLOSING;
if (portp->flags & ASYNC_NORMAL_ACTIVE)
portp->normaltermios = *tty->termios;
if (portp->flags & ASYNC_CALLOUT_ACTIVE)
portp->callouttermios = *tty->termios;
/*
* May want to wait for any data to drain before closing. The BUSY
* flag keeps track of whether we are still sending or not - it allows
* for the FIFO in the cd1400.
*/
tty->closing = 1;
if (test_bit(ASYI_TXBUSY, &portp->istate)) {
if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, portp->closing_wait);
}
portp->flags &= ~ASYNC_INITIALIZED;
stl_disableintrs(portp);
if (tty->termios->c_cflag & HUPCL)
stl_setsignals(portp, 0, 0);
stl_enablerxtx(portp, 0, 0);
stl_flushbuffer(tty);
portp->istate = 0;
if (portp->tx.buf != (char *) NULL) {
kfree_s(portp->tx.buf, STL_TXBUFSIZE);
portp->tx.buf = (char *) NULL;
portp->tx.head = (char *) NULL;
portp->tx.tail = (char *) NULL;
}
set_bit(TTY_IO_ERROR, &tty->flags);
if (tty->ldisc.flush_buffer)
(tty->ldisc.flush_buffer)(tty);
tty->closing = 0;
tty->driver_data = (void *) NULL;
portp->tty = (struct tty_struct *) NULL;
if (portp->openwaitcnt) {
if (portp->close_delay)
stl_delay(portp->close_delay);
wake_up_interruptible(&portp->open_wait);
}
portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
wake_up_interruptible(&portp->close_wait);
restore_flags(flags);
}
/*****************************************************************************/
/*
* Wait for a specified delay period, this is not a busy-loop. It will
* give up the processor while waiting. Unfortunately this has some
* rather intimate knowledge of the process management stuff.
*/
static void stl_delay(int len)
{
#if DEBUG
printk("stl_delay(len=%d)\n", len);
#endif
if (len > 0) {
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + len;
schedule();
}
}
/*****************************************************************************/
/*
* Write routine. Take data and stuff it in to the TX ring queue.
* If transmit interrupts are not running then start them.
*/
static int stl_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
{
stlport_t *portp;
unsigned int len, stlen;
unsigned long flags;
unsigned char *chbuf;
char *head, *tail;
#if DEBUG
printk("stl_write(tty=%x,from_user=%d,buf=%x,count=%d)\n", (int) tty, from_user, (int) buf, count);
#endif
if ((tty == (struct tty_struct *) NULL) || (stl_tmpwritebuf == (char *) NULL))
return(0);
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return(0);
if (portp->tx.buf == (char *) NULL)
return(0);
/*
* If copying direct from user space we must cater for page faults,
* causing us to "sleep" here for a while. To handle this copy in all
* the data we need now, into a local buffer. Then when we got it all
* copy it into the TX buffer.
*/
chbuf = (unsigned char *) buf;
if (from_user) {
head = portp->tx.head;
tail = portp->tx.tail;
len = (head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) :
(tail - head - 1);
count = MIN(len, count);
save_flags(flags);
cli();
down(&stl_tmpwritesem);
memcpy_fromfs(stl_tmpwritebuf, chbuf, count);
up(&stl_tmpwritesem);
restore_flags(flags);
chbuf = &stl_tmpwritebuf[0];
}
head = portp->tx.head;
tail = portp->tx.tail;
if (head >= tail) {
len = STL_TXBUFSIZE - (head - tail) - 1;
stlen = STL_TXBUFSIZE - (head - portp->tx.buf);
} else {
len = tail - head - 1;
stlen = len;
}
len = MIN(len, count);
count = 0;
while (len > 0) {
stlen = MIN(len, stlen);
memcpy(head, chbuf, stlen);
len -= stlen;
chbuf += stlen;
count += stlen;
head += stlen;
if (head >= (portp->tx.buf + STL_TXBUFSIZE)) {
head = portp->tx.buf;
stlen = tail - head;
}
}
portp->tx.head = head;
clear_bit(ASYI_TXLOW, &portp->istate);
stl_startrxtx(portp, -1, 1);
return(count);
}
/*****************************************************************************/
static void stl_putchar(struct tty_struct *tty, unsigned char ch)
{
stlport_t *portp;
unsigned int len;
char *head, *tail;
#if DEBUG
printk("stl_putchar(tty=%x,ch=%x)\n", (int) tty, (int) ch);
#endif
if (tty == (struct tty_struct *) NULL)
return;
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return;
if (portp->tx.buf == (char *) NULL)
return;
head = portp->tx.head;
tail = portp->tx.tail;
len = (head >= tail) ? (STL_TXBUFSIZE - (head - tail)) : (tail - head);
len--;
if (len > 0) {
*head++ = ch;
if (head >= (portp->tx.buf + STL_TXBUFSIZE))
head = portp->tx.buf;
}
portp->tx.head = head;
}
/*****************************************************************************/
/*
* If there are any characters in the buffer then make sure that TX
* interrupts are on and get'em out. Normally used after the putchar
* routine has been called.
*/
static void stl_flushchars(struct tty_struct *tty)
{
stlport_t *portp;
#if DEBUG
printk("stl_flushchars(tty=%x)\n", (int) tty);
#endif
if (tty == (struct tty_struct *) NULL)
return;
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return;
if (portp->tx.buf == (char *) NULL)
return;
#if 0
if (tty->stopped || tty->hw_stopped || (portp->tx.head == portp->tx.tail))
return;
#endif
stl_startrxtx(portp, -1, 1);
}
/*****************************************************************************/
static int stl_writeroom(struct tty_struct *tty)
{
stlport_t *portp;
char *head, *tail;
#if DEBUG
printk("stl_writeroom(tty=%x)\n", (int) tty);
#endif
if (tty == (struct tty_struct *) NULL)
return(0);
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return(0);
if (portp->tx.buf == (char *) NULL)
return(0);
head = portp->tx.head;
tail = portp->tx.tail;
return((head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : (tail - head - 1));
}
/*****************************************************************************/
/*
* Return number of chars in the TX buffer. Normally we would just
* calculate the number of chars in the buffer and return that, but if
* the buffer is empty and TX interrupts are still on then we return
* that the buffer still has 1 char in it. This way whoever called us
* will not think that ALL chars have drained - since the UART still
* must have some chars in it (we are busy after all).
*/
static int stl_charsinbuffer(struct tty_struct *tty)
{
stlport_t *portp;
unsigned int size;
char *head, *tail;
#if DEBUG
printk("stl_charsinbuffer(tty=%x)\n", (int) tty);
#endif
if (tty == (struct tty_struct *) NULL)
return(0);
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return(0);
if (portp->tx.buf == (char *) NULL)
return(0);
head = portp->tx.head;
tail = portp->tx.tail;
size = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head));
if ((size == 0) && test_bit(ASYI_TXBUSY, &portp->istate))
size = 1;
return(size);
}
/*****************************************************************************/
/*
* Generate the serial struct info.
*/
static void stl_getserial(stlport_t *portp, struct serial_struct *sp)
{
struct serial_struct sio;
stlbrd_t *brdp;
#if DEBUG
printk("stl_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp);
#endif
memset(&sio, 0, sizeof(struct serial_struct));
sio.type = PORT_CIRRUS;
sio.line = portp->portnr;
sio.port = portp->ioaddr;
sio.flags = portp->flags;
sio.baud_base = portp->baud_base;
sio.close_delay = portp->close_delay;
sio.closing_wait = portp->closing_wait;
sio.custom_divisor = portp->custom_divisor;
sio.xmit_fifo_size = CD1400_TXFIFOSIZE;
sio.hub6 = 0;
brdp = stl_brds[portp->brdnr];
if (brdp != (stlbrd_t *) NULL)
sio.irq = brdp->irq;
memcpy_tofs(sp, &sio, sizeof(struct serial_struct));
}
/*****************************************************************************/
/*
* Set port according to the serial struct info.
* At this point we do not do any auto-configure stuff, so we will
* just quietly ignore any requests to change irq, etc.
*/
static int stl_setserial(stlport_t *portp, struct serial_struct *sp)
{
struct serial_struct sio;
#if DEBUG
printk("stl_setserial(portp=%x,sp=%x)\n", (int) portp, (int) sp);
#endif
memcpy_fromfs(&sio, sp, sizeof(struct serial_struct));
if (!suser()) {
if ((sio.baud_base != portp->baud_base) ||
(sio.close_delay != portp->close_delay) ||
((sio.flags & ~ASYNC_USR_MASK) != (portp->flags & ~ASYNC_USR_MASK)))
return(-EPERM);
}
portp->flags = (portp->flags & ~ASYNC_USR_MASK) | (sio.flags & ASYNC_USR_MASK);
portp->baud_base = sio.baud_base;
portp->close_delay = sio.close_delay;
portp->closing_wait = sio.closing_wait;
portp->custom_divisor = sio.custom_divisor;
stl_setport(portp, portp->tty->termios);
return(0);
}
/*****************************************************************************/
static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
stlport_t *portp;
int rc;
#if DEBUG
printk("stl_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n", (int) tty, (int) file, cmd, (int) arg);
#endif
if (tty == (struct tty_struct *) NULL)
return(-ENODEV);
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return(-ENODEV);
rc = 0;
switch (cmd) {
case TCSBRK:
if ((rc = tty_check_change(tty)) == 0) {
tty_wait_until_sent(tty, 0);
if (! arg)
stl_sendbreak(portp, 250);
}
break;
case TCSBRKP:
if ((rc = tty_check_change(tty)) == 0) {
tty_wait_until_sent(tty, 0);
stl_sendbreak(portp, (arg ? (arg * 100) : 250));
}
break;
case TIOCGSOFTCAR:
if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long))) == 0)
put_fs_long(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned long *) arg);
break;
case TIOCSSOFTCAR:
if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
arg = get_fs_long((unsigned long *) arg);
tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0);
}
break;
case TIOCMGET:
if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int))) == 0) {
stl_getsignals(portp);
put_fs_long(portp->sigs, (unsigned long *) arg);
}
break;
case TIOCMBIS:
if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
arg = get_fs_long((unsigned long *) arg);
stl_setsignals(portp, ((arg & TIOCM_DTR) ? 1 : -1), ((arg & TIOCM_RTS) ? 1 : -1));
}
break;
case TIOCMBIC:
if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
arg = get_fs_long((unsigned long *) arg);
stl_setsignals(portp, ((arg & TIOCM_DTR) ? 0 : -1), ((arg & TIOCM_RTS) ? 0 : -1));
}
break;
case TIOCMSET:
if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
arg = get_fs_long((unsigned long *) arg);
stl_setsignals(portp, ((arg & TIOCM_DTR) ? 1 : 0), ((arg & TIOCM_RTS) ? 1 : 0));
}
break;
case TIOCGSERIAL:
if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) == 0)
stl_getserial(portp, (struct serial_struct *) arg);
break;
case TIOCSSERIAL:
if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(struct serial_struct))) == 0)
rc = stl_setserial(portp, (struct serial_struct *) arg);
break;
case TIOCSERCONFIG:
case TIOCSERGWILD:
case TIOCSERSWILD:
case TIOCSERGETLSR:
case TIOCSERGSTRUCT:
case TIOCSERGETMULTI:
case TIOCSERSETMULTI:
default:
rc = -ENOIOCTLCMD;
break;
}
return(rc);
}
/*****************************************************************************/
static void stl_settermios(struct tty_struct *tty, struct termios *old)
{
stlport_t *portp;
struct termios *tiosp;
#if DEBUG
printk("stl_settermios(tty=%x,old=%x)\n", (int) tty, (int) old);
#endif
if (tty == (struct tty_struct *) NULL)
return;
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return;
tiosp = tty->termios;
if ((tiosp->c_cflag == old->c_cflag) && (tiosp->c_iflag == old->c_iflag))
return;
stl_setport(portp, tiosp);
stl_setsignals(portp, ((tiosp->c_cflag & (CBAUD & ~CBAUDEX)) ? 1 : 0), -1);
if ((old->c_cflag & CRTSCTS) && ((tiosp->c_cflag & CRTSCTS) == 0)) {
tty->hw_stopped = 0;
stl_start(tty);
}
if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL))
wake_up_interruptible(&portp->open_wait);
}
/*****************************************************************************/
/*
* Attempt to flow control who ever is sending us data. Based on termios
* settings use software or/and hardware flow control.
*/
static void stl_throttle(struct tty_struct *tty)
{
stlport_t *portp;
unsigned long flags;
#if DEBUG
printk("stl_throttle(tty=%x)\n", (int) tty);
#endif
if (tty == (struct tty_struct *) NULL)
return;
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return;
save_flags(flags);
cli();
BRDENABLE(portp->brdnr, portp->pagenr);
stl_setreg(portp, CAR, (portp->portnr & 0x03));
if (tty->termios->c_iflag & IXOFF) {
stl_ccrwait(portp);
stl_setreg(portp, CCR, CCR_SENDSCHR2);
stl_ccrwait(portp);
}
if (tty->termios->c_cflag & CRTSCTS) {
stl_setreg(portp, MCOR1, (stl_getreg(portp, MCOR1) & 0xf0));
stl_setreg(portp, MSVR2, 0);
}
BRDDISABLE(portp->brdnr);
restore_flags(flags);
}
/*****************************************************************************/
/*
* Unflow control the device sending us data...
*/
static void stl_unthrottle(struct tty_struct *tty)
{
stlport_t *portp;
unsigned long flags;
#if DEBUG
printk("stl_unthrottle(tty=%x)\n", (int) tty);
#endif
if (tty == (struct tty_struct *) NULL)
return;
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return;
save_flags(flags);
cli();
BRDENABLE(portp->brdnr, portp->pagenr);
stl_setreg(portp, CAR, (portp->portnr & 0x03));
if (tty->termios->c_iflag & IXOFF) {
stl_ccrwait(portp);
stl_setreg(portp, CCR, CCR_SENDSCHR1);
stl_ccrwait(portp);
}
/*
* Question: should we return RTS to what it was before? It may have
* been set by an ioctl... Suppose not, since if you have hardware
* flow control set then it is pretty silly to go and set the RTS line
* by hand.
*/
if (tty->termios->c_cflag & CRTSCTS) {
stl_setreg(portp, MCOR1, (stl_getreg(portp, MCOR1) | FIFO_RTSTHRESHOLD));
stl_setreg(portp, MSVR2, MSVR2_RTS);
}
BRDDISABLE(portp->brdnr);
restore_flags(flags);
}
/*****************************************************************************/
/*
* Stop the transmitter. Basically to do this we will just turn TX
* interrupts off.
*/
static void stl_stop(struct tty_struct *tty)
{
stlport_t *portp;
#if DEBUG
printk("stl_stop(tty=%x)\n", (int) tty);
#endif
if (tty == (struct tty_struct *) NULL)
return;
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return;
stl_startrxtx(portp, -1, 0);
}
/*****************************************************************************/
/*
* Start the transmitter again. Just turn TX interrupts back on.
*/
static void stl_start(struct tty_struct *tty)
{
stlport_t *portp;
#if DEBUG
printk("stl_start(tty=%x)\n", (int) tty);
#endif
if (tty == (struct tty_struct *) NULL)
return;
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return;
stl_startrxtx(portp, -1, 1);
}
/*****************************************************************************/
/*
* Hangup this port. This is pretty much like closing the port, only
* a little more brutal. No waiting for data to drain. Shutdown the
* port and maybe drop signals.
*/
static void stl_hangup(struct tty_struct *tty)
{
stlport_t *portp;
#if DEBUG
printk("stl_hangup(tty=%x)\n", (int) tty);
#endif
if (tty == (struct tty_struct *) NULL)
return;
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return;
portp->flags &= ~ASYNC_INITIALIZED;
stl_disableintrs(portp);
if (tty->termios->c_cflag & HUPCL)
stl_setsignals(portp, 0, 0);
stl_enablerxtx(portp, 0, 0);
stl_flushbuffer(tty);
portp->istate = 0;
set_bit(TTY_IO_ERROR, &tty->flags);
if (portp->tx.buf != (char *) NULL) {
kfree_s(portp->tx.buf, STL_TXBUFSIZE);
portp->tx.buf = (char *) NULL;
portp->tx.head = (char *) NULL;
portp->tx.tail = (char *) NULL;
}
tty->driver_data = (void *) NULL;
portp->tty = (struct tty_struct *) NULL;
portp->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
portp->refcount = 0;
wake_up_interruptible(&portp->open_wait);
}
/*****************************************************************************/
static void stl_flushbuffer(struct tty_struct *tty)
{
stlport_t *portp;
unsigned long flags;
#if DEBUG
printk("stl_flushbuffer(tty=%x)\n", (int) tty);
#endif
if (tty == (struct tty_struct *) NULL)
return;
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return;
save_flags(flags);
cli();
BRDENABLE(portp->brdnr, portp->pagenr);
stl_setreg(portp, CAR, (portp->portnr & 0x03));
stl_ccrwait(portp);
stl_setreg(portp, CCR, CCR_TXFLUSHFIFO);
stl_ccrwait(portp);
portp->tx.tail = portp->tx.head;
BRDDISABLE(portp->brdnr);
restore_flags(flags);
wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
}
/*****************************************************************************/
/*
* These functions get/set/update the registers of the cd1400 UARTs.
* Access to the cd1400 registers is via an address/data io port pair.
* (Maybe should make this inline...)
*/
static int stl_getreg(stlport_t *portp, int regnr)
{
outb((regnr + portp->uartaddr), portp->ioaddr);
return(inb(portp->ioaddr + EREG_DATA));
}
static void stl_setreg(stlport_t *portp, int regnr, int value)
{
outb((regnr + portp->uartaddr), portp->ioaddr);
outb(value, portp->ioaddr + EREG_DATA);
}
static int stl_updatereg(stlport_t *portp, int regnr, int value)
{
outb((regnr + portp->uartaddr), portp->ioaddr);
if (inb(portp->ioaddr + EREG_DATA) != value) {
outb(value, portp->ioaddr + EREG_DATA);
return(1);
}
return(0);
}
/*****************************************************************************/
/*
* Transmit interrupt handler. This has gotta be fast! Handling TX
* chars is pretty simple, stuff as many as possible from the TX buffer
* into the cd1400 FIFO. Must also handle TX breaks here, since they
* are embedded as commands in the data stream. Oh no, had to use a goto!
* This could be optimized more, will do when I get time...
* In practice it is possible that interrupts are enabled but that the
* port has been hung up. Need to handle not having any TX buffer here,
* this is done by using the side effect that head and tail will also
* be NULL if the buffer has been freed.
*/
static inline void stl_txisr(stlpanel_t *panelp, int ioaddr)
{
stlport_t *portp;
int len, stlen;
char *head, *tail;
unsigned char ioack, srer;
#if DEBUG
printk("stl_txisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr);
#endif
ioack = inb(ioaddr + EREG_TXACK);
if (((ioack & panelp->ackmask) != 0) || ((ioack & ACK_TYPMASK) != ACK_TYPTX)) {
printk("STALLION: bad TX interrupt ack value=%x\n", ioack);
return;
}
portp = panelp->ports[(ioack >> 3)];
/*
* Unfortunately we need to handle breaks in the data stream, since
* this is the only way to generate them on the cd1400. Do it now if
* a break is to be sent.
*/
if (portp->brklen != 0) {
if (portp->brklen > 0) {
outb((TDR + portp->uartaddr), ioaddr);
outb(ETC_CMD, (ioaddr + EREG_DATA));
outb(ETC_STARTBREAK, (ioaddr + EREG_DATA));
outb(ETC_CMD, (ioaddr + EREG_DATA));
outb(ETC_DELAY, (ioaddr + EREG_DATA));
outb(portp->brklen, (ioaddr + EREG_DATA));
outb(ETC_CMD, (ioaddr + EREG_DATA));
outb(ETC_STOPBREAK, (ioaddr + EREG_DATA));
portp->brklen = -1;
goto stl_txalldone;
} else {
outb((COR2 + portp->uartaddr), ioaddr);
outb((inb(ioaddr + EREG_DATA) & ~COR2_ETC), (ioaddr + EREG_DATA));
portp->brklen = 0;
}
}
head = portp->tx.head;
tail = portp->tx.tail;
len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head));
if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
set_bit(ASYI_TXLOW, &portp->istate);
queue_task_irq_off(&portp->tqueue, &tq_scheduler);
}
if (len == 0) {
outb((SRER + portp->uartaddr), ioaddr);
srer = inb(ioaddr + EREG_DATA);
if (srer & SRER_TXDATA) {
srer = (srer & ~SRER_TXDATA) | SRER_TXEMPTY;
} else {
srer &= ~(SRER_TXDATA | SRER_TXEMPTY);
clear_bit(ASYI_TXBUSY, &portp->istate);
}
outb(srer, (ioaddr + EREG_DATA));
} else {
len = MIN(len, CD1400_TXFIFOSIZE);
stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
outb((TDR + portp->uartaddr), ioaddr);
outsb((ioaddr + EREG_DATA), tail, stlen);
len -= stlen;
tail += stlen;
if (tail >= (portp->tx.buf + STL_TXBUFSIZE))
tail = portp->tx.buf;
if (len > 0) {
outsb((ioaddr + EREG_DATA), tail, len);
tail += len;
}
portp->tx.tail = tail;
}
stl_txalldone:
outb((EOSRR + portp->uartaddr), ioaddr);
outb(0, (ioaddr + EREG_DATA));
}
/*****************************************************************************/
/*
* Receive character interrupt handler. Determine if we have good chars
* or bad chars and then process appropriately. Good chars are easy
* just shove the lot into the RX buffer and set all status byte to 0.
* If a bad RX char then process as required. This routine needs to be
* fast! In practice it is possible that we get an interrupt on a port
* that is closed. This can happen on hangups - since they completely
* shutdown a port not in user context. Need to handle this case.
*/
static inline void stl_rxisr(stlpanel_t *panelp, int ioaddr)
{
stlport_t *portp;
struct tty_struct *tty;
unsigned int ioack, len, buflen;
unsigned char status;
char ch;
static char unwanted[CD1400_RXFIFOSIZE];
#if DEBUG
printk("stl_rxisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr);
#endif
ioack = inb(ioaddr + EREG_RXACK);
if ((ioack & panelp->ackmask) != 0) {
printk("STALLION: bad RX interrupt ack value=%x\n", ioack);
return;
}
portp = panelp->ports[(ioack >> 3)];
tty = portp->tty;
if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) {
outb((RDCR + portp->uartaddr), ioaddr);
len = inb(ioaddr + EREG_DATA);
if ((tty == (struct tty_struct *) NULL) || (tty->flip.char_buf_ptr == (char *) NULL) ||
((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
outb((RDSR + portp->uartaddr), ioaddr);
insb((ioaddr + EREG_DATA), &unwanted[0], len);
} else {
len = MIN(len, buflen);
if (len > 0) {
outb((RDSR + portp->uartaddr), ioaddr);
insb((ioaddr + EREG_DATA), tty->flip.char_buf_ptr, len);
memset(tty->flip.flag_buf_ptr, 0, len);
tty->flip.flag_buf_ptr += len;
tty->flip.char_buf_ptr += len;
tty->flip.count += len;
tty_schedule_flip(tty);
}
}
} else if ((ioack & ACK_TYPMASK) == ACK_TYPRXBAD) {
outb((RDSR + portp->uartaddr), ioaddr);
status = inb(ioaddr + EREG_DATA);
ch = inb(ioaddr + EREG_DATA);
if ((tty != (struct tty_struct *) NULL) && ((portp->rxignoremsk & status) == 0)) {
if (portp->rxmarkmsk & status) {
if (status & ST_BREAK) {
status = TTY_BREAK;
#ifndef MODULE
if (portp->flags & ASYNC_SAK)
do_SAK(tty);
#endif
} else if (status & ST_PARITY) {
status = TTY_PARITY;
} else if (status & ST_FRAMING) {
status = TTY_FRAME;
} else if(status & ST_OVERRUN) {
status = TTY_OVERRUN;
} else {
status = 0;
}
} else {
status = 0;
}
if (tty->flip.char_buf_ptr != (char *) NULL) {
if (tty->flip.count < TTY_FLIPBUF_SIZE) {
*tty->flip.flag_buf_ptr++ = status;
*tty->flip.char_buf_ptr++ = ch;
tty->flip.count++;
}
tty_schedule_flip(tty);
}
}
} else {
printk("STALLION: bad RX interrupt ack value=%x\n", ioack);
return;
}
outb((EOSRR + portp->uartaddr), ioaddr);
outb(0, (ioaddr + EREG_DATA));
}
/*****************************************************************************/
/*
* Modem interrupt handler. The is called when the modem signal line
* (DCD) has changed state. Leave most of the work to the off-level
* processing routine.
*/
static inline void stl_mdmisr(stlpanel_t *panelp, int ioaddr)
{
stlport_t *portp;
unsigned int ioack;
unsigned char misr;
#if DEBUG
printk("stl_mdmisr(panelp=%x)\n", (int) panelp);
#endif
ioack = inb(ioaddr + EREG_MDACK);
if (((ioack & panelp->ackmask) != 0) || ((ioack & ACK_TYPMASK) != ACK_TYPMDM)) {
printk("STALLION: bad MODEM interrupt ack value=%x\n", ioack);
return;
}
portp = panelp->ports[(ioack >> 3)];
outb((MISR + portp->uartaddr), ioaddr);
misr = inb(ioaddr + EREG_DATA);
if (misr & MISR_DCD) {
set_bit(ASYI_DCDCHANGE, &portp->istate);
queue_task_irq_off(&portp->tqueue, &tq_scheduler);
}
outb((EOSRR + portp->uartaddr), ioaddr);
outb(0, (ioaddr + EREG_DATA));
}
/*****************************************************************************/
/*
* Interrupt handler for EIO and ECH boards. This code ain't all that
* pretty, but the idea is to make it as fast as possible. This code is
* well suited to be assemblerized :-) We don't use the general purpose
* register access functions here, for speed we will go strait to the
* io region.
*/
static void stl_intr(int irq, struct pt_regs *regs)
{
stlbrd_t *brdp;
stlpanel_t *panelp;
unsigned char svrtype;
int i, panelnr, iobase;
#if DEBUG
printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs);
#endif
panelp = (stlpanel_t *) NULL;
for (i = 0; (i < stl_nrbrds); ) {
if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) {
i++;
continue;
}
if (brdp->state == 0) {
i++;
continue;
}
/*
* The following section of code handles the subtle differences
* between board types. It is sort of similar, but different
* enough to handle each separately.
*/
if (brdp->brdtype == BRD_EASYIO) {
if ((inb(brdp->iostatus) & EIO_INTRPEND) == 0) {
i++;
continue;
}
panelp = brdp->panels[0];
iobase = panelp->iobase;
outb(SVRR, iobase);
svrtype = inb(iobase + EREG_DATA);
if (brdp->nrports > 4) {
outb((SVRR + 0x80), iobase);
svrtype |= inb(iobase + EREG_DATA);
}
} else if (brdp->brdtype == BRD_ECH) {
if ((inb(brdp->iostatus) & ECH_INTRPEND) == 0) {
i++;
continue;
}
outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) {
panelp = brdp->panels[panelnr];
iobase = panelp->iobase;
if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND)
break;
if (panelp->nrports > 8) {
iobase += 0x8;
if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND)
break;
}
}
if (panelnr >= brdp->nrpanels) {
i++;
continue;
}
outb(SVRR, iobase);
svrtype = inb(iobase + EREG_DATA);
outb((SVRR + 0x80), iobase);
svrtype |= inb(iobase + EREG_DATA);
} else if (brdp->brdtype == BRD_ECHPCI) {
iobase = brdp->ioaddr2;
for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) {
panelp = brdp->panels[panelnr];
outb(panelp->pagenr, brdp->ioctrl);
if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND)
break;
if (panelp->nrports > 8) {
outb((panelp->pagenr + 1), brdp->ioctrl);
if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND)
break;
}
}
if (panelnr >= brdp->nrpanels) {
i++;
continue;
}
outb(SVRR, iobase);
svrtype = inb(iobase + EREG_DATA);
outb((SVRR + 0x80), iobase);
svrtype |= inb(iobase + EREG_DATA);
} else if (brdp->brdtype == BRD_ECHMC) {
if ((inb(brdp->iostatus) & ECH_INTRPEND) == 0) {
i++;
continue;
}
for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) {
panelp = brdp->panels[panelnr];
iobase = panelp->iobase;
if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND)
break;
if (panelp->nrports > 8) {
iobase += 0x8;
if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND)
break;
}
}
if (panelnr >= brdp->nrpanels) {
i++;
continue;
}
outb(SVRR, iobase);
svrtype = inb(iobase + EREG_DATA);
outb((SVRR + 0x80), iobase);
svrtype |= inb(iobase + EREG_DATA);
} else {
printk("STALLION: unknown board type=%x\n", brdp->brdtype);
i++;
continue;
}
/*
* We have determined what type of service is required for a
* port. From here on in the service of a port is the same no
* matter what the board type...
*/
if (svrtype & SVRR_RX)
stl_rxisr(panelp, iobase);
if (svrtype & SVRR_TX)
stl_txisr(panelp, iobase);
if (svrtype & SVRR_MDM)
stl_mdmisr(panelp, iobase);
if (brdp->brdtype == BRD_ECH)
outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl);
}
}
/*****************************************************************************/
/*
* Service an off-level request for some channel.
*/
static void stl_offintr(void *private)
{
stlport_t *portp;
struct tty_struct *tty;
unsigned int oldsigs;
portp = private;
#if DEBUG
printk("stl_offintr(portp=%x)\n", (int) portp);
#endif
if (portp == (stlport_t *) NULL)
return;
tty = portp->tty;
if (tty == (struct tty_struct *) NULL)
return;
if (test_bit(ASYI_TXLOW, &portp->istate)) {
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
wake_up_interruptible(&tty->write_wait);
}
if (test_bit(ASYI_DCDCHANGE, &portp->istate)) {
clear_bit(ASYI_DCDCHANGE, &portp->istate);
oldsigs = portp->sigs;
stl_getsignals(portp);
if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0))
wake_up_interruptible(&portp->open_wait);
if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) {
if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) &&
(portp->flags & ASYNC_CALLOUT_NOHUP))) {
tty_hangup(tty);
}
}
}
}
/*****************************************************************************/
/*
* Wait for the command register to be ready. We will poll this,
* since it won't usually take too long to be ready.
*/
static void stl_ccrwait(stlport_t *portp)
{
int i;
for (i = 0; (i < CCR_MAXWAIT); i++) {
if (stl_getreg(portp, CCR) == 0) {
return;
}
}
printk("STALLION: cd1400 device not responding, port=%d panel=%d brd=%d\n", portp->portnr, portp->panelnr, portp->brdnr);
}
/*****************************************************************************/
/*
* Set up the cd1400 registers for a port based on the termios port
* settings.
*/
static void stl_setport(stlport_t *portp, struct termios *tiosp)
{
stlbrd_t *brdp;
unsigned long flags;
unsigned int clkdiv, baudrate;
unsigned char cor1, cor2, cor3;
unsigned char cor4, cor5, ccr;
unsigned char srer, sreron, sreroff;
unsigned char mcor1, mcor2, rtpr;
unsigned char clk, div;
cor1 = 0;
cor2 = 0;
cor3 = 0;
cor4 = 0;
cor5 = 0;
ccr = 0;
rtpr = 0;
clk = 0;
div = 0;
mcor1 = 0;
mcor2 = 0;
sreron = 0;
sreroff = 0;
brdp = stl_brds[portp->brdnr];
if (brdp == (stlbrd_t *) NULL)
return;
/*
* Set up the RX char ignore mask with those RX error types we
* can ignore. We can get the cd1400 to help us out a little here,
* it will ignore parity errors and breaks for us.
*/
portp->rxignoremsk = 0;
if (tiosp->c_iflag & IGNPAR) {
portp->rxignoremsk |= (ST_PARITY | ST_FRAMING | ST_OVERRUN);
cor1 |= COR1_PARIGNORE;
}
if (tiosp->c_iflag & IGNBRK) {
portp->rxignoremsk |= ST_BREAK;
cor4 |= COR4_IGNBRK;
}
portp->rxmarkmsk = ST_OVERRUN;
if (tiosp->c_iflag & (INPCK | PARMRK))
portp->rxmarkmsk |= (ST_PARITY | ST_FRAMING);
if (tiosp->c_iflag & BRKINT)
portp->rxmarkmsk |= ST_BREAK;
/*
* Go through the char size, parity and stop bits and set all the
* option register appropriately.
*/
switch (tiosp->c_cflag & CSIZE) {
case CS5:
cor1 |= COR1_CHL5;
break;
case CS6:
cor1 |= COR1_CHL6;
break;
case CS7:
cor1 |= COR1_CHL7;
break;
default:
cor1 |= COR1_CHL8;
break;
}
if (tiosp->c_cflag & CSTOPB)
cor1 |= COR1_STOP2;
else
cor1 |= COR1_STOP1;
if (tiosp->c_cflag & PARENB) {
if (tiosp->c_cflag & PARODD)
cor1 |= (COR1_PARENB | COR1_PARODD);
else
cor1 |= (COR1_PARENB | COR1_PAREVEN);
} else {
cor1 |= COR1_PARNONE;
}
/*
* Set the RX FIFO threshold at 6 chars. This gives a bit of breathing
* space for hardware flow control and the like. This should be set to
* VMIN. Also here we will set the RX data timeout to 10ms - this should
* really be based on VTIME.
*/
cor3 |= FIFO_RXTHRESHOLD;
rtpr = 2;
/*
* Calculate the baud rate timers. For now we will just assume that
* the input and output baud are the same. Could have used a baud
* table here, but this way we can generate virtually any baud rate
* we like!
*/
baudrate = tiosp->c_cflag & CBAUD;
if (baudrate & CBAUDEX) {
baudrate &= ~CBAUDEX;
if ((baudrate < 1) || (baudrate > 2))
tiosp->c_cflag &= ~CBAUDEX;
else
baudrate += 15;
}
baudrate = stl_baudrates[baudrate];
if ((tiosp->c_cflag & CBAUD) == B38400) {
if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
baudrate = 57600;
else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
baudrate = 115200;
else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
baudrate = (portp->baud_base / portp->custom_divisor);
}
if (baudrate > STL_MAXBAUD)
baudrate = STL_MAXBAUD;
if (baudrate > 0) {
for (clk = 0; (clk < CD1400_NUMCLKS); clk++) {
clkdiv = ((CD1400_CLKHZ / stl_cd1400clkdivs[clk]) / baudrate);
if (clkdiv < 0x100)
break;
}
div = (unsigned char) clkdiv;
}
/*
* Check what form of modem signaling is required and set it up.
*/
if ((tiosp->c_cflag & CLOCAL) == 0) {
mcor1 |= MCOR1_DCD;
mcor2 |= MCOR2_DCD;
sreron |= SRER_MODEM;
}
/*
* Setup cd1400 enhanced modes if we can. In particular we want to
* handle as much of the flow control as possbile automatically. As
* well as saving a few CPU cycles it will also greatly improve flow
* control reliablilty.
*/
if (tiosp->c_iflag & IXON) {
cor2 |= COR2_TXIBE;
cor3 |= (COR3_FCT | COR3_SCD12);
if (tiosp->c_iflag & IXANY)
cor2 |= COR2_IXM;
}
if (tiosp->c_cflag & CRTSCTS) {
cor2 |= COR2_CTSAE;
mcor1 |= FIFO_RTSTHRESHOLD;
}
/*
* All register cd1400 register values calculated so go through and set
* them all up.
*/
#if DEBUG
printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", portp->portnr, portp->panelnr, portp->brdnr);
printk(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n", cor1, cor2, cor3, cor4, cor5);
printk(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n", mcor1, mcor2, rtpr, sreron, sreroff);
printk(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div);
printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
#endif
save_flags(flags);
cli();
BRDENABLE(portp->brdnr, portp->pagenr);
stl_setreg(portp, CAR, (portp->portnr & 0x3));
srer = stl_getreg(portp, SRER);
stl_setreg(portp, SRER, 0);
if (stl_updatereg(portp, COR1, cor1))
ccr = 1;
if (stl_updatereg(portp, COR2, cor2))
ccr = 1;
if (stl_updatereg(portp, COR3, cor3))
ccr = 1;
if (ccr) {
stl_ccrwait(portp);
stl_setreg(portp, CCR, CCR_CORCHANGE);
}
stl_setreg(portp, COR4, cor4);
stl_setreg(portp, COR5, cor5);
stl_setreg(portp, MCOR1, mcor1);
stl_setreg(portp, MCOR2, mcor2);
if (baudrate > 0) {
stl_setreg(portp, TCOR, clk);
stl_setreg(portp, TBPR, div);
stl_setreg(portp, RCOR, clk);
stl_setreg(portp, RBPR, div);
}
stl_setreg(portp, SCHR1, tiosp->c_cc[VSTART]);
stl_setreg(portp, SCHR2, tiosp->c_cc[VSTOP]);
stl_setreg(portp, SCHR3, tiosp->c_cc[VSTART]);
stl_setreg(portp, SCHR4, tiosp->c_cc[VSTOP]);
stl_setreg(portp, RTPR, rtpr);
mcor1 = stl_getreg(portp, MSVR1);
if (mcor1 & MSVR1_DCD)
portp->sigs |= TIOCM_CD;
else
portp->sigs &= ~TIOCM_CD;
stl_setreg(portp, SRER, ((srer & ~sreroff) | sreron));
BRDDISABLE(portp->brdnr);
restore_flags(flags);
}
/*****************************************************************************/
/*
* Set the state of the DTR and RTS signals.
*/
static void stl_setsignals(stlport_t *portp, int dtr, int rts)
{
unsigned char msvr1, msvr2;
unsigned long flags;
#if DEBUG
printk("stl_setsignals(portp=%x,dtr=%d,rts=%d)\n", (int) portp, dtr, rts);
#endif
msvr1 = 0;
msvr2 = 0;
if (dtr > 0)
msvr1 = MSVR1_DTR;
if (rts > 0)
msvr2 = MSVR2_RTS;
save_flags(flags);
cli();
BRDENABLE(portp->brdnr, portp->pagenr);
stl_setreg(portp, CAR, (portp->portnr & 0x03));
if (rts >= 0)
stl_setreg(portp, MSVR2, msvr2);
if (dtr >= 0)
stl_setreg(portp, MSVR1, msvr1);
BRDDISABLE(portp->brdnr);
restore_flags(flags);
}
/*****************************************************************************/
/*
* Get the state of the signals.
*/
static void stl_getsignals(stlport_t *portp)
{
unsigned char msvr1, msvr2;
unsigned long flags;
#if DEBUG
printk("stl_getsignals(portp=%x)\n", (int) portp);
#endif
save_flags(flags);
cli();
BRDENABLE(portp->brdnr, portp->pagenr);
stl_setreg(portp, CAR, (portp->portnr & 0x03));
msvr1 = stl_getreg(portp, MSVR1);
msvr2 = stl_getreg(portp, MSVR2);
BRDDISABLE(portp->brdnr);
portp->sigs = 0;
portp->sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0;
portp->sigs |= (msvr1 & MSVR1_CTS) ? TIOCM_CTS : 0;
portp->sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0;
portp->sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0;
portp->sigs |= (msvr1 & MSVR1_DTR) ? TIOCM_DTR : 0;
portp->sigs |= (msvr2 & MSVR2_RTS) ? TIOCM_RTS : 0;
restore_flags(flags);
}
/*****************************************************************************/
/*
* Enable/Disable the Transmitter and/or Reciever.
*/
static void stl_enablerxtx(stlport_t *portp, int rx, int tx)
{
unsigned char ccr;
unsigned long flags;
#if DEBUG
printk("stl_enablerxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp, rx, tx);
#endif
ccr = 0;
if (tx == 0)
ccr |= CCR_TXDISABLE;
else if (tx > 0)
ccr |= CCR_TXENABLE;
if (rx == 0)
ccr |= CCR_RXDISABLE;
else if (rx > 0)
ccr |= CCR_RXENABLE;
save_flags(flags);
cli();
BRDENABLE(portp->brdnr, portp->pagenr);
stl_setreg(portp, CAR, (portp->portnr & 0x03));
stl_ccrwait(portp);
stl_setreg(portp, CCR, ccr);
stl_ccrwait(portp);
BRDDISABLE(portp->brdnr);
restore_flags(flags);
}
/*****************************************************************************/
/*
* Start/stop the Transmitter and/or Reciever.
*/
static void stl_startrxtx(stlport_t *portp, int rx, int tx)
{
unsigned char sreron, sreroff;
unsigned long flags;
#if DEBUG
printk("stl_startrxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp, rx, tx);
#endif
sreron = 0;
sreroff = 0;
if (tx == 0)
sreroff |= (SRER_TXDATA | SRER_TXEMPTY);
else if (tx == 1)
sreron |= SRER_TXDATA;
else if (tx >= 2)
sreron |= SRER_TXEMPTY;
if (rx == 0)
sreroff |= SRER_RXDATA;
else if (rx > 0)
sreron |= SRER_RXDATA;
save_flags(flags);
cli();
BRDENABLE(portp->brdnr, portp->pagenr);
stl_setreg(portp, CAR, (portp->portnr & 0x03));
stl_setreg(portp, SRER, ((stl_getreg(portp, SRER) & ~sreroff) | sreron));
BRDDISABLE(portp->brdnr);
if (tx > 0)
set_bit(ASYI_TXBUSY, &portp->istate);
restore_flags(flags);
}
/*****************************************************************************/
/*
* Disable all interrupts from this port.
*/
static void stl_disableintrs(stlport_t *portp)
{
unsigned long flags;
#if DEBUG
printk("stl_disableintrs(portp=%x)\n", (int) portp);
#endif
save_flags(flags);
cli();
BRDENABLE(portp->brdnr, portp->pagenr);
stl_setreg(portp, CAR, (portp->portnr & 0x03));
stl_setreg(portp, SRER, 0);
BRDDISABLE(portp->brdnr);
restore_flags(flags);
}
/*****************************************************************************/
static void stl_sendbreak(stlport_t *portp, long len)
{
unsigned long flags;
#if DEBUG
printk("stl_sendbreak(portp=%x,len=%d)\n", (int) portp, (int) len);
#endif
save_flags(flags);
cli();
BRDENABLE(portp->brdnr, portp->pagenr);
stl_setreg(portp, CAR, (portp->portnr & 0x03));
stl_setreg(portp, COR2, (stl_getreg(portp, COR2) | COR2_ETC));
stl_setreg(portp, SRER, ((stl_getreg(portp, SRER) & ~SRER_TXDATA) | SRER_TXEMPTY));
BRDDISABLE(portp->brdnr);
len = len / 5;
portp->brklen = (len > 255) ? 255 : len;
restore_flags(flags);
}
/*****************************************************************************/
/*
* Map in interrupt vector to this driver. Check that we don't
* already have this vector mapped, we might be sharing this
* interrupt accross multiple boards.
*/
static int stl_mapirq(int irq)
{
int rc, i;
#if DEBUG
printk("stl_mapirq(irq=%d)\n", irq);
#endif
rc = 0;
for (i = 0; (i < stl_numintrs); i++) {
if (stl_gotintrs[i] == irq)
break;
}
if (i >= stl_numintrs) {
if (request_irq(irq, stl_intr, SA_INTERRUPT, stl_drvname) != 0) {
printk("STALLION: failed to register interrupt routine for irq=%d\n", irq);
rc = -ENODEV;
} else {
stl_gotintrs[stl_numintrs++] = irq;
}
}
return(rc);
}
/*****************************************************************************/
/*
* Try and find and initialize all the ports on a panel. We don't care
* what sort of board these ports are on - since the port io registers
* are almost identical when dealing with ports.
*/
static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
{
stlport_t *portp;
unsigned int chipmask;
unsigned int gfrcr;
int nrchips, uartaddr, ioaddr;
int i, j;
#if DEBUG
printk("stl_initports(panelp=%x)\n", (int) panelp);
#endif
BRDENABLE(panelp->brdnr, panelp->pagenr);
/*
* Check that each chip is present and started up OK.
*/
chipmask = 0;
nrchips = panelp->nrports / CD1400_PORTS;
for (i = 0; (i < nrchips); i++) {
if (brdp->brdtype == BRD_ECHPCI) {
outb((panelp->pagenr + (i >> 1)), brdp->ioctrl);
ioaddr = panelp->iobase;
} else {
ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 1));
}
uartaddr = (i & 0x01) ? 0x080 : 0;
outb((GFRCR + uartaddr), ioaddr);
outb(0, (ioaddr + EREG_DATA));
outb((CCR + uartaddr), ioaddr);
outb(CCR_RESETFULL, (ioaddr + EREG_DATA));
outb(CCR_RESETFULL, (ioaddr + EREG_DATA));
outb((GFRCR + uartaddr), ioaddr);
for (j = 0; (j < CCR_MAXWAIT); j++) {
if ((gfrcr = inb(ioaddr + EREG_DATA)) != 0)
break;
}
if ((j >= CCR_MAXWAIT) || (gfrcr < 0x40) || (gfrcr > 0x60)) {
printk("STALLION: cd1400 not responding, brd=%d panel=%d chip=%d\n", panelp->brdnr, panelp->panelnr, i);
continue;
}
chipmask |= (0x1 << i);
outb((PPR + uartaddr), ioaddr);
outb(PPR_SCALAR, (ioaddr + EREG_DATA));
}
/*
* All cd1400's are initialized (if found!). Now go through and setup
* each ports data structures. Also init the LIVR register of cd1400
* for each port.
*/
ioaddr = panelp->iobase;
for (i = 0; (i < panelp->nrports); i++) {
if (brdp->brdtype == BRD_ECHPCI) {
outb((panelp->pagenr + (i >> 3)), brdp->ioctrl);
ioaddr = panelp->iobase;
} else {
ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 3));
}
if ((chipmask & (0x1 << (i / 4))) == 0)
continue;
portp = (stlport_t *) stl_memalloc(sizeof(stlport_t));
if (portp == (stlport_t *) NULL) {
printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlport_t));
break;
}
memset(portp, 0, sizeof(stlport_t));
portp->portnr = i;
portp->brdnr = panelp->brdnr;
portp->panelnr = panelp->panelnr;
portp->ioaddr = ioaddr;
portp->uartaddr = (i & 0x04) << 5;
portp->pagenr = panelp->pagenr + (i >> 3);
portp->baud_base = STL_BAUDBASE;
portp->close_delay = STL_CLOSEDELAY;
portp->closing_wait = 30 * HZ;
portp->normaltermios = stl_deftermios;
portp->callouttermios = stl_deftermios;
portp->tqueue.routine = stl_offintr;
portp->tqueue.data = portp;
stl_setreg(portp, CAR, (i & 0x03));
stl_setreg(portp, LIVR, (i << 3));
panelp->ports[i] = portp;
}
BRDDISABLE(panelp->brdnr);
return(0);
}
/*****************************************************************************/
/*
* Try to find and initialize an EasyIO board.
*/
static int stl_initeio(stlbrd_t *brdp)
{
stlpanel_t *panelp;
unsigned int status;
int rc;
#if DEBUG
printk("stl_initeio(brdp=%x)\n", (int) brdp);
#endif
brdp->ioctrl = brdp->ioaddr1 + 1;
brdp->iostatus = brdp->ioaddr1 + 2;
status = inb(brdp->iostatus);
switch (status & EIO_IDBITMASK) {
case EIO_8PORTRS:
case EIO_8PORTM:
case EIO_8PORTDI:
brdp->nrports = 8;
break;
case EIO_4PORTRS:
brdp->nrports = 4;
break;
default:
return(-ENODEV);
}
request_region(brdp->ioaddr1, 8, "serial(EIO)");
/*
* Check that the supplied IRQ is good and then use it to setup the
* programmable interrupt bits on EIO board. Also set the edge/level
* triggered interrupt bit.
*/
if ((brdp->irq < 0) || (brdp->irq > 15) ||
(stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr);
return(-EINVAL);
}
outb((stl_vecmap[brdp->irq] | ((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)), brdp->ioctrl);
panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t));
if (panelp == (stlpanel_t *) NULL) {
printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlpanel_t));
return(-ENOMEM);
}
memset(panelp, 0, sizeof(stlpanel_t));
panelp->brdnr = brdp->brdnr;
panelp->panelnr = 0;
panelp->nrports = brdp->nrports;
panelp->iobase = brdp->ioaddr1;
brdp->panels[0] = panelp;
brdp->nrpanels = 1;
brdp->state |= BRD_FOUND;
rc = stl_mapirq(brdp->irq);
return(rc);
}
/*****************************************************************************/
/*
* Try to find an ECH board and initialize it. This code is capable of
* dealing with all types of ECH board.
*/
static int stl_initech(stlbrd_t *brdp)
{
stlpanel_t *panelp;
unsigned int status, nxtid;
int panelnr, ioaddr, i;
#if DEBUG
printk("stl_initech(brdp=%x)\n", (int) brdp);
#endif
/*
* Set up the initial board register contents for boards. This varys a
* bit between the different board types. So we need to handle each
* separately. Also do a check that the supplied IRQ is good.
*/
if (brdp->brdtype == BRD_ECH) {
brdp->ioctrl = brdp->ioaddr1 + 1;
brdp->iostatus = brdp->ioaddr1 + 1;
status = inb(brdp->iostatus);
if ((status & ECH_IDBITMASK) != ECH_ID)
return(-ENODEV);
if ((brdp->irq < 0) || (brdp->irq > 15) ||
(stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr);
return(-EINVAL);
}
status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1);
status |= (stl_vecmap[brdp->irq] << 1);
outb((status | ECH_BRDRESET), brdp->ioaddr1);
brdp->ioctrlval = ECH_INTENABLE | ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE);
outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
outb(status, brdp->ioaddr1);
request_region(brdp->ioaddr1, 2, "serial(EC8/32)");
request_region(brdp->ioaddr2, 32, "serial(EC8/32-secondary)");
} else if (brdp->brdtype == BRD_ECHMC) {
brdp->ioctrl = brdp->ioaddr1 + 0x20;
brdp->iostatus = brdp->ioctrl;
status = inb(brdp->iostatus);
if ((status & ECH_IDBITMASK) != ECH_ID)
return(-ENODEV);
if ((brdp->irq < 0) || (brdp->irq > 15) ||
(stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr);
return(-EINVAL);
}
outb(ECHMC_BRDRESET, brdp->ioctrl);
outb(ECHMC_INTENABLE, brdp->ioctrl);
request_region(brdp->ioaddr1, 64, "serial(EC8/32-MC)");
} else if (brdp->brdtype == BRD_ECHPCI) {
brdp->ioctrl = brdp->ioaddr1 + 2;
request_region(brdp->ioaddr1, 4, "serial(EC8/32-PCI)");
request_region(brdp->ioaddr2, 8, "serial(EC8/32-PCI-secondary)");
}
/*
* Scan through the secondary io address space looking for panels.
* As we find'em allocate and initialize panel structures for each.
*/
ioaddr = brdp->ioaddr2;
panelnr = 0;
nxtid = 0;
for (i = 0; (i < STL_MAXPANELS); i++) {
if (brdp->brdtype == BRD_ECHPCI) {
outb(nxtid, brdp->ioctrl);
ioaddr = brdp->ioaddr2;
}
status = inb(ioaddr + ECH_PNLSTATUS);
if ((status & ECH_PNLIDMASK) != nxtid)
break;
panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t));
if (panelp == (stlpanel_t *) NULL) {
printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlpanel_t));
break;
}
memset(panelp, 0, sizeof(stlpanel_t));
panelp->brdnr = brdp->brdnr;
panelp->panelnr = panelnr;
panelp->iobase = ioaddr;
panelp->pagenr = nxtid;
if (status & ECH_PNL16PORT) {
if ((brdp->nrports + 16) > 32)
break;
panelp->nrports = 16;
panelp->ackmask = 0x80;
brdp->nrports += 16;
ioaddr += (EREG_BANKSIZE * 2);
nxtid += 2;
} else {
panelp->nrports = 8;
panelp->ackmask = 0xc0;
brdp->nrports += 8;
ioaddr += EREG_BANKSIZE;
nxtid++;
}
brdp->panels[panelnr++] = panelp;
brdp->nrpanels++;
if (ioaddr >= (brdp->ioaddr2 + 0x20))
break;
}
if (brdp->brdtype == BRD_ECH)
outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl);
brdp->state |= BRD_FOUND;
i = stl_mapirq(brdp->irq);
return(i);
}
/*****************************************************************************/
/*
* Initialize and configure the specified board.
* Scan through all the boards in the configuration and see what we
* can find. Handle EIO and the ECH boards a little differently here
* since the initial search and setup is too different.
*/
static int stl_brdinit(stlbrd_t *brdp)
{
int i;
#if DEBUG
printk("stl_brdinit(brdp=%x)\n", (int) brdp);
#endif
switch (brdp->brdtype) {
case BRD_EASYIO:
stl_initeio(brdp);
break;
case BRD_ECH:
case BRD_ECHMC:
case BRD_ECHPCI:
stl_initech(brdp);
break;
default:
printk("STALLION: unit=%d is unknown board type=%d\n", brdp->brdnr, brdp->brdtype);
return(ENODEV);
}
stl_brds[brdp->brdnr] = brdp;
if ((brdp->state & BRD_FOUND) == 0) {
printk("STALLION: %s board not found, unit=%d io=%x irq=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq);
return(ENODEV);
}
for (i = 0; (i < STL_MAXPANELS); i++)
if (brdp->panels[i] != (stlpanel_t *) NULL)
stl_initports(brdp, brdp->panels[i]);
printk("STALLION: %s found, unit=%d io=%x irq=%d nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels, brdp->nrports);
return(0);
}
/*****************************************************************************/
/*
* Find any ECH-PCI boards that might be installed. Initialize each
* one as it is found.
*/
#ifdef CONFIG_PCI
static int stl_findpcibrds()
{
stlbrd_t *brdp;
unsigned char busnr, devnr, irq;
unsigned short class;
unsigned int ioaddr;
int i, rc;
#if DEBUG
printk("stl_findpcibrds()\n");
#endif
if (pcibios_present()) {
for (i = 0; (i < STL_MAXBRDS); i++) {
if (pcibios_find_device(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, i, &busnr, &devnr))
break;
/*
* Found a device on the PCI bus that has our vendor and
* device ID. Need to check now that it is really us.
*/
if ((rc = pcibios_read_config_word(busnr, devnr, PCI_CLASS_DEVICE, &class))) {
printk("STALLION: failed to read class type from PCI board, errno=%x\n", rc);
continue;
}
if (class == PCI_CLASS_STORAGE_IDE)
continue;
if (stl_nrbrds >= STL_MAXBRDS) {
printk("STALLION: too many boards found, maximum supported %d\n", STL_MAXBRDS);
break;
}
/*
* We have a Stallion board. Allocate a board structure
* and initialize it. Read its IO and IRQ resources
* from conf space.
*/
brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t));
if (brdp == (stlbrd_t *) NULL) {
printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlbrd_t));
return(-ENOMEM);
}
memset(brdp, 0, sizeof(stlbrd_t));
brdp->brdnr = stl_nrbrds++;
brdp->brdtype = BRD_ECHPCI;
if ((rc = pcibios_read_config_dword(busnr, devnr, PCI_BASE_ADDRESS_0, &ioaddr))) {
printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc);
continue;
}
brdp->ioaddr2 = (ioaddr & PCI_BASE_ADDRESS_IO_MASK);
if ((rc = pcibios_read_config_dword(busnr, devnr, PCI_BASE_ADDRESS_1, &ioaddr))) {
printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc);
continue;
}
brdp->ioaddr1 = (ioaddr & PCI_BASE_ADDRESS_IO_MASK);
#if DEBUG
printk("%s(%d): BAR0=%x BAR1=%x\n", __FILE__, __LINE__, brdp->ioaddr2, brdp->ioaddr1);
#endif
if ((rc = pcibios_read_config_byte(busnr, devnr, PCI_INTERRUPT_LINE, &irq))) {
printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc);
continue;
}
brdp->irq = irq;
#if 0
ioaddr = 0x0c000001;
if ((rc = pcibios_write_config_dword(busnr, devnr, 0x40, ioaddr))) {
printk("STALLION: failed to write register on PCI board, errno=%x\n", rc);
continue;
}
if ((rc = pcibios_write_config_dword(busnr, devnr, 0x48, ioaddr))) {
printk("STALLION: failed to write register on PCI board, errno=%x\n", rc);
continue;
}
#endif
stl_brdinit(brdp);
}
}
return(0);
}
#endif
/*****************************************************************************/
/*
* Scan through all the boards in the configuration and see what we
* can find. Handle EIO and the ECH boards a little differently here
* since the initial search and setup is too different.
*/
static int stl_initbrds()
{
stlbrd_t *brdp;
stlconf_t *confp;
int i;
#if DEBUG
printk("stl_initbrds()\n");
#endif
if (stl_nrbrds > STL_MAXBRDS) {
printk("STALLION: too many boards in configuration table, truncating to %d\n", STL_MAXBRDS);
stl_nrbrds = STL_MAXBRDS;
}
/*
* Firstly scan the list of static boards configured. Allocate
* resources and initialize the boards as found.
*/
for (i = 0; (i < stl_nrbrds); i++) {
confp = &stl_brdconf[i];
brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t));
if (brdp == (stlbrd_t *) NULL) {
printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlbrd_t));
return(-ENOMEM);
}
memset(brdp, 0, sizeof(stlbrd_t));
brdp->brdnr = i;
brdp->brdtype = confp->brdtype;
brdp->ioaddr1 = confp->ioaddr1;
brdp->ioaddr2 = confp->ioaddr2;
brdp->irq = confp->irq;
brdp->irqtype = confp->irqtype;
stl_brdinit(brdp);
}
#ifdef CONFIG_PCI
/*
* If the PCI BIOS support is compiled in then lets go looking for
* ECH-PCI boards.
*/
stl_findpcibrds();
#endif
return(0);
}
/*****************************************************************************/
long stl_init(long kmem_start)
{
printk("%s: version %s\n", stl_drvname, stl_drvversion);
#ifndef MODULE
stl_meminit(kmem_start);
#endif
stl_initbrds();
/*
* Allocate a temporary write buffer.
*/
stl_tmpwritebuf = (char *) stl_memalloc(STL_TXBUFSIZE);
if (stl_tmpwritebuf == (char *) NULL)
printk("STALLION: failed to allocate memory (size=%d)\n", STL_TXBUFSIZE);
/*
* Set up the tty driver structure and register us as a driver.
* Also setup the callout tty device.
*/
memset(&stl_serial, 0, sizeof(struct tty_driver));
stl_serial.magic = TTY_DRIVER_MAGIC;
stl_serial.name = stl_serialname;
stl_serial.major = STL_SERIALMAJOR;
stl_serial.minor_start = 0;
stl_serial.num = STL_MAXBRDS * STL_MAXPORTS;
stl_serial.type = TTY_DRIVER_TYPE_SERIAL;
stl_serial.subtype = STL_DRVTYPSERIAL;
stl_serial.init_termios = stl_deftermios;
stl_serial.flags = TTY_DRIVER_REAL_RAW;
stl_serial.refcount = &stl_refcount;
stl_serial.table = stl_ttys;
stl_serial.termios = stl_termios;
stl_serial.termios_locked = stl_termioslocked;
stl_serial.open = stl_open;
stl_serial.close = stl_close;
stl_serial.write = stl_write;
stl_serial.put_char = stl_putchar;
stl_serial.flush_chars = stl_flushchars;
stl_serial.write_room = stl_writeroom;
stl_serial.chars_in_buffer = stl_charsinbuffer;
stl_serial.ioctl = stl_ioctl;
stl_serial.set_termios = stl_settermios;
stl_serial.throttle = stl_throttle;
stl_serial.unthrottle = stl_unthrottle;
stl_serial.stop = stl_stop;
stl_serial.start = stl_start;
stl_serial.hangup = stl_hangup;
stl_serial.flush_buffer = stl_flushbuffer;
stl_callout = stl_serial;
stl_callout.name = stl_calloutname;
stl_callout.major = STL_CALLOUTMAJOR;
stl_callout.subtype = STL_DRVTYPCALLOUT;
if (tty_register_driver(&stl_serial))
printk("STALLION: failed to register serial driver\n");
if (tty_register_driver(&stl_callout))
printk("STALLION: failed to register callout driver\n");
#ifndef MODULE
kmem_start = stl_memhalt();
#endif
return(kmem_start);
}
/*****************************************************************************/
......@@ -1788,6 +1788,12 @@ long tty_init(long kmem_start)
#endif
#ifdef CONFIG_CYCLADES
kmem_start = cy_init(kmem_start);
#endif
#ifdef CONFIG_STALLION
kmem_start = stl_init(kmem_start);
#endif
#ifdef CONFIG_ISTALLION
kmem_start = stli_init(kmem_start);
#endif
kmem_start = pty_init(kmem_start);
kmem_start = vcs_init(kmem_start);
......
......@@ -1042,7 +1042,7 @@ static unsigned long check_aligned(struct buffer_head * first, unsigned long add
while (nrbuf-- > 0)
brelse(bh[nrbuf]);
free_page(address);
++current->mm->min_flt;
++current->min_flt;
return page;
no_go:
while (nrbuf-- > 0)
......@@ -1100,7 +1100,7 @@ static unsigned long try_to_load_aligned(unsigned long address,
read_buffers(arr,block);
while (block-- > 0)
brelse(arr[block]);
++current->mm->maj_flt;
++current->maj_flt;
return address;
not_aligned:
while ((tmp = bh) != NULL) {
......@@ -1154,7 +1154,7 @@ unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, in
if (where)
return where;
}
++current->mm->maj_flt;
++current->maj_flt;
for (i=0, j=0; j<PAGE_SIZE ; i++, j+= size) {
bh[i] = NULL;
if (b[i])
......
/*
* linux/fs/isofs/inode.c
*
* (C) 1992, 1993, 1994 Eric Youngdale Modified for ISO9660 filesystem.
* 1995 Mark Dobie - patch to allow VideoCD and PhotoCD mounting.
*
* (C) 1991 Linus Torvalds - minix filesystem
* 1992, 1993, 1994 Eric Youngdale Modified for ISO9660 filesystem.
* 1994 Eberhard Moenkeberg - multi session handling.
* 1995 Mark Dobie - allow mounting of some weird VideoCDs and PhotoCDs.
*
*/
#ifdef MODULE
......@@ -152,7 +153,9 @@ static int parse_options(char *options, struct iso9660_options * popt)
return 1;
}
/*
* look if the driver can tell the multi session redirection value
*/
static unsigned int isofs_get_last_session(int dev)
{
struct cdrom_multisession ms_info;
......@@ -161,10 +164,6 @@ static unsigned int isofs_get_last_session(int dev)
extern struct file_operations * get_blkfops(unsigned int);
int i;
/*
* look if the driver can tell the multi session redirection value
* <emoenke@gwdg.de>
*/
vol_desc_start=0;
if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
{
......@@ -565,7 +564,7 @@ void isofs_read_inode(struct inode * inode)
inode->i_op = NULL;
/* get the volume sequence numner */
/* get the volume sequence number */
volume_seq_no = isonum_723 (raw_inode->volume_sequence_number) ;
/*
......
......@@ -449,10 +449,10 @@ static int get_stat(int pid, char * buffer)
tsk->tty ? tsk->tty->device : 0,
tty_pgrp,
tsk->flags,
tsk->mm ? tsk->mm->min_flt : 0,
tsk->mm ? tsk->mm->cmin_flt : 0,
tsk->mm ? tsk->mm->maj_flt : 0,
tsk->mm ? tsk->mm->cmaj_flt : 0,
tsk->min_flt,
tsk->cmin_flt,
tsk->maj_flt,
tsk->cmaj_flt,
tsk->utime,
tsk->stime,
tsk->cutime,
......
......@@ -95,7 +95,6 @@ struct mouse_status {
};
/* Function Prototypes */
extern long mouse_init(long);
#endif
/*****************************************************************************/
/*
* cd1400.h -- cd1400 UART hardware info.
*
* Copyright (C) 1994,1995 Greg Ungerer (gerg@stallion.oz.au).
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*****************************************************************************/
#ifndef _CD1400_H
#define _CD1400_H
/*****************************************************************************/
/*
* Define the number of async ports per cd1400 uart chip.
*/
#define CD1400_PORTS 4
#define CD1400_CLKHZ 25000000
/*
* Define the cd1400 uarts internal FIFO sizes.
*/
#define CD1400_TXFIFOSIZE 12
#define CD1400_RXFIFOSIZE 12
/*
* Local RX FIFO thresh hold level. Also define the RTS thresh hold
* based on the RX thresh hold.
*/
#define FIFO_RXTHRESHOLD 6
#define FIFO_RTSTHRESHOLD 7
/*****************************************************************************/
/*
* Define the cd1400 register addresses. These are all the valid
* registers with the cd1400. Some are global, some virtual, some
* per port.
*/
#define GFRCR 0x40
#define CAR 0x68
#define GCR 0x4b
#define SVRR 0x67
#define RICR 0x44
#define TICR 0x45
#define MICR 0x46
#define RIR 0x6b
#define TIR 0x6a
#define MIR 0x69
#define PPR 0x7e
#define RIVR 0x43
#define TIVR 0x42
#define MIVR 0x41
#define TDR 0x63
#define RDSR 0x62
#define MISR 0x4c
#define EOSRR 0x60
#define LIVR 0x18
#define CCR 0x05
#define SRER 0x06
#define COR1 0x08
#define COR2 0x09
#define COR3 0x0a
#define COR4 0x1e
#define COR5 0x1f
#define CCSR 0x0b
#define RDCR 0x0e
#define SCHR1 0x1a
#define SCHR2 0x1b
#define SCHR3 0x1c
#define SCHR4 0x1d
#define SCRL 0x22
#define SCRH 0x23
#define LNC 0x24
#define MCOR1 0x15
#define MCOR2 0x16
#define RTPR 0x21
#define MSVR1 0x6c
#define MSVR2 0x6d
#define PSVR 0x6f
#define RBPR 0x78
#define RCOR 0x7c
#define TBPR 0x72
#define TCOR 0x76
/*****************************************************************************/
/*
* Define the set of baud rate clock divisors.
*/
#define CD1400_CLK0 8
#define CD1400_CLK1 32
#define CD1400_CLK2 128
#define CD1400_CLK3 512
#define CD1400_CLK4 2048
#define CD1400_NUMCLKS 5
/*****************************************************************************/
/*
* Define the clock pre-scalar value to be a 5 ms clock. This should be
* OK for now. It would probably be better to make it 10 ms, but we
* can't fit that divisor into 8 bits!
*/
#define PPR_SCALAR 244
/*****************************************************************************/
/*
* Define values used to set character size options.
*/
#define COR1_CHL5 0x00
#define COR1_CHL6 0x01
#define COR1_CHL7 0x02
#define COR1_CHL8 0x03
/*
* Define values used to set the number of stop bits.
*/
#define COR1_STOP1 0x00
#define COR1_STOP15 0x04
#define COR1_STOP2 0x08
/*
* Define values used to set the parity scheme in use.
*/
#define COR1_PARNONE 0x00
#define COR1_PARFORCE 0x20
#define COR1_PARENB 0x40
#define COR1_PARIGNORE 0x10
#define COR1_PARODD 0x80
#define COR1_PAREVEN 0x00
#define COR2_IXM 0x80
#define COR2_TXIBE 0x40
#define COR2_ETC 0x20
#define COR2_LLM 0x10
#define COR2_RLM 0x08
#define COR2_RTSAO 0x04
#define COR2_CTSAE 0x02
#define COR3_SCDRNG 0x80
#define COR3_SCD34 0x40
#define COR3_FCT 0x20
#define COR3_SCD12 0x10
/*
* Define values used by COR4.
*/
#define COR4_BRKINT 0x08
#define COR4_IGNBRK 0x18
/*****************************************************************************/
/*
* Define the modem control register values.
* Note that the actual hardware is a little different to the conventional
* pin names on the cd1400.
*/
#define MSVR1_DTR 0x01
#define MSVR1_DSR 0x10
#define MSVR1_RI 0x20
#define MSVR1_CTS 0x40
#define MSVR1_DCD 0x80
#define MSVR2_RTS 0x02
#define MSVR2_DSR 0x10
#define MSVR2_RI 0x20
#define MSVR2_CTS 0x40
#define MSVR2_DCD 0x80
#define MCOR1_DCD 0x80
#define MCOR1_CTS 0x40
#define MCOR1_RI 0x20
#define MCOR1_DSR 0x10
#define MCOR2_DCD 0x80
#define MCOR2_CTS 0x40
#define MCOR2_RI 0x20
#define MCOR2_DSR 0x10
/*****************************************************************************/
/*
* Define the bits used with the service (interrupt) enable register.
*/
#define SRER_NNDT 0x01
#define SRER_TXEMPTY 0x02
#define SRER_TXDATA 0x04
#define SRER_RXDATA 0x10
#define SRER_MODEM 0x80
/*****************************************************************************/
/*
* Define operational commands for the command register.
*/
#define CCR_RESET 0x80
#define CCR_CORCHANGE 0x4e
#define CCR_SENDCH 0x20
#define CCR_CHANCTRL 0x10
#define CCR_TXENABLE (CCR_CHANCTRL | 0x08)
#define CCR_TXDISABLE (CCR_CHANCTRL | 0x04)
#define CCR_RXENABLE (CCR_CHANCTRL | 0x02)
#define CCR_RXDISABLE (CCR_CHANCTRL | 0x01)
#define CCR_SENDSCHR1 (CCR_SENDCH | 0x01)
#define CCR_SENDSCHR2 (CCR_SENDCH | 0x02)
#define CCR_SENDSCHR3 (CCR_SENDCH | 0x03)
#define CCR_SENDSCHR4 (CCR_SENDCH | 0x04)
#define CCR_RESETCHAN (CCR_RESET | 0x00)
#define CCR_RESETFULL (CCR_RESET | 0x01)
#define CCR_TXFLUSHFIFO (CCR_RESET | 0x02)
#define CCR_MAXWAIT 10000
/*****************************************************************************/
/*
* Define the valid acknowledgement types (for hw ack cycle).
*/
#define ACK_TYPMASK 0x07
#define ACK_TYPTX 0x02
#define ACK_TYPMDM 0x01
#define ACK_TYPRXGOOD 0x03
#define ACK_TYPRXBAD 0x07
#define SVRR_RX 0x01
#define SVRR_TX 0x02
#define SVRR_MDM 0x04
#define ST_OVERRUN 0x01
#define ST_FRAMING 0x02
#define ST_PARITY 0x04
#define ST_BREAK 0x08
#define ST_SCHAR1 0x10
#define ST_SCHAR2 0x20
#define ST_SCHAR3 0x30
#define ST_SCHAR4 0x40
#define ST_RANGE 0x70
#define ST_TIMEOUT 0x80
#define MISR_DCD 0x80
#define MISR_CTS 0x40
#define MISR_RI 0x20
#define MISR_DSR 0x10
/*****************************************************************************/
/*
* Defines for the CCSR status register.
*/
#define CCSR_RXENABLED 0x80
#define CCSR_RXFLOWON 0x40
#define CCSR_RXFLOWOFF 0x20
#define CCSR_TXENABLED 0x08
#define CCSR_TXFLOWON 0x04
#define CCSR_TXFLOWOFF 0x02
/*****************************************************************************/
/*
* Define the embedded commands.
*/
#define ETC_CMD 0x00
#define ETC_STARTBREAK 0x81
#define ETC_DELAY 0x82
#define ETC_STOPBREAK 0x83
/*****************************************************************************/
#endif
/*****************************************************************************/
/*
* cdk.h -- CDK interface definitions.
*
* Copyright (C) 1994,1995 Greg Ungerer (gerg@stallion.oz.au).
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*****************************************************************************/
#ifndef _CDK_H
#define _CDK_H
/*****************************************************************************/
#pragma pack(2)
/*
* The following set of definitions is used to communicate with the
* shared memory interface of the Stallion intelligent multiport serial
* boards. The definitions in this file are taken directly from the
* document titled "Generic Stackable Interface, Downloader and
* Communications Development Kit".
*/
/*
* Define the set of importrant shared memory addresses. These are
* required to intialize the board and get things started. All of these
* addresses are relative to the start of the shared memory.
*/
#define CDK_SIGADDR 0x200
#define CDK_FEATADDR 0x280
#define CDK_CDKADDR 0x300
#define CDK_RDYADDR 0x262
#define CDK_ALIVEMARKER 13
/*
* On hardware power up the ROMs located on the EasyConnection 8/64 will
* fill out the following signature information into shared memory. This
* way the host system can quickly determine that the board is present
* and is operational.
*/
typedef struct cdkecpsig {
unsigned long magic;
unsigned short romver;
unsigned short cputype;
unsigned char panelid[8];
} cdkecpsig_t;
#define ECP_MAGIC 0x21504345
/*
* On hardware power up the ROMs located on the ONboard, Stallion and
* Brumbys will fill out the following signature information into shared
* memory. This way the host system can quickly determine that the board
* is present and is operational.
*/
typedef struct cdkonbsig {
unsigned short magic0;
unsigned short magic1;
unsigned short magic2;
unsigned short magic3;
unsigned short romver;
unsigned short memoff;
unsigned short memseg;
unsigned short amask0;
unsigned short pic;
unsigned short status;
unsigned short btype;
unsigned short clkticks;
unsigned short clkspeed;
unsigned short amask1;
unsigned short amask2;
} cdkonbsig_t;
#define ONB_MAGIC0 0xf2a7
#define ONB_MAGIC1 0xa149
#define ONB_MAGIC2 0x6352
#define ONB_MAGIC3 0xf121
/*
* Define the feature area structure. The feature area is the set of
* startup parameters used by the slave image when it starts executing.
* They allow for the specification of buffer sizes, debug trace, etc.
*/
typedef struct cdkfeature {
unsigned long debug;
unsigned long banner;
unsigned long etype;
unsigned long nrdevs;
unsigned long brdspec;
unsigned long txrqsize;
unsigned long rxrqsize;
unsigned long flags;
} cdkfeature_t;
#define ETYP_DDK 0
#define ETYP_CDK 1
/*
* Define the CDK header structure. This is the info that the slave
* environment sets up after it has been downloaded and started. It
* essentially provides a memory map for the shared memory interface.
*/
typedef struct cdkhdr {
unsigned short command;
unsigned short status;
unsigned short port;
unsigned short mode;
unsigned long cmd_buf[14];
unsigned short alive_cnt;
unsigned short intrpt_mode;
unsigned char intrpt_id[8];
unsigned char ver_release;
unsigned char ver_modification;
unsigned char ver_fix;
unsigned char deadman_restart;
unsigned short deadman;
unsigned short nrdevs;
unsigned long memp;
unsigned long hostp;
unsigned long slavep;
unsigned char hostreq;
unsigned char slavereq;
unsigned char cmd_reserved[30];
} cdkhdr_t;
#define MODE_DDK 0
#define MODE_CDK 1
#define IMD_INTR 0x0
#define IMD_PPINTR 0x1
#define IMD_POLL 0xff
/*
* Define the memory mapping structure. This structure is pointed to by
* the memp field in the stlcdkhdr struct. As many as these structures
* as required are layed out in shared memory to define how the rest of
* shared memory is divided up. There will be one for each port.
*/
typedef struct cdkmem {
unsigned short dtype;
unsigned long offset;
} cdkmem_t;
#define TYP_UNDEFINED 0x0
#define TYP_ASYNCTRL 0x1
#define TYP_ASYNC 0x20
#define TYP_PARALLEL 0x40
#define TYP_SYNCX21 0x60
/*****************************************************************************/
/*
* Following is a set of defines and structures used to actually deal
* with the serial ports on the board. Firstly is the set of commands
* that can be applied to ports.
*/
#define ASYCMD (((unsigned long) 'a') << 8)
#define A_NULL (ASYCMD | 0)
#define A_FLUSH (ASYCMD | 1)
#define A_BREAK (ASYCMD | 2)
#define A_GETPORT (ASYCMD | 3)
#define A_SETPORT (ASYCMD | 4)
#define A_SETPORTF (ASYCMD | 5)
#define A_SETPORTFTX (ASYCMD | 6)
#define A_SETPORTFRX (ASYCMD | 7)
#define A_GETSIGNALS (ASYCMD | 8)
#define A_SETSIGNALS (ASYCMD | 9)
#define A_SETSIGNALSF (ASYCMD | 10)
#define A_SETSIGNALSFTX (ASYCMD | 11)
#define A_SETSIGNALSFRX (ASYCMD | 12)
#define A_GETNOTIFY (ASYCMD | 13)
#define A_SETNOTIFY (ASYCMD | 14)
#define A_NOTIFY (ASYCMD | 15)
#define A_PORTCTRL (ASYCMD | 16)
#define A_GETSTATS (ASYCMD | 17)
#define A_RQSTATE (ASYCMD | 18)
#define A_FLOWSTATE (ASYCMD | 19)
/*
* Define those arguments used for simple commands.
*/
#define FLUSHRX 0x1
#define FLUSHTX 0x2
#define BREAKON -1
#define BREAKOFF -2
/*
* Define the port setting structure, and all those defines that go along
* with it. Basically this structure defines the charcateristics of this
* port: baud rate, chars, parity, input/output char cooking etc.
*/
typedef struct asyport {
unsigned long baudout;
unsigned long baudin;
unsigned long iflag;
unsigned long oflag;
unsigned long lflag;
unsigned long pflag;
unsigned long flow;
unsigned long spare1;
unsigned short vtime;
unsigned short vmin;
unsigned short txlo;
unsigned short txhi;
unsigned short rxlo;
unsigned short rxhi;
unsigned short rxhog;
unsigned short spare2;
unsigned char csize;
unsigned char stopbs;
unsigned char parity;
unsigned char stopin;
unsigned char startin;
unsigned char stopout;
unsigned char startout;
unsigned char parmark;
unsigned char brkmark;
unsigned char cc[11];
} asyport_t;
#define PT_STOP1 0x0
#define PT_STOP15 0x1
#define PT_STOP2 0x2
#define PT_NOPARITY 0x0
#define PT_ODDPARITY 0x1
#define PT_EVENPARITY 0x2
#define PT_MARKPARITY 0x3
#define PT_SPACEPARITY 0x4
#define F_NONE 0x0
#define F_IXON 0x1
#define F_IXOFF 0x2
#define F_IXANY 0x4
#define F_IOXANY 0x8
#define F_RTSFLOW 0x10
#define F_CTSFLOW 0x20
#define F_DTRFLOW 0x40
#define F_DCDFLOW 0x80
#define F_DSROFLOW 0x100
#define F_DSRIFLOW 0x200
#define FI_NORX 0x1
#define FI_RAW 0x2
#define FI_ISTRIP 0x4
#define FI_UCLC 0x8
#define FI_INLCR 0x10
#define FI_ICRNL 0x20
#define FI_IGNCR 0x40
#define FI_IGNBREAK 0x80
#define FI_DSCRDBREAK 0x100
#define FI_1MARKBREAK 0x200
#define FI_2MARKBREAK 0x400
#define FI_XCHNGBREAK 0x800
#define FI_IGNRXERRS 0x1000
#define FI_DSCDRXERRS 0x2000
#define FI_1MARKRXERRS 0x4000
#define FI_2MARKRXERRS 0x8000
#define FI_XCHNGRXERRS 0x10000
#define FI_DSCRDNULL 0x20000
#define FO_OLCUC 0x1
#define FO_ONLCR 0x2
#define FO_OOCRNL 0x4
#define FO_ONOCR 0x8
#define FO_ONLRET 0x10
#define FO_ONL 0x20
#define FO_OBS 0x40
#define FO_OVT 0x80
#define FO_OFF 0x100
#define FO_OTAB1 0x200
#define FO_OTAB2 0x400
#define FO_OTAB3 0x800
#define FO_OCR1 0x1000
#define FO_OCR2 0x2000
#define FO_OCR3 0x4000
#define FO_OFILL 0x8000
#define FO_ODELL 0x10000
#define P_RTSLOCK 0x1
#define P_CTSLOCK 0x2
#define P_MAPRTS 0x4
#define P_MAPCTS 0x8
#define P_LOOPBACK 0x10
#define P_DTRFOLLOW 0x20
#define P_FAKEDCD 0x40
/*
* Define a structure to communicate serial port signal and data state
* information.
*/
typedef struct asysigs {
unsigned long data;
unsigned long signal;
unsigned long sigvalue;
} asysigs_t;
#define DT_TXBUSY 0x1
#define DT_TXEMPTY 0x2
#define DT_TXLOW 0x4
#define DT_TXHIGH 0x8
#define DT_TXFULL 0x10
#define DT_TXHOG 0x20
#define DT_TXFLOWED 0x40
#define DT_TXBREAK 0x80
#define DT_RXBUSY 0x100
#define DT_RXEMPTY 0x200
#define DT_RXLOW 0x400
#define DT_RXHIGH 0x800
#define DT_RXFULL 0x1000
#define DT_RXHOG 0x2000
#define DT_RXFLOWED 0x4000
#define DT_RXBREAK 0x8000
#define SG_DTR 0x1
#define SG_DCD 0x2
#define SG_RTS 0x4
#define SG_CTS 0x8
#define SG_DSR 0x10
#define SG_RI 0x20
/*
* Define the notification setting structure. This is used to tell the
* port what events we want to be informed about. Fields here use the
* same defines as for the asysigs structure above.
*/
typedef struct asynotify {
unsigned long ctrl;
unsigned long data;
unsigned long signal;
unsigned long sigvalue;
} asynotify_t;
/*
* Define the port control structure. It is used to do fine grain
* control operations on the port.
*/
typedef struct {
unsigned long rxctrl;
unsigned long txctrl;
char rximdch;
char tximdch;
char spare1;
char spare2;
} asyctrl_t;
#define CT_ENABLE 0x1
#define CT_DISABLE 0x2
#define CT_STOP 0x4
#define CT_START 0x8
#define CT_STARTFLOW 0x10
#define CT_STOPFLOW 0x20
#define CT_SENDCHR 0x40
/*
* Define the stats structure kept for each port. This is a useful set
* of data collected for each port on the slave. The A_GETSTATS command
* is used to retrive this data from the slave.
*/
typedef struct asystats {
unsigned long opens;
unsigned long txchars;
unsigned long rxchars;
unsigned long txringq;
unsigned long rxringq;
unsigned long txmsgs;
unsigned long rxmsgs;
unsigned long overruns;
unsigned long framing;
unsigned long parity;
unsigned long ringover;
unsigned long lost;
unsigned long rxstart;
unsigned long rxstop;
unsigned long txstart;
unsigned long txstop;
unsigned long dcdcnt;
unsigned long dtrcnt;
unsigned long ctscnt;
unsigned long rtscnt;
unsigned long dsrcnt;
unsigned long ricnt;
unsigned long txbreaks;
unsigned long rxbreaks;
unsigned long signals;
unsigned long state;
} asystats_t;
/*****************************************************************************/
/*
* All command and control communication with a device on the slave is
* via a control block in shared memory. Each device has its own control
* block, defined by the following structure. The control block allows
* the host to open, close and control the device on the slave.
*/
typedef struct cdkctrl {
unsigned char open;
unsigned char close;
unsigned long openarg;
unsigned long closearg;
unsigned long cmd;
unsigned long status;
unsigned long args[32];
} cdkctrl_t;
/*
* Each device on the slave passes data to and from the host via a ring
* queue in shared memory. Define a ring queue structure to hold the
* vital information about each ring queue. Two ring queues will be
* allocated for each port, one for reveice data and one for transmit
* data.
*/
typedef struct cdkasyrq {
unsigned long offset;
unsigned short size;
unsigned short head;
unsigned short tail;
} cdkasyrq_t;
/*
* Each asynchronous port is defined in shared memory by the following
* structure. It contains a control block to command a device, and also
* the neccessary data channel information as well.
*/
typedef struct cdkasy {
cdkctrl_t ctrl;
unsigned short notify;
asynotify_t changed;
unsigned short receive;
cdkasyrq_t rxq;
unsigned short transmit;
cdkasyrq_t txq;
} cdkasy_t;
#pragma pack()
/*****************************************************************************/
/*
* Define the set of ioctls used by the driver to do special things
* to the board. These include interrupting it, and initializeing
* the driver after board startup and shutdown.
*/
#define STLCMD (((unsigned long) 's') << 8)
#define STL_BINTR (STLCMD | 20)
#define STL_BSTART (STLCMD | 21)
#define STL_BSTOP (STLCMD | 22)
#define STL_BRESET (STLCMD | 23)
/*****************************************************************************/
#endif
/****************************************************************************************
* *
* general (not only SCSI) header library for linux CDROM drivers *
* (C) 1992 David Giller rafetmad@oxy.edu *
* 1994 Eberhard Moenkeberg emoenke@gwdg.de ("read audio" and some other stuff) *
* *
* <linux/cdrom.h> -- CD-ROM IOCTLs and structs *
* *
****************************************************************************************/
#ifndef _LINUX_CDROM_H
#define _LINUX_CDROM_H
/*
* some fix numbers
*/
#define CD_MINS 74 /* max. minutes per CD */
#define CD_SECS 60 /* seconds per minute */
#define CD_FRAMES 75 /* frames per second */
#define CD_CHUNK_SIZE 24 /* lowest-level "data bytes piece" */
#define CD_NUM_OF_CHUNKS 98 /* chunks per frame */
#define CD_FRAMESIZE 2048 /* bytes per frame, cooked mode */
#define CD_FRAMESIZE_RAW0 2336 /* bytes per frame, "raw" mode */
#define CD_FRAMESIZE_XA 2340 /* bytes per frame, "xa" mode */
#define CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */
#define CD_FRAMESIZE_SUB 96 /* subchannel data size */
#define CD_BLOCK_OFFSET 150 /* offset of first logical frame */
#define CD_XA_HEAD 12 /* header size of XA frame */
#define CD_XA_TAIL 280 /* tail size of XA frame */
#define CD_XA_SYNC_HEAD CD_XA_HEAD+12 /* sync bytes + header of XA frame */
/*
* -- <linux/cdrom.h>
* general (not only SCSI) header library for linux CDROM drivers
* (C) 1992 David Giller rafetmad@oxy.edu
* 1994, 1995 Eberhard Moenkeberg emoenke@gwdg.de
*
* For IOCTL calls, we will commandeer byte 0x53, or 'S'.
*
*/
/*
* CD-ROM-specific SCSI command opcodes
*/
/*
* Group 2 (10-byte). All of these are called 'optional' by SCSI-II.
*/
#define SCMD_READ_TOC 0x43 /* read table of contents */
#define SCMD_PLAYAUDIO_MSF 0x47 /* play data at time offset */
#define SCMD_PLAYAUDIO_TI 0x48 /* play data at track/index */
#define SCMD_PAUSE_RESUME 0x4B /* pause/resume audio */
#define SCMD_READ_SUBCHANNEL 0x42 /* read SC info on playing disc */
#define SCMD_PLAYAUDIO10 0x45 /* play data at logical block */
#define SCMD_READ_HEADER 0x44 /* read TOC header */
/*
* Group 5
*/
#define SCMD_PLAYAUDIO12 0xA5 /* play data at logical block */
#define SCMD_PLAYTRACK_REL12 0xA9 /* play track at relative offset*/
#ifndef _LINUX_CDROM_H
#define _LINUX_CDROM_H
/*
* Group 6 Commands
* some fix numbers
*/
#define CD_MINS 74 /* max. minutes per CD, not really a limit */
#define CD_SECS 60 /* seconds per minute */
#define CD_FRAMES 75 /* frames per second */
#define SCMD_CD_PLAYBACK_CONTROL 0xC9 /* Sony vendor-specific audio */
#define SCMD_CD_PLAYBACK_STATUS 0xC4 /* control opcodes. info please!*/
#define CD_SYNC_SIZE 12 /* 12 sync bytes per raw data frame, not transfered by the drive */
#define CD_HEAD_SIZE 4 /* header (address) bytes per raw data frame */
#define CD_SUBHEAD_SIZE 8 /* subheader bytes per raw XA data frame */
#define CD_XA_HEAD (CD_HEAD_SIZE+CD_SUBHEAD_SIZE) /* "before data" part of raw XA frame */
#define CD_XA_SYNC_HEAD (CD_XA_HEAD+12)/* sync bytes + header of XA frame */
/*
* CD-ROM capacity structure.
*/
#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */
#define CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */
/* most drives don't deliver everything: */
#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /* 2340 */
#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /* 2336 */
struct scsi_capacity
{
u_long capacity;
u_long lbasize;
};
#define CD_EDC_SIZE 4 /* bytes EDC per most raw data frame types */
#define CD_ZERO_SIZE 8 /* bytes zero per yellow book mode 1 frame */
#define CD_ECC_SIZE 276 /* bytes ECC per most raw data frame types */
#define CD_XA_TAIL (CD_EDC_SIZE+CD_ECC_SIZE) /* "after data" part of raw XA frame */
/*
* CD-ROM MODE_SENSE/MODE_SELECT parameters
*/
#define CD_FRAMESIZE_SUB 96 /* subchannel data "frame" size */
#define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */
#define ERR_RECOVERY_PARMS 0x01
#define DISCO_RECO_PARMS 0x02
#define FORMAT_PARMS 0x03
#define GEOMETRY_PARMS 0x04
#define CERTIFICATION_PARMS 0x06
#define CACHE_PARMS 0x38
/*
* standard mode-select header prepended to all mode-select commands
*/
#define CD_CHUNK_SIZE 24 /* lowest-level "data bytes piece" */
#define CD_NUM_OF_CHUNKS 98 /* chunks per frame */
struct ccs_modesel_head
{
u_char _r1; /* reserved */
u_char medium; /* device-specific medium type */
u_char _r2; /* reserved */
u_char block_desc_length; /* block descriptor length */
u_char density; /* device-specific density code */
u_char number_blocks_hi; /* number of blocks in this block desc */
u_char number_blocks_med;
u_char number_blocks_lo;
u_char _r3;
u_char block_length_hi; /* block length for blocks in this desc */
u_short block_length;
};
#define CD_FRAMESIZE_XA CD_FRAMESIZE_RAW1 /* obsolete name */
#define CD_BLOCK_OFFSET CD_MSF_OFFSET /* obsolete name */
/*
* error recovery parameters
*/
struct ccs_err_recovery
{
u_char _r1 : 2; /* reserved */
u_char page_code : 6; /* page code */
u_char page_length; /* page length */
u_char awre : 1; /* auto write realloc enabled */
u_char arre : 1; /* auto read realloc enabled */
u_char tb : 1; /* transfer block */
u_char rc : 1; /* read continuous */
u_char eec : 1; /* enable early correction */
u_char per : 1; /* post error */
u_char dte : 1; /* disable transfer on error */
u_char dcr : 1; /* disable correction */
u_char retry_count; /* error retry count */
u_char correction_span; /* largest recov. to be attempted, bits */
u_char head_offset_count; /* head offset (2's C) for each retry */
u_char strobe_offset_count; /* data strobe " */
u_char recovery_time_limit; /* time limit on recovery attempts */
};
/*
* disco/reco parameters
*/
struct ccs_disco_reco
{
u_char _r1 : 2; /* reserved */
u_char page_code : 6; /* page code */
u_char page_length; /* page length */
u_char buffer_full_ratio; /* write buffer reconnect threshold */
u_char buffer_empty_ratio; /* read " */
u_short bus_inactivity_limit; /* limit on bus inactivity time */
u_short disconnect_time_limit; /* minimum disconnect time */
u_short connect_time_limit; /* minimum connect time */
u_short _r2; /* reserved */
};
/*
* drive geometry parameters
*/
struct ccs_geometry
{
u_char _r1 : 2; /* reserved */
u_char page_code : 6; /* page code */
u_char page_length; /* page length */
u_char cyl_ub; /* #cyls */
u_char cyl_mb;
u_char cyl_lb;
u_char heads; /* #heads */
u_char precomp_cyl_ub; /* precomp start */
u_char precomp_cyl_mb;
u_char precomp_cyl_lb;
u_char current_cyl_ub; /* reduced current start */
u_char current_cyl_mb;
u_char current_cyl_lb;
u_short step_rate; /* stepping motor rate */
u_char landing_cyl_ub; /* landing zone */
u_char landing_cyl_mb;
u_char landing_cyl_lb;
u_char _r2;
u_char _r3;
u_char _r4;
};
/*
* cache parameters
* the raw frame layout:
*
* - audio (red): | audio_sample_bytes |
* | 2352 |
*
* - data (yellow, mode1): | sync - head - data - EDC - zero - ECC |
* | 12 - 4 - 2048 - 4 - 8 - 276 |
*
* - data (yellow, mode2): | sync - head - data |
* | 12 - 4 - 2336 |
*
* - XA data (green, mode2 form1): | sync - head - sub - data - EDC - ECC |
* | 12 - 4 - 8 - 2048 - 4 - 276 |
*
* - XA data (green, mode2 form2): | sync - head - sub - data - EDC |
* | 12 - 4 - 8 - 2324 - 4 |
*/
struct ccs_cache
{
u_char _r1 : 2; /* reserved */
u_char page_code : 6; /* page code */
u_char page_length; /* page length */
u_char mode; /* cache control byte */
u_char threshold; /* prefetch threshold */
u_char max_prefetch; /* maximum prefetch size */
u_char max_multiplier; /* maximum prefetch multiplier */
u_char min_prefetch; /* minimum prefetch size */
u_char min_multiplier; /* minimum prefetch multiplier */
u_char _r2[8];
};
/*
* CDROM IOCTL structures
*/
struct cdrom_msf
{
u_char cdmsf_min0; /* start minute */
u_char cdmsf_sec0; /* start second */
u_char cdmsf_frame0; /* start frame */
u_char cdmsf_min1; /* end minute */
u_char cdmsf_sec1; /* end second */
u_char cdmsf_frame1; /* end frame */
};
{
u_char cdmsf_min0; /* start minute */
u_char cdmsf_sec0; /* start second */
u_char cdmsf_frame0; /* start frame */
u_char cdmsf_min1; /* end minute */
u_char cdmsf_sec1; /* end second */
u_char cdmsf_frame1; /* end frame */
};
struct cdrom_ti
{
u_char cdti_trk0; /* start track */
u_char cdti_ind0; /* start index */
u_char cdti_trk1; /* end track */
u_char cdti_ind1; /* end index */
};
{
u_char cdti_trk0; /* start track */
u_char cdti_ind0; /* start index */
u_char cdti_trk1; /* end track */
u_char cdti_ind1; /* end index */
};
struct cdrom_tochdr
{
u_char cdth_trk0; /* start track */
u_char cdth_trk1; /* end track */
};
{
u_char cdth_trk0; /* start track */
u_char cdth_trk1; /* end track */
};
struct cdrom_tocentry
{
{
u_char cdte_track;
u_char cdte_adr :4;
u_char cdte_ctrl :4;
u_char cdte_format;
union
{
{
struct
{
{
u_char minute;
u_char second;
u_char frame;
} msf;
} msf;
int lba;
} cdte_addr;
} cdte_addr;
u_char cdte_datamode;
};
};
/*
* CD-ROM address types (cdrom_tocentry.cdte_format)
......@@ -245,19 +115,17 @@ struct cdrom_tocentry
#define CDROM_MSF 0x02 /* "minute-second-frame": binary, not bcd here! */
/*
* bit to tell whether track is data or audio
* bit to tell whether track is data or audio (cdrom_tocentry.cdte_ctrl)
*/
#define CDROM_DATA_TRACK 0x04
/*
* The leadout track is always 0xAA, regardless of # of tracks on disc
*/
#define CDROM_LEADOUT 0xAA
struct cdrom_subchnl
{
{
u_char cdsc_format;
u_char cdsc_audiostatus;
u_char cdsc_adr: 4;
......@@ -265,74 +133,72 @@ struct cdrom_subchnl
u_char cdsc_trk;
u_char cdsc_ind;
union
{
{
struct
{
{
u_char minute;
u_char second;
u_char frame;
} msf;
} msf;
int lba;
} cdsc_absaddr;
} cdsc_absaddr;
union
{
{
struct
{
{
u_char minute;
u_char second;
u_char frame;
} msf;
} msf;
int lba;
} cdsc_reladdr;
};
} cdsc_reladdr;
};
/*
* return value from READ SUBCHANNEL DATA
* audio states (from SCSI-2, but seen with other drives, too)
*/
#define CDROM_AUDIO_INVALID 0x00 /* audio status not supported */
#define CDROM_AUDIO_PLAY 0x11 /* audio play operation in progress */
#define CDROM_AUDIO_PAUSED 0x12 /* audio play operation paused */
#define CDROM_AUDIO_COMPLETED 0x13 /* audio play successfully completed */
#define CDROM_AUDIO_ERROR 0x14 /* audio play stopped due to error */
#define CDROM_AUDIO_NO_STATUS 0x15 /* no current audio status to return */
#define CDROM_AUDIO_INVALID 0x00 /* audio status not supported */
#define CDROM_AUDIO_PLAY 0x11 /* audio play operation in progress */
#define CDROM_AUDIO_PAUSED 0x12 /* audio play operation paused */
#define CDROM_AUDIO_COMPLETED 0x13 /* audio play successfully completed */
#define CDROM_AUDIO_ERROR 0x14 /* audio play stopped due to error */
#define CDROM_AUDIO_NO_STATUS 0x15 /* no current audio status to return */
struct cdrom_volctrl
{
{
u_char channel0;
u_char channel1;
u_char channel2;
u_char channel3;
};
};
struct cdrom_read
{
{
int cdread_lba;
caddr_t cdread_bufaddr;
int cdread_buflen;
};
};
/*
* preliminary extensions for transferring audio frames
* currently used by sbpcd.c
* (still may change if other drivers will use it, too):
* extensions for transfering audio frames
* currently used by sbpcd.c, cdu31a.c, ide-cd.c
*/
struct cdrom_read_audio
{
union
{
union
{
struct
struct
{
u_char minute;
u_char second;
u_char frame;
u_char minute;
u_char second;
u_char frame;
} msf;
int lba;
} addr; /* frame address */
u_char addr_format; /* CDROM_LBA or CDROM_MSF */
int nframes; /* number of 2352-byte-frames to read at once, limited by the drivers */
u_char *buf; /* frame buffer (size: nframes*2352 bytes) */
};
int lba;
} addr; /* frame address */
u_char addr_format; /* CDROM_LBA or CDROM_MSF */
int nframes; /* number of 2352-byte-frames to read at once, limited by the drivers */
u_char *buf; /* frame buffer (size: nframes*2352 bytes) */
};
/*
* this has to be the "arg" of the CDROMMULTISESSION ioctl
......@@ -340,20 +206,20 @@ struct cdrom_read_audio
* The returned "addr" is valid only if "xa_flag" is true.
*/
struct cdrom_multisession
{
union
{
union
{
struct
struct
{
u_char minute;
u_char second;
u_char frame;
u_char minute;
u_char second;
u_char frame;
} msf;
int lba;
} addr; /* frame address: start-of-last-session (not the new "frame 16"!)*/
u_char xa_flag; /* 1: "is XA disk" */
u_char addr_format; /* CDROM_LBA or CDROM_MSF */
};
int lba;
} addr; /* frame address: start-of-last-session (not the new "frame 16"!)*/
u_char xa_flag; /* 1: "is XA disk" */
u_char addr_format; /* CDROM_LBA or CDROM_MSF */
};
#ifdef FIVETWELVE
#define CDROM_MODE1_SIZE 512
......@@ -364,71 +230,225 @@ struct cdrom_multisession
/*
* CD-ROM IOCTL commands
* For IOCTL calls, we will commandeer byte 0x53, or 'S'.
*/
#define CDROMPAUSE 0x5301 /* pause */
#define CDROMRESUME 0x5302 /* resume */
#define CDROMPAUSE 0x5301
#define CDROMRESUME 0x5302
#define CDROMPLAYMSF 0x5303 /* (struct cdrom_msf) */
#define CDROMPLAYTRKIND 0x5304 /* (struct cdrom_ti) */
#define CDROMPLAYMSF 0x5303 /* (struct cdrom_msf) */
/* SCMD_PLAY_AUDIO_MSF */
#define CDROMREADTOCHDR 0x5305 /* (struct cdrom_tochdr) */
#define CDROMREADTOCENTRY 0x5306 /* (struct cdrom_tocentry) */
#define CDROMPLAYTRKIND 0x5304 /* (struct cdrom_ti) */
/* SCMD_PLAY_AUDIO_TI */
#define CDROMSTOP 0x5307 /* stop the drive motor */
#define CDROMSTART 0x5308 /* turn the motor on */
#define CDROMREADTOCHDR 0x5305 /* (struct cdrom_tochdr) */
/* read the TOC header */
#define CDROMREADTOCENTRY 0x5306 /* (struct cdrom_tocentry) */
/* read a TOC entry */
#define CDROMEJECT 0x5309 /* eject CD-ROM media */
#define CDROMSTOP 0x5307 /* stop the drive motor */
#define CDROMSTART 0x5308 /* turn the motor on */
#define CDROMVOLCTRL 0x530a /* (struct cdrom_volctrl) */
#define CDROMEJECT 0x5309 /* eject CD-ROM media */
#define CDROMSUBCHNL 0x530b /* (struct cdrom_subchnl) */
#define CDROMVOLCTRL 0x530a /* (struct cdrom_volctrl) */
/* volume control */
#define CDROMREADMODE2 0x530c /* (struct cdrom_read) */
/* read type-2 data (not suppt) */
#define CDROMSUBCHNL 0x530b /* (struct cdrom_subchnl) */
/* read Q sub-channel data */
#define CDROMREADMODE1 0x530d /* (struct cdrom_read) */
/* read type-1 data */
#define CDROMREADMODE2 0x530c /* (struct cdrom_read) */
/* read type-2 data (not suppt) */
#define CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */
#define CDROMREADMODE1 0x530d /* (struct cdrom_read) */
/* read type-1 data */
/*
* preliminary extension for transferring audio frames
* currently used by cdu31a.c and sbpcd.c
* (still may change if other drivers will use it, too):
*/
#define CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */
/*
* preliminary extension for enable (1) / disable (0) auto-ejecting
* currently used by sbpcd.c and sr.c
* (still may change if other drivers will use it, too):
* enable (1) / disable (0) auto-ejecting
*/
#define CDROMEJECT_SW 0x530f /* arg: 0 or 1 */
#define CDROMEJECT_SW 0x530f /* arg: 0 or 1 */
/*
* obtain the start-of-last-session address of multi session disks
*/
#define CDROMMULTISESSION 0x5310 /* (struct cdrom_multisession) */
#define CDROMMULTISESSION 0x5310 /* (struct cdrom_multisession) */
/*
* obtain the "universal product code" number
* (only some data disks have it coded)
*/
#define CDROM_GET_UPC 0x5311 /* 8 bytes returned */
#define CDROM_GET_UPC 0x5311 /* 8 bytes returned */
#define CDROMRESET 0x5312 /* hard-reset the drive */
#define CDROMVOLREAD 0x5313 /* let the drive tell its volume setting */
#define CDROMRESET 0x5312 /* hard-reset the drive */
#define CDROMVOLREAD 0x5313 /* let the drive tell its volume setting */
/* (struct cdrom_volctrl) */
/*
*these ioctls are used in aztcd.c
* these ioctls are used in aztcd.c
*/
#define CDROMREADRAW 0x5314 /*read data in raw mode*/
#define CDROMREADCOOKED 0x5315 /*read data in cooked mode*/
#define CDROMSEEK 0x5316 /*seek msf address*/
#define CDROMREADRAW 0x5314 /* read data in raw mode */
#define CDROMREADCOOKED 0x5315 /* read data in cooked mode */
#define CDROMSEEK 0x5316 /*seek msf address*/
/*
* CD-ROM-specific SCSI command opcodes
*/
/*
* Group 2 (10-byte). All of these are called 'optional' by SCSI-II.
*/
#define SCMD_READ_TOC 0x43 /* read table of contents */
#define SCMD_PLAYAUDIO_MSF 0x47 /* play data at time offset */
#define SCMD_PLAYAUDIO_TI 0x48 /* play data at track/index */
#define SCMD_PAUSE_RESUME 0x4B /* pause/resume audio */
#define SCMD_READ_SUBCHANNEL 0x42 /* read SC info on playing disc */
#define SCMD_PLAYAUDIO10 0x45 /* play data at logical block */
#define SCMD_READ_HEADER 0x44 /* read TOC header */
/*
* Group 5
*/
#define SCMD_PLAYAUDIO12 0xA5 /* play data at logical block */
#define SCMD_PLAYTRACK_REL12 0xA9 /* play track at relative offset */
/*
* Group 6 Commands
*/
#define SCMD_CD_PLAYBACK_CONTROL 0xC9 /* Sony vendor-specific audio */
#define SCMD_CD_PLAYBACK_STATUS 0xC4 /* control opcodes */
/*
* CD-ROM capacity structure.
*/
struct scsi_capacity
{
u_long capacity;
u_long lbasize;
};
/*
* CD-ROM MODE_SENSE/MODE_SELECT parameters
*/
#define ERR_RECOVERY_PARMS 0x01
#define DISCO_RECO_PARMS 0x02
#define FORMAT_PARMS 0x03
#define GEOMETRY_PARMS 0x04
#define CERTIFICATION_PARMS 0x06
#define CACHE_PARMS 0x38
/*
* standard mode-select header prepended to all mode-select commands
*/
struct ccs_modesel_head
{
u_char _r1; /* reserved */
u_char medium; /* device-specific medium type */
u_char _r2; /* reserved */
u_char block_desc_length; /* block descriptor length */
u_char density; /* device-specific density code */
u_char number_blocks_hi; /* number of blocks in this block desc */
u_char number_blocks_med;
u_char number_blocks_lo;
u_char _r3;
u_char block_length_hi; /* block length for blocks in this desc */
u_short block_length;
};
/*
* error recovery parameters
*/
struct ccs_err_recovery
{
u_char _r1 : 2; /* reserved */
u_char page_code : 6; /* page code */
u_char page_length; /* page length */
u_char awre : 1; /* auto write realloc enabled */
u_char arre : 1; /* auto read realloc enabled */
u_char tb : 1; /* transfer block */
u_char rc : 1; /* read continuous */
u_char eec : 1; /* enable early correction */
u_char per : 1; /* post error */
u_char dte : 1; /* disable transfer on error */
u_char dcr : 1; /* disable correction */
u_char retry_count; /* error retry count */
u_char correction_span; /* largest recov. to be attempted, bits */
u_char head_offset_count; /* head offset (2's C) for each retry */
u_char strobe_offset_count; /* data strobe */
u_char recovery_time_limit; /* time limit on recovery attempts */
};
/*
* disco/reco parameters
*/
struct ccs_disco_reco
{
u_char _r1 : 2; /* reserved */
u_char page_code : 6; /* page code */
u_char page_length; /* page length */
u_char buffer_full_ratio; /* write buffer reconnect threshold */
u_char buffer_empty_ratio; /* read */
u_short bus_inactivity_limit; /* limit on bus inactivity time */
u_short disconnect_time_limit; /* minimum disconnect time */
u_short connect_time_limit; /* minimum connect time */
u_short _r2; /* reserved */
};
/*
* drive geometry parameters
*/
struct ccs_geometry
{
u_char _r1 : 2; /* reserved */
u_char page_code : 6; /* page code */
u_char page_length; /* page length */
u_char cyl_ub; /* #cyls */
u_char cyl_mb;
u_char cyl_lb;
u_char heads; /* #heads */
u_char precomp_cyl_ub; /* precomp start */
u_char precomp_cyl_mb;
u_char precomp_cyl_lb;
u_char current_cyl_ub; /* reduced current start */
u_char current_cyl_mb;
u_char current_cyl_lb;
u_short step_rate; /* stepping motor rate */
u_char landing_cyl_ub; /* landing zone */
u_char landing_cyl_mb;
u_char landing_cyl_lb;
u_char _r2;
u_char _r3;
u_char _r4;
};
/*
* cache parameters
*/
struct ccs_cache
{
u_char _r1 : 2; /* reserved */
u_char page_code : 6; /* page code */
u_char page_length; /* page length */
u_char mode; /* cache control byte */
u_char threshold; /* prefetch threshold */
u_char max_prefetch; /* maximum prefetch size */
u_char max_multiplier; /* maximum prefetch multiplier */
u_char min_prefetch; /* minimum prefetch size */
u_char min_multiplier; /* minimum prefetch multiplier */
u_char _r2[8];
};
#endif _LINUX_CDROM_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:
*/
......@@ -82,24 +82,24 @@ struct hd_geometry {
unsigned long start;
};
/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x30n/0x31n */
#define HDIO_GETGEO 0x301 /* get device geometry */
#define HDIO_GET_UNMASKINTR 0x302 /* get current unmask setting */
#define HDIO_GET_MULTCOUNT 0x304 /* get current IDE blockmode setting */
#define HDIO_GET_IDENTITY 0x307 /* get IDE identification info */
#define HDIO_GET_KEEPSETTINGS 0x308 /* get keep-settings-on-reset flag */
#define HDIO_GET_CHIPSET 0x309 /* get current interface type setting */
#define HDIO_GET_NOWERR 0x30a /* get ignore-write-error flag */
#define HDIO_GET_DMA 0x30b /* get use-dma flag */
#define HDIO_DRIVE_CMD 0x31f /* execute a special drive command */
/* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x32n/0x33n */
#define HDIO_SET_MULTCOUNT 0x321 /* set IDE blockmode */
#define HDIO_SET_UNMASKINTR 0x322 /* permit other irqs during I/O */
#define HDIO_SET_KEEPSETTINGS 0x323 /* keep ioctl settings on reset */
#define HDIO_SET_CHIPSET 0x324 /* optimise driver for interface type */
#define HDIO_SET_NOWERR 0x325 /* set ignore-write-error flag */
#define HDIO_SET_DMA 0x326 /* set use-dma flag */
/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */
#define HDIO_GETGEO 0x0301 /* get device geometry */
#define HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */
#define HDIO_GET_MULTCOUNT 0x0304 /* get current IDE blockmode setting */
#define HDIO_GET_IDENTITY 0x0307 /* get IDE identification info */
#define HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */
#define HDIO_GET_CHIPSET 0x0309 /* get current interface type setting */
#define HDIO_GET_NOWERR 0x030a /* get ignore-write-error flag */
#define HDIO_GET_DMA 0x030b /* get use-dma flag */
#define HDIO_DRIVE_CMD 0x031f /* execute a special drive command */
/* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */
#define HDIO_SET_MULTCOUNT 0x0321 /* set IDE blockmode */
#define HDIO_SET_UNMASKINTR 0x0322 /* permit other irqs during I/O */
#define HDIO_SET_KEEPSETTINGS 0x0323 /* keep ioctl settings on reset */
#define HDIO_SET_CHIPSET 0x0324 /* optimise driver for interface type */
#define HDIO_SET_NOWERR 0x0325 /* set ignore-write-error flag */
#define HDIO_SET_DMA 0x0326 /* set use-dma flag */
/* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */
struct hd_driveid {
......
......@@ -83,11 +83,14 @@
#define IDE1_MAJOR 22
#define MITSUMI_CDROM_MAJOR 23
#define CDU535_CDROM_MAJOR 24
#define STL_SERIALMAJOR 24
#define MATSUSHITA_CDROM_MAJOR 25
#define STL_CALLOUTMAJOR 25
#define MATSUSHITA_CDROM2_MAJOR 26
#define QIC117_TAPE_MAJOR 27
#define MATSUSHITA_CDROM3_MAJOR 27
#define MATSUSHITA_CDROM4_MAJOR 28
#define STL_SIOMEMMAJOR 28
#define AZTECH_CDROM_MAJOR 29
#define CM206_CDROM_MAJOR 32
#define IDE2_MAJOR 33
......
......@@ -8,4 +8,14 @@
unsigned long mouse_init(unsigned long);
struct mouse {
int minor;
const char *name;
struct file_operations *fops;
struct mouse * next, * prev;
};
extern int mouse_register(struct mouse * mouse);
extern int mouse_deregister(struct mouse * mouse);
#endif
......@@ -13,14 +13,14 @@
* or
* sbpcd=0x300,LaserMate
* or
* sbpcd=0x330,SPEA
* sbpcd=0x338,SoundScape
*
* 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
* insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x338,2
* respective to override the configured address and type.
*/
......@@ -35,20 +35,25 @@
* ========
* 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.
* SOUNDSCAPE addresses are from the LASERMATE type and range. You have to
* specify the REAL address here, not the configuration port address. Look
* at the CDROM driver's invoking line within your DOS CONFIG.SYS, or let
* sbpcd auto-probe, if you are not firm with the address.
* 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.
* if your SoundScape configuration port is at 0x330, specify
* 0x338 and SBPRO 2.
*
* interface type:
* ===============
* set SBPRO to 1 for "true" SoundBlaster card
* set SBPRO to 0 for "compatible" soundcards and
* for "poor" (no sound) interface cards.
* set SBPRO to 2 for the SPEA Media FX card
* set SBPRO to 2 for Ensonic SoundScape or SPEA Media FX cards
*
* Almost all "compatible" sound boards need to set SBPRO to 0.
* If SBPRO is set wrong, the drives will get found - but any
......
......@@ -127,12 +127,6 @@ struct mm_struct {
unsigned long start_brk, brk, start_stack, start_mmap;
unsigned long arg_start, arg_end, env_start, env_end;
unsigned long rss;
unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
int swappable:1;
unsigned long swap_address;
unsigned long old_maj_flt; /* old value of maj_flt */
unsigned long dec_flt; /* page fault count of the last time */
unsigned long swap_cnt; /* number of pages to swap on next pass */
struct vm_area_struct * mmap;
struct vm_area_struct * mmap_avl;
};
......@@ -144,9 +138,6 @@ struct mm_struct {
0, 0, 0, 0, \
0, 0, 0, 0, \
0, \
/* ?_flt */ 0, 0, 0, 0, \
0, \
/* swap */ 0, 0, 0, 0, \
&init_mmap, &init_mmap }
struct signal_struct {
......@@ -195,7 +186,15 @@ struct task_struct {
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
struct timer_list real_timer;
long utime, stime, cutime, cstime, start_time;
struct rlimit rlim[RLIM_NLIMITS];
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
int swappable:1;
unsigned long swap_address;
unsigned long old_maj_flt; /* old value of maj_flt */
unsigned long dec_flt; /* page fault count of the last time */
unsigned long swap_cnt; /* number of pages to swap on next pass */
/* limits */
struct rlimit rlim[RLIM_NLIMITS];
unsigned short used_math;
char comm[16];
/* file system info */
......@@ -254,6 +253,8 @@ struct task_struct {
/* timeout */ 0,0,0,0,0,0,0, \
/* timer */ { NULL, NULL, 0, 0, it_real_fn }, \
/* utime */ 0,0,0,0,0, \
/* flt */ 0,0,0,0, \
/* swp */ 0,0,0,0,0, \
/* rlimits */ { {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}, \
{LONG_MAX, LONG_MAX}, {_STK_LIM, _STK_LIM}, \
{ 0, LONG_MAX}, {LONG_MAX, LONG_MAX}, \
......
......@@ -281,6 +281,12 @@ extern long vcs_init(long);
#ifdef CONFIG_CYCLADES
extern long cy_init(long);
#endif
#ifdef CONFIG_STALLION
extern long stl_init(long);
#endif
#ifdef CONFIG_ISTALLION
extern long stli_init(long);
#endif
extern int tty_paranoia_check(struct tty_struct *tty, dev_t device,
const char *routine);
......
......@@ -660,10 +660,10 @@ static pte_t shm_swap_in(struct vm_area_struct * shmd, unsigned long offset, uns
pte = pte_mkdirty(mk_pte(page, PAGE_SHARED));
shp->shm_pages[idx] = pte_val(pte);
} else
--current->mm->maj_flt; /* was incremented in do_no_page */
--current->maj_flt; /* was incremented in do_no_page */
done: /* pte_val(pte) == shp->shm_pages[idx] */
current->mm->min_flt++;
current->min_flt++;
mem_map[MAP_NR(pte_page(pte))]++;
return pte_modify(pte, shmd->vm_page_prot);
}
......
......@@ -97,6 +97,8 @@ void release(struct task_struct * p)
if (STACK_MAGIC != *(unsigned long *)p->kernel_stack_page)
printk(KERN_ALERT "release: %s kernel stack corruption. Aiee\n", p->comm);
free_page(p->kernel_stack_page);
current->cmin_flt += p->min_flt + p->cmin_flt;
current->cmaj_flt += p->maj_flt + p->cmaj_flt;
kfree(p);
return;
}
......@@ -405,10 +407,9 @@ static void exit_mm(void)
{
struct mm_struct * mm = current->mm;
current->swappable = 0;
if (mm) {
if (!--mm->count) {
current->p_pptr->mm->cmin_flt += mm->min_flt + mm->cmin_flt;
current->p_pptr->mm->cmaj_flt += mm->maj_flt + mm->cmaj_flt;
exit_mmap(mm);
free_page_tables(current);
kfree(mm);
......
......@@ -108,8 +108,8 @@ static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
return -1;
*tsk->mm = *current->mm;
tsk->mm->count = 1;
tsk->mm->min_flt = tsk->mm->maj_flt = 0;
tsk->mm->cmin_flt = tsk->mm->cmaj_flt = 0;
tsk->min_flt = tsk->maj_flt = 0;
tsk->cmin_flt = tsk->cmaj_flt = 0;
if (new_page_tables(tsk))
return -1;
if (dup_mmap(tsk->mm)) {
......@@ -205,6 +205,7 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
(*p->binfmt->use_count)++;
p->did_exec = 0;
p->swappable = 0;
p->kernel_stack_page = new_stack;
*(unsigned long *) p->kernel_stack_page = STACK_MAGIC;
p->state = TASK_UNINTERRUPTIBLE;
......@@ -242,7 +243,7 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
p->semundo = NULL;
/* ok, now we should be set up.. */
p->mm->swappable = 1;
p->swappable = 1;
p->exit_signal = clone_flags & CSIGNAL;
p->counter = current->counter >> 1;
wake_up_process(p); /* do this last, just in case */
......
......@@ -764,24 +764,24 @@ int getrusage(struct task_struct *p, int who, struct rusage *ru)
r.ru_utime.tv_usec = CT_TO_USECS(p->utime);
r.ru_stime.tv_sec = CT_TO_SECS(p->stime);
r.ru_stime.tv_usec = CT_TO_USECS(p->stime);
r.ru_minflt = p->mm->min_flt;
r.ru_majflt = p->mm->maj_flt;
r.ru_minflt = p->min_flt;
r.ru_majflt = p->maj_flt;
break;
case RUSAGE_CHILDREN:
r.ru_utime.tv_sec = CT_TO_SECS(p->cutime);
r.ru_utime.tv_usec = CT_TO_USECS(p->cutime);
r.ru_stime.tv_sec = CT_TO_SECS(p->cstime);
r.ru_stime.tv_usec = CT_TO_USECS(p->cstime);
r.ru_minflt = p->mm->cmin_flt;
r.ru_majflt = p->mm->cmaj_flt;
r.ru_minflt = p->cmin_flt;
r.ru_majflt = p->cmaj_flt;
break;
default:
r.ru_utime.tv_sec = CT_TO_SECS(p->utime + p->cutime);
r.ru_utime.tv_usec = CT_TO_USECS(p->utime + p->cutime);
r.ru_stime.tv_sec = CT_TO_SECS(p->stime + p->cstime);
r.ru_stime.tv_usec = CT_TO_USECS(p->stime + p->cstime);
r.ru_minflt = p->mm->min_flt + p->mm->cmin_flt;
r.ru_majflt = p->mm->maj_flt + p->mm->cmaj_flt;
r.ru_minflt = p->min_flt + p->cmin_flt;
r.ru_majflt = p->maj_flt + p->cmaj_flt;
break;
}
memcpy_tofs(ru, &r, sizeof(r));
......
......@@ -628,7 +628,7 @@ void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
old_page = pte_page(pte);
if (old_page >= high_memory)
goto bad_wp_page;
vma->vm_mm->min_flt++;
tsk->min_flt++;
/*
* Do we need to copy?
*/
......@@ -969,7 +969,7 @@ static inline void do_swap_page(struct task_struct * tsk,
if (mem_map[MAP_NR(pte_page(page))] > 1 && !(vma->vm_flags & VM_SHARED))
page = pte_wrprotect(page);
++vma->vm_mm->rss;
++vma->vm_mm->maj_flt;
++tsk->maj_flt;
set_pte(page_table, page);
return;
}
......@@ -1000,14 +1000,14 @@ void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
address &= PAGE_MASK;
if (!vma->vm_ops || !vma->vm_ops->nopage) {
++vma->vm_mm->rss;
++vma->vm_mm->min_flt;
++tsk->min_flt;
get_empty_page(tsk, vma, page_table);
return;
}
page = __get_free_page(GFP_KERNEL);
if (share_page(vma, address, write_access, page)) {
++vma->vm_mm->min_flt;
++vma->vm_mm->rss;
++tsk->min_flt;
return;
}
if (!page) {
......@@ -1015,7 +1015,7 @@ void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
put_page(page_table, BAD_PAGE);
return;
}
++vma->vm_mm->maj_flt;
++tsk->maj_flt;
++vma->vm_mm->rss;
/*
* The fourth argument is "no_share", which tells the low-level code
......
......@@ -331,7 +331,7 @@ void swap_in(struct task_struct * tsk, struct vm_area_struct * vma,
return;
}
vma->vm_mm->rss++;
vma->vm_mm->maj_flt++;
tsk->maj_flt++;
if (!write_access && add_to_swap_cache(page, entry)) {
set_pte(page_table, mk_pte(page, vma->vm_page_prot));
return;
......@@ -461,7 +461,7 @@ static inline int swap_out_pmd(struct task_struct * tsk, struct vm_area_struct *
do {
int result;
vma->vm_mm->swap_address = address + PAGE_SIZE;
tsk->swap_address = address + PAGE_SIZE;
result = try_to_swap_out(tsk, vma, address, pte, limit);
if (result)
return result;
......@@ -530,8 +530,8 @@ static int swap_out_process(struct task_struct * p, unsigned long limit)
/*
* Go through process' page directory.
*/
address = p->mm->swap_address;
p->mm->swap_address = 0;
address = p->swap_address;
p->swap_address = 0;
/*
* Find the proper vm-area
......@@ -551,7 +551,7 @@ static int swap_out_process(struct task_struct * p, unsigned long limit)
break;
address = vma->vm_start;
}
p->mm->swap_address = 0;
p->swap_address = 0;
return 0;
}
......@@ -578,7 +578,7 @@ static int swap_out(unsigned int priority, unsigned long limit)
}
p = task[swap_task];
if (p && p->mm && p->mm->swappable && p->mm->rss)
if (p && p->swappable && p->mm->rss)
break;
swap_task++;
......@@ -587,23 +587,23 @@ static int swap_out(unsigned int priority, unsigned long limit)
/*
* Determine the number of pages to swap from this process.
*/
if (!p->mm->swap_cnt) {
p->mm->dec_flt = (p->mm->dec_flt * 3) / 4 + p->mm->maj_flt - p->mm->old_maj_flt;
p->mm->old_maj_flt = p->mm->maj_flt;
if (p->mm->dec_flt >= SWAP_RATIO / SWAP_MIN) {
p->mm->dec_flt = SWAP_RATIO / SWAP_MIN;
p->mm->swap_cnt = SWAP_MIN;
} else if (p->mm->dec_flt <= SWAP_RATIO / SWAP_MAX)
p->mm->swap_cnt = SWAP_MAX;
if (!p->swap_cnt) {
p->dec_flt = (p->dec_flt * 3) / 4 + p->maj_flt - p->old_maj_flt;
p->old_maj_flt = p->maj_flt;
if (p->dec_flt >= SWAP_RATIO / SWAP_MIN) {
p->dec_flt = SWAP_RATIO / SWAP_MIN;
p->swap_cnt = SWAP_MIN;
} else if (p->dec_flt <= SWAP_RATIO / SWAP_MAX)
p->swap_cnt = SWAP_MAX;
else
p->mm->swap_cnt = SWAP_RATIO / p->mm->dec_flt;
p->swap_cnt = SWAP_RATIO / p->dec_flt;
}
if (!--p->mm->swap_cnt)
if (!--p->swap_cnt)
swap_task++;
switch (swap_out_process(p, limit)) {
case 0:
if (p->mm->swap_cnt)
if (p->swap_cnt)
swap_task++;
break;
case 1:
......
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