summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/Makefile16
-rw-r--r--drivers/block/amiflop.c5
-rw-r--r--drivers/block/ataflop.c11
-rw-r--r--drivers/block/ez.c19
-rw-r--r--drivers/block/floppy.c17
-rw-r--r--drivers/block/genhd.c40
-rw-r--r--drivers/block/hd.c5
-rw-r--r--drivers/block/ide-disk.c2
-rw-r--r--drivers/block/ide-floppy.c6
-rw-r--r--drivers/block/ide-probe.c2
-rw-r--r--drivers/block/ide-tape.c10
-rw-r--r--drivers/block/ide.c19
-rw-r--r--drivers/block/linear.c3
-rw-r--r--drivers/block/loop.c5
-rw-r--r--drivers/block/md.c3
-rw-r--r--drivers/block/ps2esdi.c12
-rw-r--r--drivers/block/rd.c32
-rw-r--r--drivers/block/xd.c31
-rw-r--r--drivers/block/z2ram.c5
-rw-r--r--drivers/cdrom/aztcd.c5
-rw-r--r--drivers/cdrom/bpcd.c21
-rw-r--r--drivers/cdrom/cdi.c5
-rw-r--r--drivers/cdrom/cdu31a.c17
-rw-r--r--drivers/cdrom/cm206.c11
-rw-r--r--drivers/cdrom/gscd.c11
-rw-r--r--drivers/cdrom/isp16.c25
-rw-r--r--drivers/cdrom/mcd.c5
-rw-r--r--drivers/cdrom/mcdx.c9
-rw-r--r--drivers/cdrom/optcd.c7
-rw-r--r--drivers/cdrom/sbpcd.c20
-rw-r--r--drivers/cdrom/sjcd.c5
-rw-r--r--drivers/cdrom/sonycd535.c9
-rw-r--r--drivers/char/Config.in5
-rw-r--r--drivers/char/Makefile13
-rw-r--r--drivers/char/README.epca506
-rw-r--r--drivers/char/busmouse.c2
-rw-r--r--drivers/char/console.c3
-rw-r--r--drivers/char/consolemap.c5
-rw-r--r--drivers/char/cyclades.c5029
-rw-r--r--drivers/char/dsp56k.c578
-rw-r--r--drivers/char/epca.c4313
-rw-r--r--drivers/char/esp.c2
-rw-r--r--drivers/char/fbmem.c5
-rw-r--r--drivers/char/ftape/kernel-interface.c3
-rw-r--r--drivers/char/istallion.c2
-rw-r--r--drivers/char/keyb_m68k.c876
-rw-r--r--drivers/char/keyboard.c397
-rw-r--r--drivers/char/lp.c2
-rw-r--r--drivers/char/lp_intern.c20
-rw-r--r--drivers/char/lp_m68k.c5
-rw-r--r--drivers/char/mem.c83
-rw-r--r--drivers/char/misc.c4
-rw-r--r--drivers/char/msbusmouse.c2
-rw-r--r--drivers/char/n_tty.c10
-rw-r--r--drivers/char/pc_keyb.c647
-rw-r--r--drivers/char/pcxx.c4
-rw-r--r--drivers/char/random.c102
-rw-r--r--drivers/char/riscom8.c4
-rw-r--r--drivers/char/serial.c2
-rw-r--r--drivers/char/tga.c37
-rw-r--r--drivers/char/tpqic02.c6
-rw-r--r--drivers/char/tty_io.c97
-rw-r--r--drivers/char/vga.c9
-rw-r--r--drivers/char/vt.c2
-rw-r--r--drivers/char/wdt.c2
-rw-r--r--drivers/isdn/Config.in1
-rw-r--r--drivers/isdn/Makefile12
-rw-r--r--drivers/isdn/hisax/.cvsignore1
-rw-r--r--drivers/isdn/hisax/isdnl1.c10
-rw-r--r--drivers/isdn/isdn_net.c2
-rw-r--r--drivers/isdn/sc/Makefile2
-rw-r--r--drivers/isdn/teles/Makefile17
-rw-r--r--drivers/isdn/teles/buffers.c329
-rw-r--r--drivers/isdn/teles/callc.c1453
-rw-r--r--drivers/isdn/teles/card.c1900
-rw-r--r--drivers/isdn/teles/config.c48
-rw-r--r--drivers/isdn/teles/fsm.c156
-rw-r--r--drivers/isdn/teles/isdnl2.c1320
-rw-r--r--drivers/isdn/teles/isdnl3.c673
-rw-r--r--drivers/isdn/teles/l3_1TR6.c538
-rw-r--r--drivers/isdn/teles/l3_1TR6.h160
-rw-r--r--drivers/isdn/teles/llglue.c151
-rw-r--r--drivers/isdn/teles/mod.c160
-rw-r--r--drivers/isdn/teles/proto.h18
-rw-r--r--drivers/isdn/teles/q931.c1155
-rw-r--r--drivers/isdn/teles/tei.c248
-rw-r--r--drivers/isdn/teles/teles.h486
-rw-r--r--drivers/net/3c501.c2
-rw-r--r--drivers/net/3c505.c12
-rw-r--r--drivers/net/3c507.c2
-rw-r--r--drivers/net/3c509.c2
-rw-r--r--drivers/net/3c523.c2
-rw-r--r--drivers/net/3c59x.c2
-rw-r--r--drivers/net/a2065.c2
-rw-r--r--drivers/net/apricot.c2
-rw-r--r--drivers/net/arcnet.c2
-rw-r--r--drivers/net/ariadne.c4
-rw-r--r--drivers/net/at1700.c2
-rw-r--r--drivers/net/atarilance.c4
-rw-r--r--drivers/net/atp.c2
-rw-r--r--drivers/net/cs89x0.c2
-rw-r--r--drivers/net/de4x5.c445
-rw-r--r--drivers/net/de4x5.h160
-rw-r--r--drivers/net/defxx.c86
-rw-r--r--drivers/net/depca.c2
-rw-r--r--drivers/net/dlci.c2
-rw-r--r--drivers/net/dummy.c2
-rw-r--r--drivers/net/eepro.c2
-rw-r--r--drivers/net/eepro100.c2
-rw-r--r--drivers/net/eexpress.c11
-rw-r--r--drivers/net/eth16i.c2
-rw-r--r--drivers/net/ewrk3.c10
-rw-r--r--drivers/net/fmv18x.c2
-rw-r--r--drivers/net/hdlcdrv.c4
-rw-r--r--drivers/net/hp100.c2913
-rw-r--r--drivers/net/hp100.h494
-rw-r--r--drivers/net/ibmtr.c41
-rw-r--r--drivers/net/lance.c4
-rw-r--r--drivers/net/ltpc.c2
-rw-r--r--drivers/net/mkiss.c16
-rw-r--r--drivers/net/myri_sbus.c2
-rw-r--r--drivers/net/ni52.c4
-rw-r--r--drivers/net/ni65.c6
-rw-r--r--drivers/net/pcnet32.c4
-rw-r--r--drivers/net/plip.c2
-rw-r--r--drivers/net/ppp.c10
-rw-r--r--drivers/net/sdla.c2
-rw-r--r--drivers/net/sdla_fr.c8
-rw-r--r--drivers/net/sdla_ppp.c8
-rw-r--r--drivers/net/sdla_x25.c8
-rw-r--r--drivers/net/sdlamain.c6
-rw-r--r--drivers/net/seeq8005.c2
-rw-r--r--drivers/net/sgiseeq.c2
-rw-r--r--drivers/net/sk_g16.c9
-rw-r--r--drivers/net/skeleton.c11
-rw-r--r--drivers/net/slip.c18
-rw-r--r--drivers/net/smc9194.c2
-rw-r--r--drivers/net/sonic.c12
-rw-r--r--drivers/net/soundmodem/sm.c8
-rw-r--r--drivers/net/strip.c4
-rw-r--r--drivers/net/sunhme.c6
-rw-r--r--drivers/net/sunlance.c10
-rw-r--r--drivers/net/sunqe.c4
-rw-r--r--drivers/net/tulip.c2
-rw-r--r--drivers/net/wavelan.c18
-rw-r--r--drivers/net/wavelan.p.h1
-rw-r--r--drivers/net/x25_asy.c14
-rw-r--r--drivers/net/znet.c2
-rw-r--r--drivers/pci/pci.c16
-rw-r--r--drivers/pnp/.cvsignore1
-rw-r--r--drivers/sbus/audio/amd7930.c1
-rw-r--r--drivers/sbus/audio/cs4231.c1
-rw-r--r--drivers/sbus/char/creator.c49
-rw-r--r--drivers/sbus/char/suncons.c6
-rw-r--r--drivers/sbus/char/sunkbd.c2
-rw-r--r--drivers/sbus/char/sunserial.c45
-rw-r--r--drivers/sbus/char/vfc.h12
-rw-r--r--drivers/sbus/char/vfc_dev.c111
-rw-r--r--drivers/sbus/char/vfc_i2c.c24
-rw-r--r--drivers/scsi/53c7,8xx.c71
-rw-r--r--drivers/scsi/53c7,8xx.h2
-rw-r--r--drivers/scsi/53c7xx.c6107
-rw-r--r--drivers/scsi/53c7xx.h1675
-rw-r--r--drivers/scsi/53c7xx.scr1591
-rw-r--r--drivers/scsi/ChangeLog.ncr53c8xx72
-rw-r--r--drivers/scsi/Config.in3
-rw-r--r--drivers/scsi/Makefile42
-rw-r--r--drivers/scsi/README.ncr53c8xx61
-rw-r--r--drivers/scsi/a2091.c17
-rw-r--r--drivers/scsi/a3000.c3
-rw-r--r--drivers/scsi/amiga7xx.c107
-rw-r--r--drivers/scsi/amiga7xx.h52
-rw-r--r--drivers/scsi/atari_NCR5380.c8
-rw-r--r--drivers/scsi/atari_scsi.c9
-rw-r--r--drivers/scsi/dc390.h147
-rw-r--r--drivers/scsi/eata.c94
-rw-r--r--drivers/scsi/eata.h2
-rw-r--r--drivers/scsi/gvp11.c3
-rw-r--r--drivers/scsi/hosts.c14
-rw-r--r--drivers/scsi/ide-scsi.c2
-rw-r--r--drivers/scsi/ncr53c8xx.c1916
-rw-r--r--drivers/scsi/ncr53c8xx.h382
-rw-r--r--drivers/scsi/qlogicpti.c67
-rw-r--r--drivers/scsi/scsi.h6
-rw-r--r--drivers/scsi/scsi_proc.c20
-rw-r--r--drivers/scsi/scsiiom.c1540
-rw-r--r--drivers/scsi/sd.c3
-rw-r--r--drivers/scsi/seagate.c30
-rw-r--r--drivers/scsi/seagate.h3
-rw-r--r--drivers/scsi/tmscsim.c1928
-rw-r--r--drivers/scsi/tmscsim.h680
-rw-r--r--drivers/scsi/u14-34f.c78
-rw-r--r--drivers/scsi/u14-34f.h2
-rw-r--r--drivers/scsi/wd33c93.c218
-rw-r--r--drivers/scsi/wd33c93.h6
-rw-r--r--drivers/sgi/char/sgicons.c9
-rw-r--r--drivers/sgi/char/sgiserial.c10
-rw-r--r--drivers/sound/Config.in284
-rw-r--r--drivers/sound/lowlevel/.cvsignore1
199 files changed, 28250 insertions, 15720 deletions
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index ab00e93fc..f8ec1abd9 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -30,6 +30,22 @@ else
endif
endif
+ifeq ($(CONFIG_ATARI_ACSI),y)
+ LX_OBJS += acsi.o
+else
+ ifeq ($(CONFIG_ATARI_ACSI),m)
+ MX_OBJS += acsi.o
+ endif
+endif
+
+ifeq ($(CONFIG_ATARI_SLM),y)
+ L_OBJS += acsi_slm.o
+else
+ ifeq ($(CONFIG_ATARI_SLM),m)
+ M_OBJS += acsi_slm.o
+ endif
+endif
+
ifeq ($(CONFIG_AMIGA_Z2RAM),y)
L_OBJS += z2ram.o
else
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 12c0fcd52..ab11b62a8 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -62,6 +62,7 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
@@ -1712,7 +1713,7 @@ static void fd_probe(int dev)
}
-static void probe_drives(void)
+__initfunc(static void probe_drives(void))
{
int drive,found;
@@ -1860,7 +1861,7 @@ static void fd_block_done(int irq, void *dummy, struct pt_regs *fp)
}
-int amiga_floppy_init(void)
+__initfunc(int amiga_floppy_init(void))
{
int i;
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 3cf489712..7a08808f2 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -75,6 +75,7 @@
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/system.h>
@@ -1777,7 +1778,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
/* Initialize the 'unit' variable for drive 'drive' */
-static void fd_probe( int drive )
+__initfunc(static void fd_probe( int drive ))
{
UD.connected = 0;
UDT = NULL;
@@ -1820,7 +1821,7 @@ static void fd_probe( int drive )
* declared absent.
*/
-static int fd_test_drive_present( int drive )
+__initfunc(static int fd_test_drive_present( int drive ))
{
unsigned long timeout;
unsigned char status;
@@ -1867,7 +1868,7 @@ static int fd_test_drive_present( int drive )
* floppies, additionally start the disk-change and motor-off timers.
*/
-static void config_types( void )
+__initfunc(static void config_types( void ))
{
int drive, cnt = 0;
@@ -2010,7 +2011,7 @@ static struct file_operations floppy_fops = {
floppy_revalidate, /* revalidate */
};
-int atari_floppy_init (void)
+__initfunc(int atari_floppy_init (void))
{
int i;
@@ -2070,7 +2071,7 @@ int atari_floppy_init (void)
}
-void atari_floppy_setup( char *str, int *ints )
+__initfunc(void atari_floppy_setup( char *str, int *ints ))
{
int i;
diff --git a/drivers/block/ez.c b/drivers/block/ez.c
index c6fc96a2f..82270915d 100644
--- a/drivers/block/ez.c
+++ b/drivers/block/ez.c
@@ -101,6 +101,7 @@
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/ioport.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -256,7 +257,7 @@ static struct file_operations ez_fops = {
ez_revalidate /* revalidate new media */
};
-int ez_init (void) /* preliminary initialisation */
+__initfunc(int ez_init (void)) /* preliminary initialisation */
{
if (register_blkdev(MAJOR_NR,"ez",&ez_fops)) {
@@ -271,7 +272,7 @@ int ez_init (void) /* preliminary initialisation */
return 0;
}
-static void ez_geninit (struct gendisk *ignored) /* real init */
+__initfunc(static void ez_geninit (struct gendisk *ignored)) /* real init */
{ int i;
@@ -507,7 +508,7 @@ void cleanup_module(void)
syntax: ez=base[,irq[,rep[,nybble]]]
*/
-void ez_setup(char *str, int *ints)
+__initfunc(void ez_setup(char *str, int *ints))
{ if (ints[0] > 0) ez_base = ints[1];
if (ints[0] > 1) ez_irq = ints[2];
@@ -748,7 +749,7 @@ static void ez_doorlock( int func )
/* ez_media_check: check for and acknowledge the MC flag */
-static void ez_media_check( void )
+__initfunc(static void ez_media_check( void ))
{ int r;
@@ -768,7 +769,7 @@ static void ez_media_check( void )
disconnect();
}
-static int ez_identify( void )
+__initfunc(static int ez_identify( void ))
{ int k, r;
@@ -800,7 +801,7 @@ static int ez_identify( void )
#define word_val(n) (ez_scratch[2*n]+256*ez_scratch[2*n+1])
-static void ez_get_capacity( void )
+__initfunc(static void ez_get_capacity( void ))
{ int ez_cylinders;
@@ -821,7 +822,7 @@ static void ez_get_capacity( void )
ez_heads,ez_sectors);
}
-static void ez_standby_off( void )
+__initfunc(static void ez_standby_off( void ))
{ connect();
wait_for(0,NULL);
@@ -830,7 +831,7 @@ static void ez_standby_off( void )
disconnect();
}
-static int ez_port_check( void ) /* check for 8-bit port */
+__initfunc(static int ez_port_check( void )) /* check for 8-bit port */
{ int r;
@@ -843,7 +844,7 @@ static int ez_port_check( void ) /* check for 8-bit port */
return 0;
}
-static int ez_detect( void )
+__initfunc(static int ez_detect( void ))
{ int j, k;
char sig[EZ_SIGLEN] = EZ_SIG;
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 9fc100ded..3f90981fd 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -140,6 +140,7 @@ static int allowed_drive_mask = 0x33;
#include <linux/mc146818rtc.h> /* CMOS defines */
#include <linux/ioport.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
#include <asm/dma.h>
#include <asm/irq.h>
@@ -3727,7 +3728,7 @@ static struct file_operations floppy_fops = {
/* Determine the floppy disk controller type */
/* This routine was written by David C. Niemi */
-static char get_fdc_version(void)
+__initfunc(static char get_fdc_version(void))
{
int r;
@@ -3805,7 +3806,7 @@ static char get_fdc_version(void)
/* lilo configuration */
-static void floppy_set_flags(int *ints,int param, int param2)
+__initfunc(static void floppy_set_flags(int *ints,int param, int param2))
{
int i;
@@ -3818,7 +3819,7 @@ static void floppy_set_flags(int *ints,int param, int param2)
DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
}
-static void daring(int *ints,int param, int param2)
+__initfunc(static void daring(int *ints,int param, int param2))
{
int i;
@@ -3834,7 +3835,7 @@ static void daring(int *ints,int param, int param2)
DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
}
-static void set_cmos(int *ints, int dummy, int dummy2)
+__initfunc(static void set_cmos(int *ints, int dummy, int dummy2))
{
int current_drive=0;
@@ -3895,7 +3896,7 @@ static struct param_table {
{ "L40SX", 0, &print_unex, 0, 0 } };
#define FLOPPY_SETUP
-void floppy_setup(char *str, int *ints)
+__initfunc(void floppy_setup(char *str, int *ints))
{
int i;
int param;
@@ -3931,7 +3932,7 @@ void floppy_setup(char *str, int *ints)
static int have_no_fdc= -EIO;
-int floppy_init(void)
+__initfunc(int floppy_init(void))
{
int i,unit,drive;
@@ -4136,7 +4137,7 @@ extern char *get_options(char *str, int *ints);
char *floppy=NULL;
-static void parse_floppy_cfg_string(char *cfg)
+__initfunc(static void parse_floppy_cfg_string(char *cfg))
{
char *ptr;
int ints[11];
@@ -4152,7 +4153,7 @@ static void parse_floppy_cfg_string(char *cfg)
}
}
-static void mod_setup(char *pattern, void (*setup)(char *, int *))
+__initfunc(static void mod_setup(char *pattern, void (*setup)(char *, int *)))
{
unsigned long i;
char c;
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index aa11a3ee1..ad0e79b1b 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -191,7 +191,7 @@ static void extended_partition(struct gendisk *hd, kdev_t dev)
*/
bh->b_state = 0;
- if (le16_to_cpu(*(unsigned short *) (bh->b_data+510)) != MSDOS_LABEL_MAGIC)
+ if ((*(unsigned short *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC))
goto done;
p = (struct partition *) (0x1BE + bh->b_data);
@@ -316,7 +316,7 @@ read_mbr:
#ifdef CONFIG_BLK_DEV_IDE
check_table:
#endif
- if (le16_to_cpu(*(unsigned short *) (0x1fe + data)) != MSDOS_LABEL_MAGIC) {
+ if (*(unsigned short *) (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
brelse(bh);
return 0;
}
@@ -359,7 +359,7 @@ check_table:
goto read_mbr; /* start over with new MBR */
}
} else if (sig <= 0x1ae &&
- le16_to_cpu(*(unsigned short *)(data + sig)) == 0x55AA &&
+ *(unsigned short *)(data + sig) == cpu_to_le16(0x55AA) &&
(1 & *(unsigned char *)(data + sig + 2))) {
/* DM6 signature in MBR, courtesy of OnTrack */
(void) ide_xlate_1024 (dev, 0, " [DM6:MBR]");
@@ -424,7 +424,7 @@ check_table:
/*
* Check for old-style Disk Manager partition table
*/
- if (le16_to_cpu(*(unsigned short *) (data+0xfc)) == MSDOS_LABEL_MAGIC) {
+ if (*(unsigned short *) (data+0xfc) == cpu_to_le16(MSDOS_LABEL_MAGIC)) {
p = (struct partition *) (0x1be + data);
for (i = 4 ; i < 16 ; i++, current_minor++) {
p--;
@@ -573,12 +573,12 @@ static int sun_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sec
spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
for(i=0; i < 8; i++, p++) {
unsigned long st_sector;
+ int num_sectors;
- /* We register all partitions, even if zero size, so that
- * the minor numbers end up ok as per SunOS interpretation.
- */
st_sector = first_sector + be32_to_cpu(p->start_cylinder) * spc;
- add_partition(hd, current_minor, st_sector, be32_to_cpu(p->num_sectors));
+ num_sectors = be32_to_cpu(p->num_sectors);
+ if (num_sectors)
+ add_partition(hd, current_minor, st_sector, num_sectors);
current_minor++;
}
printk("\n");
@@ -660,10 +660,10 @@ static int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sec
#include <asm/byteorder.h>
#include <linux/affs_hardblocks.h>
-static __inline__ __u32
-checksum_block(__u32 *m, int size)
+static __inline__ u32
+checksum_block(u32 *m, int size)
{
- __u32 sum = 0;
+ u32 sum = 0;
while (size--)
sum += htonl(*m++);
@@ -671,7 +671,7 @@ checksum_block(__u32 *m, int size)
}
static int
-amiga_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
+amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
{
struct buffer_head *bh;
struct RigidDiskBlock *rdb;
@@ -686,13 +686,15 @@ amiga_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector
for (blk = 0; blk < RDB_ALLOCATION_LIMIT; blk++) {
if(!(bh = bread(dev,blk,512))) {
- printk("Dev %d: unable to read RDB block %d\n",dev,blk);
+ printk("Dev %s: unable to read RDB block %d\n",
+ kdevname(dev),blk);
goto rdb_done;
}
- if (*(__u32 *)bh->b_data == htonl(IDNAME_RIGIDDISK)) {
+ if (*(u32 *)bh->b_data == htonl(IDNAME_RIGIDDISK)) {
rdb = (struct RigidDiskBlock *)bh->b_data;
- if (checksum_block((__u32 *)bh->b_data,htonl(rdb->rdb_SummedLongs) & 0x7F)) {
- printk("Dev %d: RDB in block %d has bad checksum\n",dev,blk);
+ if (checksum_block((u32 *)bh->b_data,htonl(rdb->rdb_SummedLongs) & 0x7F)) {
+ printk("Dev %s: RDB in block %d has bad checksum\n",
+ kdevname(dev),blk);
brelse(bh);
continue;
}
@@ -701,14 +703,14 @@ amiga_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector
brelse(bh);
for (part = 1; blk > 0 && part <= 16; part++) {
if (!(bh = bread(dev,blk,512))) {
- printk("Dev %d: unable to read partition block %d\n",
- dev,blk);
+ printk("Dev %s: unable to read partition block %d\n",
+ kdevname(dev),blk);
goto rdb_done;
}
pb = (struct PartitionBlock *)bh->b_data;
blk = htonl(pb->pb_Next);
if (pb->pb_ID == htonl(IDNAME_PARTITION) && checksum_block(
- (__u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) {
+ (u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) {
/* Tell Kernel about it */
diff --git a/drivers/block/hd.c b/drivers/block/hd.c
index 9c4d8bb71..62e2f8da3 100644
--- a/drivers/block/hd.c
+++ b/drivers/block/hd.c
@@ -39,6 +39,7 @@
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/mc146818rtc.h> /* CMOS defines */
+#include <linux/init.h>
#define REALLY_SLOW_IO
#include <asm/system.h>
@@ -110,7 +111,7 @@ unsigned long read_timer(void)
}
#endif
-void hd_setup(char *str, int *ints)
+__initfunc(void hd_setup(char *str, int *ints))
{
int hdind = 0;
@@ -792,7 +793,7 @@ static struct file_operations hd_fops = {
block_fsync /* fsync */
};
-int hd_init(void)
+__initfunc(int hd_init(void))
{
if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
printk("hd: unable to get major %d for harddisk\n",MAJOR_NR);
diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c
index 94073d468..fbf8c3833 100644
--- a/drivers/block/ide-disk.c
+++ b/drivers/block/ide-disk.c
@@ -48,7 +48,6 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/ioport.h>
@@ -59,6 +58,7 @@
#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
+#include <linux/delay.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c
index d362dfab4..5a0a603b5 100644
--- a/drivers/block/ide-floppy.c
+++ b/drivers/block/ide-floppy.c
@@ -726,7 +726,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive)
return;
}
#ifdef CONFIG_BLK_DEV_TRITON
- if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+ if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
printk (KERN_ERR "ide-floppy: DMA disabled, reverting to PIO\n");
HWIF(drive)->dmaproc(ide_dma_off, drive);
@@ -842,7 +842,7 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
bcount.all=pc->request_transfer; /* Request to transfer the entire buffer at once */
#ifdef CONFIG_BLK_DEV_TRITON
- if (clear_bit (PC_DMA_ERROR, &pc->flags)) {
+ if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
printk (KERN_WARNING "ide-floppy: DMA disabled, reverting to PIO\n");
HWIF(drive)->dmaproc(ide_dma_off, drive);
}
@@ -1182,7 +1182,7 @@ static int idefloppy_media_change (ide_drive_t *drive)
{
idefloppy_floppy_t *floppy = drive->driver_data;
- return clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+ return test_and_clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
}
/*
diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c
index 76e10c08f..25b3d54fa 100644
--- a/drivers/block/ide-probe.c
+++ b/drivers/block/ide-probe.c
@@ -47,7 +47,6 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/ioport.h>
@@ -58,6 +57,7 @@
#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
+#include <linux/delay.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c
index 537c5dd82..2fc5f0b9d 100644
--- a/drivers/block/ide-tape.c
+++ b/drivers/block/ide-tape.c
@@ -1777,7 +1777,7 @@ static void idetape_pc_intr (ide_drive_t *drive)
return;
}
#ifdef CONFIG_BLK_DEV_TRITON
- if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+ if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
HWIF(drive)->dmaproc(ide_dma_off, drive);
@@ -1916,7 +1916,7 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
bcount.all=pc->request_transfer; /* Request to transfer the entire buffer at once */
#ifdef CONFIG_BLK_DEV_TRITON
- if (clear_bit (PC_DMA_ERROR, &pc->flags)) {
+ if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
HWIF(drive)->dmaproc(ide_dma_off, drive);
}
@@ -2248,7 +2248,7 @@ static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned
status.all = GET_STAT();
if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2)
set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
- if (!clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
+ if (!test_and_clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
if (postponed_rq == NULL) {
tape->dsc_polling_start = jiffies;
tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
@@ -2506,7 +2506,7 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
if (!idetape_pipeline_active (tape) && tape->nr_stages >= (3 * tape->max_stages) / 4)
idetape_insert_pipeline_into_queue (drive);
- if (clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags)) /* Return a deferred error */
+ if (test_and_clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags)) /* Return a deferred error */
return -EIO;
return blocks;
}
@@ -3254,7 +3254,7 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
return -ENXIO;
tape = drive->driver_data;
- if (set_bit (IDETAPE_BUSY, &tape->flags))
+ if (test_and_set_bit (IDETAPE_BUSY, &tape->flags))
return -EBUSY;
MOD_INC_USE_COUNT;
idetape_create_read_position_cmd (&pc);
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index ca9456479..89759dd32 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -294,7 +294,6 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/ioport.h>
@@ -307,6 +306,8 @@
#include <linux/malloc.h>
#include <linux/bios32.h>
#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/init.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
@@ -2144,7 +2145,7 @@ void ide_fixstring (byte *s, const int bytecount, const int byteswap)
* stridx() returns the offset of c within s,
* or -1 if c is '\0' or not found within s.
*/
-static int stridx (const char *s, char c)
+__initfunc(static int stridx (const char *s, char c))
{
char *i = strchr(s, c);
return (i && c) ? i - s : -1;
@@ -2162,7 +2163,7 @@ static int stridx (const char *s, char c)
* and base16 is allowed when prefixed with "0x".
* 4. otherwise, zero is returned.
*/
-static int match_parm (char *s, const char *keywords[], int vals[], int max_vals)
+__initfunc(static int match_parm (char *s, const char *keywords[], int vals[], int max_vals))
{
static const char *decimal = "0123456789";
static const char *hex = "0123456789abcdef";
@@ -2261,7 +2262,7 @@ static int match_parm (char *s, const char *keywords[], int vals[], int max_vals
* "ide0=ali14xx" : probe/support ali14xx chipsets (ALI M1439, M1443, M1445)
* "ide0=umc8672" : probe/support umc8672 chipsets
*/
-void ide_setup (char *s)
+__initfunc(void ide_setup (char *s))
{
int i, vals[3];
ide_hwif_t *hwif;
@@ -2558,7 +2559,7 @@ typedef void (ide_pci_init_proc_t)(byte, byte);
* ide_probe_pci() scans PCI for a specific vendor/device function,
* and invokes the supplied init routine for each instance detected.
*/
-static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci_init_proc_t *init, int func_adj)
+__initfunc(static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci_init_proc_t *init, int func_adj))
{
unsigned long flags;
unsigned index;
@@ -2581,7 +2582,7 @@ static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci
* This routine should ideally be using pcibios_find_class() to find all
* PCI IDE interfaces, but that function causes some systems to "go weird".
*/
-static void probe_for_hwifs (void)
+__initfunc(static void probe_for_hwifs (void))
{
#ifdef CONFIG_PCI
/*
@@ -2620,7 +2621,7 @@ static void probe_for_hwifs (void)
#endif
}
-void ide_init_builtin_drivers (void)
+__initfunc(void ide_init_builtin_drivers (void))
{
/*
* Probe for special "known" interface chipsets
@@ -2889,7 +2890,7 @@ EXPORT_SYMBOL(ide_unregister);
/*
* This is gets invoked once during initialization, to set *everything* up
*/
-int ide_init (void)
+__initfunc(int ide_init (void))
{
init_ide_data ();
@@ -2904,7 +2905,7 @@ int ide_init (void)
char *options = NULL;
MODULE_PARM(options,"s");
-static void parse_options (char *line)
+__initfunc(static void parse_options (char *line))
{
char *next = line;
diff --git a/drivers/block/linear.c b/drivers/block/linear.c
index 6fc6960aa..f0f9fec79 100644
--- a/drivers/block/linear.c
+++ b/drivers/block/linear.c
@@ -21,6 +21,7 @@
#include <linux/md.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include "linear.h"
@@ -180,7 +181,7 @@ static struct md_personality linear_personality=
#ifndef MODULE
-void linear_init (void)
+__initfunc(void linear_init (void))
{
register_md_personality (LINEAR, &linear_personality);
}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index d6af70d4f..212efece2 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -23,6 +23,7 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/major.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
@@ -537,8 +538,8 @@ static struct file_operations lo_fops = {
#define loop_init init_module
#endif
-int
-loop_init( void ) {
+__initfunc(int
+loop_init( void )) {
int i;
if (register_blkdev(MAJOR_NR, "loop", &lo_fops)) {
diff --git a/drivers/block/md.c b/drivers/block/md.c
index 7b4ec6313..078e1e1ee 100644
--- a/drivers/block/md.c
+++ b/drivers/block/md.c
@@ -35,6 +35,7 @@
#include <linux/kerneld.h>
#endif
#include <linux/errno.h>
+#include <linux/init.h>
#define MAJOR_NR MD_MAJOR
#define MD_DRIVER
@@ -546,7 +547,7 @@ void raid0_init (void);
void raid1_init (void);
void raid5_init (void);
-int md_init (void)
+__initfunc(int md_init (void))
{
printk ("md driver %s MAX_MD_DEV=%d, MAX_REAL=%d\n", MD_VERSION, MAX_MD_DEV, MAX_REAL);
diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
index 8e845e8d7..b4d5146de 100644
--- a/drivers/block/ps2esdi.c
+++ b/drivers/block/ps2esdi.c
@@ -43,6 +43,7 @@
#include <linux/ps2esdi.h>
#include <linux/blk.h>
#include <linux/mca.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -176,7 +177,7 @@ static struct gendisk ps2esdi_gendisk =
};
/* initialization routine called by ll_rw_blk.c */
-int ps2esdi_init(void)
+__initfunc(int ps2esdi_init(void))
{
/* register the device - pass the name, major number and operations
@@ -197,7 +198,7 @@ int ps2esdi_init(void)
} /* ps2esdi_init */
/* handles boot time command line parameters */
-void tp720_setup(char *str, int *ints)
+__initfunc(void tp720_setup(char *str, int *ints))
{
/* no params, just sets the tp720esdi flag if it exists */
@@ -205,7 +206,7 @@ void tp720_setup(char *str, int *ints)
tp720esdi = 1;
}
-void ed_setup(char *str, int *ints)
+__initfunc(void ed_setup(char *str, int *ints))
{
int hdind = 0;
@@ -252,10 +253,9 @@ static int ps2esdi_getinfo(char *buf, int slot, void *d)
}
/* ps2 esdi specific initialization - called thru the gendisk chain */
-static void ps2esdi_geninit(struct gendisk *ignored)
+__initfunc(static void ps2esdi_geninit(struct gendisk *ignored))
{
/*
-
The first part contains the initialization code
for the ESDI disk subsystem. All we really do
is search for the POS registers of the controller
@@ -386,7 +386,7 @@ static void ps2esdi_geninit(struct gendisk *ignored)
} /* ps2esdi_geninit */
-static void ps2esdi_get_device_cfg(void)
+__initfunc(static void ps2esdi_get_device_cfg(void))
{
u_short cmd_blk[TYPE_0_CMD_BLK_LENGTH];
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 102b19963..4ac6c0c41 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -51,9 +51,11 @@
#include <linux/ioctl.h>
#include <linux/fd.h>
#include <linux/module.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/uaccess.h>
+#include <asm/byteorder.h>
extern void wait_for_keypress(void);
@@ -269,7 +271,7 @@ static struct file_operations fd_fops = {
};
/* This is the registration and initialization section of the ramdisk driver */
-int rd_init(void)
+__initfunc(int rd_init(void))
{
int i;
@@ -334,8 +336,8 @@ void cleanup_module(void)
* romfs
* gzip
*/
-int
-identify_ramdisk_image(kdev_t device, struct file *fp, int start_block)
+__initfunc(int
+identify_ramdisk_image(kdev_t device, struct file *fp, int start_block))
{
const int size = 512;
struct minix_super_block *minixsb;
@@ -440,7 +442,7 @@ done:
/*
* This routine loads in the ramdisk image.
*/
-static void rd_load_image(kdev_t device,int offset)
+__initfunc(static void rd_load_image(kdev_t device,int offset))
{
struct inode inode, out_inode;
struct file infile, outfile;
@@ -527,7 +529,7 @@ done:
}
-void rd_load()
+__initfunc(void rd_load(void))
{
if (rd_doload == 0)
return;
@@ -549,7 +551,7 @@ void rd_load()
#ifdef CONFIG_BLK_DEV_INITRD
-void initrd_load(void)
+__initfunc(void initrd_load(void))
{
rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0);
}
@@ -608,21 +610,21 @@ static void gzip_release(void **);
#include "../../lib/inflate.c"
-static void *malloc(int size)
+__initfunc(static void *malloc(int size))
{
return kmalloc(size, GFP_KERNEL);
}
-static void free(void *where)
+__initfunc(static void free(void *where))
{
kfree(where);
}
-static void gzip_mark(void **ptr)
+__initfunc(static void gzip_mark(void **ptr))
{
}
-static void gzip_release(void **ptr)
+__initfunc(static void gzip_release(void **ptr))
{
}
@@ -631,7 +633,7 @@ static void gzip_release(void **ptr)
* Fill the input buffer. This is called only when the buffer is empty
* and at least one byte is really needed.
*/
-static int fill_inbuf()
+__initfunc(static int fill_inbuf(void))
{
if (exit_code) return -1;
@@ -648,7 +650,7 @@ static int fill_inbuf()
* Write the output window window[0..outcnt-1] and update crc and bytes_out.
* (Used for the decompressed data only.)
*/
-static void flush_window()
+__initfunc(static void flush_window(void))
{
ulg c = crc; /* temporary variable */
unsigned n;
@@ -666,14 +668,14 @@ static void flush_window()
outcnt = 0;
}
-static void error(char *x)
+__initfunc(static void error(char *x))
{
printk(KERN_ERR "%s", x);
exit_code = 1;
}
-static int
-crd_load(struct file * fp, struct file *outfp)
+__initfunc(static int
+crd_load(struct file * fp, struct file *outfp))
{
int result;
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index 603c4b142..472959603 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -30,6 +30,7 @@
#include <linux/kernel.h>
#include <linux/genhd.h>
#include <linux/hdreg.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -126,7 +127,7 @@ static u_char xd_override = 0, xd_type = 0;
static u_short xd_iobase = 0;
/* xd_init: register the block device number and set up pointer tables */
-int xd_init (void)
+__initfunc(int xd_init (void))
{
if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
printk("xd_init: unable to get major number %d\n",MAJOR_NR);
@@ -141,7 +142,7 @@ int xd_init (void)
}
/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
-static u_char xd_detect (u_char *controller, unsigned int *address)
+__initfunc(static u_char xd_detect (u_char *controller, unsigned int *address))
{
u_char i,j,found = 0;
@@ -164,7 +165,7 @@ static u_char xd_detect (u_char *controller, unsigned int *address)
/* xd_geninit: grab the IRQ and DMA channel, initialise the drives */
/* and set up the "raw" device entries in the table */
-static void xd_geninit (struct gendisk *ignored)
+__initfunc(static void xd_geninit (struct gendisk *ignored))
{
u_char i,controller;
unsigned int address;
@@ -527,7 +528,7 @@ static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outd
return (csb & CSB_ERROR);
}
-static u_char xd_initdrives (void (*init_drive)(u_char drive))
+__initfunc(static u_char xd_initdrives (void (*init_drive)(u_char drive)))
{
u_char cmdblk[6],i,count = 0;
@@ -541,7 +542,7 @@ static u_char xd_initdrives (void (*init_drive)(u_char drive))
return (count);
}
-static void xd_dtc_init_controller (unsigned int address)
+__initfunc(static void xd_dtc_init_controller (unsigned int address))
{
switch (address) {
case 0xC8000: xd_iobase = 0x320; break;
@@ -556,7 +557,7 @@ static void xd_dtc_init_controller (unsigned int address)
outb(0,XD_RESET); /* reset the controller */
}
-static void xd_dtc_init_drive (u_char drive)
+__initfunc(static void xd_dtc_init_drive (u_char drive))
{
u_char cmdblk[6],buf[64];
@@ -581,7 +582,7 @@ static void xd_dtc_init_drive (u_char drive)
printk("xd_dtc_init_drive: error reading geometry for drive %d\n",drive);
}
-static void xd_wd_init_controller (unsigned int address)
+__initfunc(static void xd_wd_init_controller (unsigned int address))
{
switch (address) {
case 0xC8000: xd_iobase = 0x320; break;
@@ -600,7 +601,7 @@ static void xd_wd_init_controller (unsigned int address)
/* outb(0,XD_RESET); */ /* reset the controller */
}
-static void xd_wd_init_drive (u_char drive)
+__initfunc(static void xd_wd_init_drive (u_char drive))
{
u_char cmdblk[6],buf[0x200];
@@ -622,7 +623,7 @@ static void xd_wd_init_drive (u_char drive)
printk("xd_wd_init_drive: error reading geometry for drive %d\n",drive);
}
-static void xd_seagate_init_controller (unsigned int address)
+__initfunc(static void xd_seagate_init_controller (unsigned int address))
{
switch (address) {
case 0xC8000: xd_iobase = 0x320; break;
@@ -639,7 +640,7 @@ static void xd_seagate_init_controller (unsigned int address)
outb(0,XD_RESET); /* reset the controller */
}
-static void xd_seagate_init_drive (u_char drive)
+__initfunc(static void xd_seagate_init_drive (u_char drive))
{
u_char cmdblk[6],buf[0x200];
@@ -655,7 +656,7 @@ static void xd_seagate_init_drive (u_char drive)
}
/* Omti support courtesy Dirk Melchers */
-static void xd_omti_init_controller (unsigned int address)
+__initfunc(static void xd_omti_init_controller (unsigned int address))
{
switch (address) {
case 0xC8000: xd_iobase = 0x320; break;
@@ -673,7 +674,7 @@ static void xd_omti_init_controller (unsigned int address)
outb(0,XD_RESET); /* reset the controller */
}
-static void xd_omti_init_drive (u_char drive)
+__initfunc(static void xd_omti_init_drive (u_char drive))
{
/* gets infos from drive */
xd_override_init_drive(drive);
@@ -684,7 +685,7 @@ static void xd_omti_init_drive (u_char drive)
/* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
-static void xd_override_init_drive (u_char drive)
+__initfunc(static void xd_override_init_drive (u_char drive))
{
u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
u_char cmdblk[6],i;
@@ -707,7 +708,7 @@ static void xd_override_init_drive (u_char drive)
}
/* xd_setup: initialise from command line parameters */
-void xd_setup (char *command,int *integers)
+__initfunc(void xd_setup (char *command,int *integers))
{
xd_override = 1;
@@ -720,7 +721,7 @@ void xd_setup (char *command,int *integers)
}
/* xd_setparam: set the drive characteristics */
-static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
+__initfunc(static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc))
{
u_char cmdblk[14];
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index 0f556752d..ac13bcff2 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -28,6 +28,7 @@
#include <linux/major.h>
#include <linux/malloc.h>
#include <linux/blk.h>
+#include <linux/init.h>
#if defined(MODULE)
#include <linux/module.h>
@@ -282,8 +283,8 @@ static struct file_operations z2_fops =
block_fsync /* fsync */
};
-int
-z2_init( void )
+__initfunc(int
+z2_init( void ))
{
if ( !MACH_IS_AMIGA )
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
index 514a7826d..c97133141 100644
--- a/drivers/cdrom/aztcd.c
+++ b/drivers/cdrom/aztcd.c
@@ -166,6 +166,7 @@
#include <linux/ioport.h>
#include <linux/string.h>
#include <linux/major.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -1049,7 +1050,7 @@ static int aztGetToc(int multi)
Kernel Interface Functions
##########################################################################
*/
-void aztcd_setup(char *str, int *ints)
+__initfunc(void aztcd_setup(char *str, int *ints))
{ if (ints[0] > 0)
azt_port = ints[1];
if (ints[0] > 1)
@@ -1567,7 +1568,7 @@ static int aztcd_release(struct inode * inode, struct file * file)
* Test for presence of drive and initialize it. Called at boot time.
*/
-int aztcd_init(void)
+__initfunc(int aztcd_init(void))
{ long int count, max_count;
unsigned char result[50];
int st;
diff --git a/drivers/cdrom/bpcd.c b/drivers/cdrom/bpcd.c
index 49225ec0c..9f7e8b395 100644
--- a/drivers/cdrom/bpcd.c
+++ b/drivers/cdrom/bpcd.c
@@ -113,6 +113,7 @@
#include <linux/delay.h>
#include <linux/cdrom.h>
#include <linux/ioport.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -201,7 +202,7 @@ static struct file_operations bp_fops = {
nybble value. The following function initialises the table.
*/
-static void init_nyb_map( void )
+__initfunc(static void init_nyb_map( void ))
{ int i, j;
@@ -212,7 +213,7 @@ static void init_nyb_map( void )
}
}
-int bpcd_init (void) /* preliminary initialisation */
+__initfunc(int bpcd_init (void)) /* preliminary initialisation */
{ init_nyb_map();
@@ -327,7 +328,7 @@ void cleanup_module(void)
syntax: bpcd=base[,nybble[,rep]]
*/
-void bpcd_setup(char *str, int *ints)
+__initfunc(void bpcd_setup(char *str, int *ints))
{ if (ints[0] > 0) bp_base = ints[1];
if (ints[0] > 1) bp_nybble = ints[2];
@@ -425,7 +426,7 @@ static void read_data( char * buf, int len )
if (bp_mode == 2) { t2(1); t2(0x20); }
}
-static int probe( int id )
+__initfunc(static int probe( int id ))
{ int l, h, t;
int r = -1;
@@ -588,7 +589,7 @@ static void bp_eject( void)
bp_atapi(ej_cmd,0,"eject");
}
-static int bp_reset( void )
+__initfunc(static int bp_reset( void ))
/* the ATAPI standard actually specifies the contents of all 7 registers
after a reset, but the specification is ambiguous concerning the last
@@ -615,7 +616,7 @@ static int bp_reset( void )
return flg-1;
}
-static int bp_identify( char * id )
+__initfunc(static int bp_identify( char * id ))
{ int k;
char id_cmd[12] = {0x12,0,0,0,36,0,0,0,0,0,0,0};
@@ -627,7 +628,7 @@ static int bp_identify( char * id )
return 0;
}
-static int bp_port_check( void ) /* check for 8-bit port */
+__initfunc(static int bp_port_check( void )) /* check for 8-bit port */
{ int r;
@@ -640,7 +641,7 @@ static int bp_port_check( void ) /* check for 8-bit port */
return 0;
}
-static int bp_locate( void )
+__initfunc(static int bp_locate( void ))
{ int k;
@@ -652,7 +653,7 @@ static int bp_locate( void )
return -1;
}
-static int bp_do_detect( int autop )
+__initfunc(static int bp_do_detect( int autop ))
{ char id[18];
@@ -705,7 +706,7 @@ static int bp_do_detect( int autop )
add it here ....
*/
-static int bp_detect( void )
+__initfunc(static int bp_detect( void ))
{ if (bp_base) return bp_do_detect(0);
if (!bp_do_detect(0x378)) return 0;
diff --git a/drivers/cdrom/cdi.c b/drivers/cdrom/cdi.c
index c45056d2e..ee90de9c6 100644
--- a/drivers/cdrom/cdi.c
+++ b/drivers/cdrom/cdi.c
@@ -28,6 +28,7 @@
#include <linux/config.h>
#include <linux/blk.h> /* where the proto type of cdi_init() is */
+#include <linux/init.h>
#ifdef CONFIG_ISP16_CDI
#include <linux/isp16.h>
#endif CONFIG_ISP16_CDI
@@ -35,8 +36,8 @@
/*
* Cdrom interface configuration.
*/
-int
-cdi_init(void)
+__initfunc(int
+cdi_init(void))
{
int ret_val = -1;
diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
index 54c129686..e2c269bcf 100644
--- a/drivers/cdrom/cdu31a.c
+++ b/drivers/cdrom/cdu31a.c
@@ -190,6 +190,7 @@
#include <linux/ioport.h>
#include <linux/string.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -220,7 +221,7 @@ static struct
unsigned short base; /* I/O Base Address */
short int_num; /* Interrupt Number (-1 means scan for it,
0 means don't use) */
-} cdu31a_addresses[] =
+} cdu31a_addresses[] __initdata =
{
#if 0 /* No autoconfig any more. See Note at beginning
of this file. */
@@ -2963,12 +2964,12 @@ static struct file_operations scd_fops = {
/* The different types of disc loading mechanisms supported */
-static const char *load_mech[] = { "caddy", "tray", "pop-up", "unknown" };
+static const char *load_mech[] __initdata = { "caddy", "tray", "pop-up", "unknown" };
-static void
+__initfunc(static void
get_drive_configuration(unsigned short base_io,
unsigned char res_reg[],
- unsigned int *res_size)
+ unsigned int *res_size))
{
int retry_count;
@@ -3032,9 +3033,9 @@ get_drive_configuration(unsigned short base_io,
/*
* Set up base I/O and interrupts, called from main.c.
*/
-void
+__initfunc(void
cdu31a_setup(char *strings,
- int *ints)
+ int *ints))
{
if (ints[0] > 0)
{
@@ -3063,8 +3064,8 @@ static int cdu31a_block_size;
/*
* Initialize the driver.
*/
-int
-cdu31a_init(void)
+__initfunc(int
+cdu31a_init(void))
{
struct s_sony_drive_config drive_config;
unsigned int res_size;
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
index 9411b3f02..fb5533706 100644
--- a/drivers/cdrom/cm206.c
+++ b/drivers/cdrom/cm206.c
@@ -138,6 +138,7 @@ History:
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <linux/ucdrom.h>
@@ -1186,7 +1187,7 @@ void cleanup(int level)
check_region, 15 bits of one port and 6 of another make things
likely enough to accept the region on the first hit...
*/
-int probe_base_port(int base)
+__initfunc(int probe_base_port(int base))
{
int b=0x300, e=0x370; /* this is the range of start addresses */
volatile int fool, i;
@@ -1206,7 +1207,7 @@ int probe_base_port(int base)
#if !defined(MODULE) || defined(AUTO_PROBE_MODULE)
/* Probe for irq# nr. If nr==0, probe for all possible irq's. */
-int probe_irq(int nr) {
+__initfunc(int probe_irq(int nr)) {
int irqs, irq;
outw(dc_normal | READ_AHEAD, r_data_control); /* disable irq-generation */
sti();
@@ -1220,7 +1221,7 @@ int probe_irq(int nr) {
}
#endif
-int cm206_init(void)
+__initfunc(int cm206_init(void))
{
uch e=0;
long int size=sizeof(struct cm206_struct);
@@ -1303,7 +1304,7 @@ int cm206_init(void)
static int cm206[2] = {0,0}; /* for compatible `insmod' parameter passing */
-void parse_options(void)
+__initfunc(void parse_options(void))
{
int i;
for (i=0; i<2; i++) {
@@ -1337,7 +1338,7 @@ void cleanup_module(void)
/* This setup function accepts either `auto' or numbers in the range
* 3--11 (for irq) or 0x300--0x370 (for base port) or both. */
-void cm206_setup(char *s, int *p)
+__initfunc(void cm206_setup(char *s, int *p))
{
int i;
if (!strcmp(s, "auto")) auto_probe=1;
diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
index c9ad14748..685990a77 100644
--- a/drivers/cdrom/gscd.c
+++ b/drivers/cdrom/gscd.c
@@ -55,6 +55,7 @@
#include <linux/ioport.h>
#include <linux/major.h>
#include <linux/string.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -191,7 +192,7 @@ static int check_gscd_med_chg (kdev_t full_dev)
}
-void gscd_setup (char *str, int *ints)
+__initfunc(void gscd_setup (char *str, int *ints))
{
if (ints[0] > 0)
{
@@ -848,7 +849,7 @@ int i;
return;
}
-int find_drives (void)
+__initfunc(int find_drives (void))
{
int *pdrv;
int drvnum;
@@ -899,7 +900,7 @@ int i;
return drvnum;
}
-void init_cd_drive ( int num )
+__initfunc(void init_cd_drive ( int num ))
{
char resp [50];
int i;
@@ -991,7 +992,7 @@ void cleanup_module (void)
/* Test for presence of drive and initialize it. Called only at boot time. */
-int gscd_init (void)
+__initfunc(int gscd_init (void))
{
return my_gscd_init ();
}
@@ -999,7 +1000,7 @@ int gscd_init (void)
/* This is the common initialisation for the GoldStar drive. */
/* It is called at boot time AND for module init. */
-int my_gscd_init (void)
+__initfunc(int my_gscd_init (void))
{
int i;
int result;
diff --git a/drivers/cdrom/isp16.c b/drivers/cdrom/isp16.c
index c3bb43d24..88c070eba 100644
--- a/drivers/cdrom/isp16.c
+++ b/drivers/cdrom/isp16.c
@@ -48,6 +48,7 @@
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/isp16.h>
+#include <linux/init.h>
#include <asm/io.h>
static short isp16_detect(void);
@@ -76,8 +77,8 @@ void cleanup_module(void);
#define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p))
-void
-isp16_setup(char *str, int *ints)
+__initfunc(void
+isp16_setup(char *str, int *ints))
{
if ( ints[0] > 0 )
isp16_cdrom_base = ints[1];
@@ -93,8 +94,8 @@ isp16_setup(char *str, int *ints)
* ISP16 initialisation.
*
*/
-int
-isp16_init(void)
+__initfunc(int
+isp16_init(void))
{
u_char expected_drive;
@@ -143,8 +144,8 @@ isp16_init(void)
return(0);
}
-static short
-isp16_detect(void)
+__initfunc(static short
+isp16_detect(void))
{
if ( isp16_c929__detect() >= 0 )
@@ -153,8 +154,8 @@ isp16_detect(void)
return(isp16_c928__detect());
}
-static short
-isp16_c928__detect(void)
+__initfunc(static short
+isp16_c928__detect(void))
{
u_char ctrl;
u_char enable_cdrom;
@@ -202,8 +203,8 @@ isp16_c928__detect(void)
return(i);
}
-static short
-isp16_c929__detect(void)
+__initfunc(static short
+isp16_c929__detect(void))
{
u_char ctrl;
u_char tmp;
@@ -229,8 +230,8 @@ isp16_c929__detect(void)
return(2);
}
-static short
-isp16_cdi_config(int base, u_char drive_type, int irq, int dma)
+__initfunc(static short
+isp16_cdi_config(int base, u_char drive_type, int irq, int dma))
{
u_char base_code;
u_char irq_code;
diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c
index aa6f07ec8..e4d1a73f6 100644
--- a/drivers/cdrom/mcd.c
+++ b/drivers/cdrom/mcd.c
@@ -80,6 +80,7 @@
#include <linux/ioport.h>
#include <linux/string.h>
#include <linux/delay.h>
+#include <linux/init.h>
/* #define REALLY_SLOW_IO */
#include <asm/system.h>
@@ -196,7 +197,7 @@ static int GetToc(void);
static int getValue(unsigned char *result);
-void mcd_setup(char *str, int *ints)
+__initfunc(void mcd_setup(char *str, int *ints))
{
if (ints[0] > 0)
mcd_port = ints[1];
@@ -1175,7 +1176,7 @@ static struct file_operations mcd_fops = {
* Test for presence of drive and initialize it. Called at boot time.
*/
-int mcd_init(void)
+__initfunc(int mcd_init(void))
{
int count;
unsigned char result[3];
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
index 081bd0d53..242508f9d 100644
--- a/drivers/cdrom/mcdx.c
+++ b/drivers/cdrom/mcdx.c
@@ -63,6 +63,7 @@ static const char *mcdx_c_version
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -358,6 +359,10 @@ mcdx_ioctl(
msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1);
msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1);
+ stuffp->stop.dt.minute = msf.cdmsf_min1;
+ stuffp->stop.dt.second = msf.cdmsf_sec1;
+ stuffp->stop.dt.frame = msf.cdmsf_frame1;
+
return mcdx_playmsf(stuffp, &msf);
}
@@ -910,7 +915,7 @@ int check_mcdx_media_change(kdev_t full_dev)
return 1;
}
-void mcdx_setup(char *str, int *pi)
+__initfunc(void mcdx_setup(char *str, int *pi))
{
if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1];
if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2];
@@ -1160,7 +1165,7 @@ void cleanup_module(void)
/* Support functions ************************************************/
-int mcdx_init(void)
+__initfunc(int mcdx_init(void))
{
int drive;
diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
index 8bd4b84f6..417769111 100644
--- a/drivers/cdrom/optcd.c
+++ b/drivers/cdrom/optcd.c
@@ -65,6 +65,7 @@
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/ioport.h>
+#include <linux/init.h>
#include <asm/io.h>
#define MAJOR_NR OPTICS_CDROM_MAJOR
@@ -1961,7 +1962,7 @@ static int opt_media_change(kdev_t dev)
/* Returns 1 if a drive is detected with a version string
starting with "DOLPHIN". Otherwise 0. */
-static int version_ok(void)
+__initfunc(static int version_ok(void))
{
char devname[100];
int count, i, ch, status;
@@ -2016,7 +2017,7 @@ static struct file_operations opt_fops = {
/* Get kernel parameter when used as a kernel driver */
-void optcd_setup(char *str, int *ints)
+__initfunc(void optcd_setup(char *str, int *ints))
{
if (ints[0] > 0)
optcd_port = ints[1];
@@ -2024,7 +2025,7 @@ void optcd_setup(char *str, int *ints)
/* Test for presence of drive and initialize it. Called at boot time
or during module initialisation. */
-int optcd_init(void)
+__initfunc(int optcd_init(void))
{
int status;
diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
index 6d27b2248..401dbc657 100644
--- a/drivers/cdrom/sbpcd.c
+++ b/drivers/cdrom/sbpcd.c
@@ -328,6 +328,7 @@
#include <linux/major.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -3052,7 +3053,7 @@ static int cc_SubChanInfo(int frame, int count, u_char *buffer)
}
#endif FUTURE
/*==========================================================================*/
-static void check_datarate(void)
+__initfunc(static void check_datarate(void))
{
int i=0;
@@ -3122,7 +3123,7 @@ static int c2_ReadError(int fam)
}
#endif
/*==========================================================================*/
-static void ask_mail(void)
+__initfunc(static void ask_mail(void))
{
int i;
@@ -3141,7 +3142,7 @@ static void ask_mail(void)
msg(DBG_INF,"infobuf =%s\n", msgbuf);
}
/*==========================================================================*/
-static int check_version(void)
+__initfunc(static int check_version(void))
{
int i, j, l;
int teac_possible=0;
@@ -3439,7 +3440,7 @@ static void switch_drive(int i)
/*
* probe for the presence of an interface card
*/
-static int check_card(int port)
+__initfunc(static int check_card(int port))
{
#undef N_RESPO
#define N_RESPO 20
@@ -3543,7 +3544,7 @@ static int check_card(int port)
/*
* probe for the presence of drives on the selected controller
*/
-static int check_drives(void)
+__initfunc(static int check_drives(void))
{
int i, j;
@@ -5285,9 +5286,10 @@ static struct file_operations sbpcd_fops =
*
*/
#if (SBPCD_ISSUE-1)
-static
+__initfunc(static void sbpcd_setup(const char *s, int *p))
+#else
+__initfunc(void sbpcd_setup(const char *s, int *p))
#endif
-void sbpcd_setup(const char *s, int *p)
{
setup_done++;
msg(DBG_INI,"sbpcd_setup called with %04X,%s\n",p[1], s);
@@ -5338,7 +5340,7 @@ void sbpcd_setup(const char *s, int *p)
* port 0x330, we have to use an offset of 8; so, the real CDROM port
* address is 0x338.
*/
-static int config_spea(void)
+__initfunc(static int config_spea(void))
{
/*
* base address offset between configuration port and CDROM port,
@@ -5397,7 +5399,7 @@ static int config_spea(void)
#ifdef MODULE
int init_module(void)
#else
-int SBPCD_INIT(void)
+__initfunc(int SBPCD_INIT(void))
#endif MODULE
{
int i=0, j=0;
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
index 0ca13dc3d..67d04134d 100644
--- a/drivers/cdrom/sjcd.c
+++ b/drivers/cdrom/sjcd.c
@@ -65,6 +65,7 @@
#include <linux/ioport.h>
#include <linux/string.h>
#include <linux/major.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -159,7 +160,7 @@ static int sjcd_cleanup(void);
* Set up device, i.e., use command line data to set
* base address.
*/
-void sjcd_setup( char *str, int *ints )
+__initfunc(void sjcd_setup( char *str, int *ints ))
{
if (ints[0] > 0)
sjcd_base = ints[1];
@@ -1449,7 +1450,7 @@ static struct {
* Test for presence of drive and initialize it. Called at boot time.
* Probe cdrom, find out version and status.
*/
-int sjcd_init( void ){
+__initfunc(int sjcd_init( void )){
int i;
printk(KERN_INFO "SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n", SJCD_VERSION_MAJOR,
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
index 33b4bd42a..b5c257f9b 100644
--- a/drivers/cdrom/sonycd535.c
+++ b/drivers/cdrom/sonycd535.c
@@ -120,6 +120,7 @@
#include <linux/genhd.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#define REALLY_SLOW_IO
#include <asm/system.h>
@@ -1484,8 +1485,8 @@ static struct file_operations cdu_fops =
/*
* Initialize the driver.
*/
-int
-sony535_init(void)
+__initfunc(int
+sony535_init(void))
{
struct s535_sony_drive_config drive_config;
Byte cmd_buff[3];
@@ -1649,8 +1650,8 @@ sony535_init(void)
*
* the address value has to be the existing CDROM port address.
*/
-void
-sonycd535_setup(char *strings, int *ints)
+__initfunc(void
+sonycd535_setup(char *strings, int *ints))
{
/* if IRQ change and default io base desired,
* then call with io base of 0
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index c32475be7..4216b3154 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -19,7 +19,10 @@ if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
fi
bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD
if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
- tristate 'Digiboard PC/Xx Support' CONFIG_DIGI
+ tristate 'Digiboard Intelligent Async Support' CONFIG_DIGIEPCA
+ if [ "$CONFIG_DIGIEPCA" = "n" ]; then
+ tristate 'Digiboard PC/Xx Support' CONFIG_DIGI
+ fi
tristate 'Cyclades async mux support' CONFIG_CYCLADES
bool 'Stallion multiport serial support' CONFIG_STALDRV
if [ "$CONFIG_STALDRV" = "y" ]; then
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 3e6500f3a..d5a19d343 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -41,7 +41,10 @@ endif
ifndef CONFIG_SUN_KEYBOARD
ifdef CONFIG_VT
-L_OBJS += keyboard.o defkeymap.o
+L_OBJS += keyboard.o
+endif
+ifneq ($(ARCH),m68k)
+L_OBJS += pc_keyb.o defkeymap.o
endif
endif
@@ -63,6 +66,14 @@ else
endif
endif
+ifeq ($(CONFIG_DIGIEPCA),y)
+L_OBJS += epca.o
+else
+ ifeq ($(CONFIG_DIGIEPCA),m)
+ M_OBJS += epca.o
+ endif
+endif
+
ifeq ($(CONFIG_CYCLADES),y)
L_OBJS += cyclades.o
else
diff --git a/drivers/char/README.epca b/drivers/char/README.epca
new file mode 100644
index 000000000..3561608f1
--- /dev/null
+++ b/drivers/char/README.epca
@@ -0,0 +1,506 @@
+user.doc
+Digi International driver package for the PC/Xe, PC/Xi, PC/Xr, PC/Xem as well
+the EISA and PCI variants of these boards where applicable.
+Copyright (C) 1996 Digi International. Written by Ronnie Sanford digilnux@dgii.com
+
+ 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.
+
+
+This document describes the software used with the Digi/Linux driver package.
+The four user programs listed below are described in this document:
+
+ 1. digiConfig -> Application that configures the Digi driver.
+
+ 2. digiDload -> Application which initializes the Digi hardware.
+
+ 3. buildPCI -> Application which provides the user a method of
+ building device nodes for PCI devices.
+
+ 4. ditty -> Application which provides the user a method of
+ configuring terminal options on Digi hardware.
+
+
+
+--------------------------------------------------------------------------
+1. Configuring driver/kernel for Digi products
+--------------------------------------------------------------------------
+
+ The Digi driver must be configured each time Digi hardware is added
+ or removed. There are two supported methods of doing this. The
+ first method configures the driver dynamically at boot time but requires
+ the user to utilize the lilo loader. This method is the preffered method
+ as it does not require the rebuilding of the kernel. In order to use lilo
+ to configure Digi boards at boot time an appropriate append command should
+ be added to /etc/lilo.conf below the appropriate label decleration.
+ See footer 4. The append commands format is a string of comma seperated
+ identifiers or integers used to configure supported boards. These six
+ values in order are:
+
+ Enable/Disable this card or Override,
+ Type of card: PC/Xe (AccelePort) (0), PC/Xeve (1), PC/Xem or PC/Xr (2),
+ EISA/Xem (3), PC/Xe (64K) (4), PC/Xi (5).
+ Enable/Disable alternate pin arrangement,
+ Number of ports on this card,
+ I/O Port where card is configured (in HEX if using string identifiers),
+ Base of memory window (in HEX if using string identifiers)
+
+ A sample append command is given below which if used would configure and
+ enable a PC/Xe with 8 ports, at i/o address 200, memory address 0xd0000
+ with alt pin turned off. The lilo.conf file should look like this:
+
+ image = /vmlinuz
+ root = /dev/hda2
+ label = vmlinuz
+ append="digiepca=E,PC/Xe,D,8,200,D0000"
+
+ likewise the below will perform the same function:
+
+ image = /vmlinuz
+ root = /dev/hda2
+ label = vmlinuz
+ append="digiepca=1,0,0,8,512,851968"
+
+ Note:
+
+ PCI boards are auto-detected and configured (Hence their codes are
+ not given here). Do not attempt to configure PCI boards with the lilo
+ append command.
+
+ If configuration data has been specified by using digiConfig (Described
+ below), and you wish to override this configuration using lilo without
+ specifying a specific card (Example if there are PCI cards in the system)
+ the following override command will accomplish this:
+
+ -> append="digiepca=2"
+
+ If lilo is not enabled, the second method of configuring Digi hardware
+ will have to be used. digiConfig is an application that can be used
+ to inform the system of any additions, deletions, or modifications
+ involving Digi hardware. To use this method the operator executes
+ digiConfig anytime an EISA or ISA card is added that he wishes to use.
+ This routine is also used to remove cards from the system, and to modify
+ parameters of those cards already present in the system. Upon being
+ executed digiConfig modifies files accessed by the Digi driver. To make
+ these changes permanent; the operating system must be recompiled. After
+ the operating system has been recompiled and booted, the changes made with
+ digiConfig will be introduced to the user. This program MUST be executed
+ every time Digi EISA/ISA hardware configuration changes. Note, it is not
+ necessary to execute digiConfig in order to configure the Digi PCI cards.
+ These cards are self-identifying and will be recognized by the driver.
+ They cannot be displayed using digiConfig nor will digiConfig build the
+ device nodes their device nodes. See footer 1.
+
+ To execute digiConfig; simply type: digiConfig
+
+ The application will query you for the type, memory address, port
+ address, number of ports, alt pin disposition and status of each board
+ that exist on the system. Note, currently this driver only supports
+ PC/Xe, PC/Xeve, PC/Xi, PC/Xr, and PC/Xem as well as their EISA and PCI
+ implementations if applicable. All supported cards (Other than PCI) that
+ are present should be registered via digiConfig. See footer 2.
+
+ After all cards have been configured select exit. The system will then
+ inform you if any changes have been made, and ask you if it is okay to
+ make these changes permanent. If the data entered is correct, select okay.
+ Selecting cancel will prevent the changes from becoming active. digiConfig
+ can then be re-executed to configure the system again.
+
+--------------------------------------------------------------------------
+2. Initializing Digi hardware with digiDload
+--------------------------------------------------------------------------
+
+ digiDload is the application executed after the Digi driver has been
+ loaded. It is responsible for initializing the hardware and leaving
+ it in a state such that the Digi board may be operated by the user.
+ The application may be placed anywhere on the path, but its related
+ support files must be located in /etc/digi. The related files are:
+
+ sxfep.bin
+ sxbios.bin
+ xxfep.bin
+ xxbios.bin
+
+ The format for this command is "digiDload [v]". If given the "v"
+ option turns on verbosity. If not given the application runs in quite
+ mode. To execute the program simply type:
+
+ digiDload
+
+ Upon completion digiDload will generate the below message:
+
+ "digiDload complete: Card initialized"
+
+ At this point the card is configured and ready for normal usage. See
+ technotes.doc for information on how how ports are determined and
+ assigned.
+
+--------------------------------------------------------------------------
+3. Build PCI device nodes with buildPCI
+--------------------------------------------------------------------------
+
+ buildPCI is an application useful for building the necessary device nodes
+ for Digi PCI cards. It is reccomended that this tool be used because the
+ current digiConfig application does not provide this function for PCI cards
+ (Though it does build device nodes for non-PCI cards). To use this program
+ execute the following:first install the driver, and execute digiDload (See above). After digiDload
+ has sucessfully loaded, execute the following:
+
+ buildPCI <arg1> <arg2>
+
+ Where arg1 is the number of ports connected to Digi cards that are not PCI
+ (As shown by the digiConfig utility), and arg2 is the number of ports
+ connected to Digi cards that are PCI.
+
+ Note, buildPCI only has to be ran once to build the necessary device
+ nodes. Though this program may be executed at anytime, we reccomend
+ delaying execution until the first time you install the package and after
+ digiDload has been executed.
+
+--------------------------------------------------------------------------
+4. Setting Terminal Options with ditty
+--------------------------------------------------------------------------
+
+ditty is a utility program that sets and displays the terminal options
+for Digi intelligent serial products. See man ditty for detailed information.
+
+
+Footnotes:
+
+1. The 1.2.x kernel does not provide a method of mapping the high
+ addresses (Normally higher than RAM) associated with PCI. For this
+ reason, this driver disables PCI support while running under the 1.2.x
+ kernels.
+
+2. PCI cards should not and cannot be registered with digiConfig. After
+ the driver has been loaded buildPCI may be executed to construct the
+ necessary device nodes. This step is not necessary for system not
+ having Digi PCI cards.
+
+3. This is because we forsee a time when buildPCI may auto-detect the
+ available Digi PCI cards and this would only work if the program is
+ executed after digiDload.
+
+4. A complete example is given in install.doc.
+
+-------------CHANGES--------------------
+
+All changes should be recorded here. All changes should be explained in
+verbose detail.
+-----------------------------------------------------------------------
+Programmer : Ronnie Sanford
+Date : June 1, 1996
+Description (Verbose) : Initial release of driver package.
+Files affected : all
+Release version : 1.0.0f (BETA)
+-----------------------------------------------------------------------
+-----------------------------------------------------------------------
+Programmer : Ronnie Sanford
+Date : August 7, 1996
+Description (Verbose) : Made several modifications to provide PCI and EISA
+ support:
+
+ 1. We now allocate the termios structures based on
+ the maximum number of channels that COULD be
+ available to the system. We no longer use the
+ number of channels declared in epcaconfig.h
+ (NBDEVS) as the total channel number. This is
+ because this value does not represent channels
+ available to potential PCI cards. This new
+ larger value is also passed back to the os in
+ the num field of tty_driver.
+
+ 2. Added code to copy the previous board structure
+ (Now called static_boards) into a new local
+ copy of the boards structure. This has been
+ done so that PCI cards may be added to this
+ board array and later referenced (And even
+ queried.).
+
+ 3. Added code to pc_init that checks for supported
+ PCI cards. If found this code initializes a new
+ entry into the drivers local board structure
+ with the PCI cards address, and type, etc.. It
+ also bumps the card count (num_cards).
+
+ 4. Modified code in post_fep_init so that when this
+ routine is executed the number of ports supported
+ by a particular PCI card will be determined and
+ loaded into the board structure. It would be
+ much better if this code was placed in pc_init
+ (Because we could then report to the os the true
+ number of ports available; not just the max), but
+ since the card has to be booted to determine the
+ number of ports it supports, we are forced to do it
+ after DIGI_INIT has called post_fep_init. In the
+ future we may attempt to read the num ports
+ attached directly (address 0x1ac).
+
+ 5. Added board types to epca.h in support of various
+ PCI boards (Some of which do not exist yet).
+ Added procedures for these boards throughout the
+ code. Note, windowing is not necessary for PCI
+ boards.
+
+ 6. Added code supporting the EISA/XEM. This included
+ modifying epca.h with the new board type and
+ adding this type into the driver. The EISA/XEM
+ is basically identical to the PC/XEM, other than
+ it's base address does not have to be (And cannot
+ be configured directly).
+
+ 7. Modified digiConfig to prompt for EISA/XEM cards.
+
+Files affected : epca.c, epca.h, digi1.h, digiConfig
+Release version : 1.0.0g (BETA)
+-----------------------------------------------------------------------
+-----------------------------------------------------------------------
+Programmer : Ronnie Sanford
+Date : August 21, 1996
+Description (Verbose) : Made the following modifications:
+
+ 1. A problem affecting hard flow control was found
+ in the termios2digi_h routine. Specifically,
+ when the user activated hard flow control using
+ the CRTSCTS specification, the values used to
+ program hard flow control on the board were
+ incorrect. The solution was to change a line
+ that read "res |= ((ch->m_dtr) | (ch->m_rts));"
+ to "res |= ((ch->m_cts) | (ch->m_rts));" This
+ line only applies if cflag & CRTSCTS. Special
+ thanks to Matt Robinson (matt@mania.com.au) who
+ found and fixed this problem.
+
+ 2. In previous betas the cud device was set to CLOCAL
+ on driver boot up. Likewise the ttyD device was
+ set to ~CLOCAL. This has been fixed in this driver.
+ Now ttyD is CLOCAL and cud is ~CLOCAL. The fix
+ for this can be found in pc_init.
+
+ 3. In ditty.c many changes were made to eliminate bugs
+ and warning messages. Two ioctl calls were eliminated
+ as well a problem involving using the returned baud
+ index to determine the drivers baud rate. Newer
+ Linux kernels support higher baud rates by using
+ 0x1000 bit. When the returned value (ored with
+ 0x1000) was used to reference our fbaud table a
+ serious memory problem occured. This has been fixed.
+
+ 4. Added a request_region call to post_fep_init. This
+ should cause the i/o ports being used to be
+ registered with proc.
+
+ 5. Modified digiConfig to set all cud and ttyD devices
+ to read/write all permission.
+
+ 6. Developed a new apps called buildPCI that provides
+ an easy way to build device nodes for PCI cards.
+
+ 7. Modified user.doc and technotes.doc document the
+ use of buildPCI.
+
+Files affected : epca.c, ditty.c, digiConfig, user.doc, technotes.doc
+Release version : 1.0.0 (Official release)
+-----------------------------------------------------------------------
+Programmer : Ronnie Sanford
+Date : August 21, 1996
+Description (Verbose) : Made the following modifications:
+
+ 1. Removed code from pc_close which closes the
+ drivers line discipline and restores its original
+ line discipline. This is currently unecessary,
+ though future fast cook enhancements may require
+ this.
+
+ 2. Removed code in block_til_ready that set the
+ asyncflags to either ASYNC_CALLOUT_ACTIVE, or
+ ASYNC_NORMAL_ACTIVE. This code was redundant
+ as it already existed in block_til_ready.
+
+ 3. Added code in block_til_ready to cause a return
+ prior to schedule being called if the device
+ was a CALLOUT device. CALLOUT devices never
+ block on CD. (This was a serious bug that
+ prevented the CALLOUT devices (ttyD) from
+ functioning properly in some instances.
+
+ Make a change in the MODEMCHG_IND case of doevent
+ such that it does not require ASYNC_CALLOUT_ACTIVE
+ or ASYNC_NORMAL_ACTIVE to be set in order to
+ unblock an open (Using wait_interruptible).
+
+ Thanks to Mike McLagan (mike.mclagan@linux.org)
+ for diagnosing and fixing this problem.
+
+ 4. Made changes to the disposition of CLOCAL on
+ both SERIAL NORMAL and CALLOUT devices. Both
+ device types now have CLOCAL active at default.
+ This may be changed with a stty command.
+
+ 5. Made changes to digiConfig such that it checks
+ major.h (If valid) for the correct major
+ numbers to use.
+
+Files affected : epca.c, digiConfig
+Release version : 1.0.1a
+
+
+-----------------------------------------------------------------------
+Programmer : Ronnie Sanford
+Date : September 17, 1996
+Description (Verbose) : Made the following modifications:
+
+ 1. Modified pc_open such that it no longer checks
+ the cflag value returned by termios2digi_c for
+ CLOCAL. Digi hardware does not use this value
+ and thus termios2digi_c rightly screens this
+ value out. This driver checks for CLOCAL using
+ the drivers cflag value as known by the Linux OS.
+ (The value passed into termios2digi_c)
+
+ 2. Modified termios2digi_c to screen out the
+ CBAUDEX in CBAUD. This error caused parity to
+ automaticaly be enabled on at higher baud rates.
+
+
+ 3. Added the "disable_bh()" call to the shutdown
+ subroutine. Hopefully this will allow the driver
+ to correctly clean up after itself when used as a
+ module.
+
+ 4. Added support for the PC/XI and 64K PC/XE cards.
+ This involved primarily modifying digiDload to
+ initialize and boot the new cards; however
+ driver modifications were also required to
+ provide the proper windowing for the newly
+ supported cards. (Code was also added to
+ determine the memory segment of the XI card as
+ that card may have more than 64K. Currently
+ digiDload assumes a 64K XI card.)
+
+ 5. Added subroutine called epca_setup that can be
+ called during LILO boot up. This provides the
+ user an easy way to change cards; without
+ running digiConfig and without recompiling the
+ kernel. Added code in pc_init and pc_open to
+ support the epca_setup routine. pc_init checks
+ the liloconfig flag (Which is set by epca_setup)
+ to determine if the driver is using the LILO
+ arguments. If not pc_init loads the board data
+ found in epcaconfig.h; if so it DOESN'T load
+ epcaconfig data depending on epca_setup to handle
+ board configuration. pc_open has been modified
+ such that it checks to insure that no errors
+ occured during the LILO boot process. If a
+ user attempts to boot the driver (via. LILO)
+ with incorrect data, the open will fail.
+
+ 6. Modified the windowing routines pcxe_rxwinon
+ and pcxe_txwinon routines. A bug existed such
+ that those routines checked to see if the rxwin
+ and txwin flags were reset. If so they assumed
+ the board was an XI or 64K XE. Furthermore since
+ these flags were never initialized in our driver
+ sometimes they were 0 and therefore caused a
+ memory fault (Or at least a window overrun). This
+ code has been removed since the pcxe shares
+ nothing in common with the 64K XI and XE.
+
+ 7. Added code in pc_init to set the memory_seg for
+ the various boards. This code was necessary to
+ correct a bug in the PCXE, PCXEVE code where
+ receive and transmit pointers were being calculated
+ from an uninitialized variable (memory_seg).
+
+ 8. Modified digiConfig to allow 64K PC/XI and 64K
+ PC/XE cards to be configured.
+
+ 9. Made changes to support the new 2.1.x development
+ kernel. In particular this required changing all
+ references to vremap to ioremap.
+
+ 10. Modified digiConfig such that it now generates
+ node names corresponding to their internal
+ as opposed to the label on the port itself. Nodes
+ (ttyD?? and cud??) now start at 0. Example:
+ ttyD0 and cud0 represent port 1 on any supported
+ Digi product. A similar change has been made
+ in buildPCI.c.
+
+ 12. At the early portion of post_fep_init if a PCI
+ card is detected a warning message could be given
+ incorrectly if 64 ports were attached to a PCI
+ card. The below line :
+
+ epcaassert(bd->numports > 64,"PCI returned a invalid number of ports");
+
+ was changed to :
+
+ epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");
+
+ Remember that epcaassert checks for NOT true.
+ Special thanks to Daniel Taylor for fixing this.
+
+ 13. Modified the epcaparam routine. In version 100
+ and 101a there was a line that looked like the
+ below:
+
+ if (ch->omodem != mval)
+
+ The problem with this line was that the first time
+ through omodem was not initialized. Secondly, since
+ many TIOC commands did not alter mval (They use
+ a different variable) changes made by these commands
+ could be lost. This line was changed to:
+
+ mval ^= ch->modemfake & (mval ^ ch->modem);
+
+ if (ch->omodem ^ mval)
+
+ 14. Modified digiConfig in such a way that it checks
+ the version number of the kernel and if it finds
+ a 2.x.x kernel or higher it reads the necessary
+ major numbers for cud and ttyD devices from major.h.
+ This was also done in prior versions but these
+ versions required a #define which identified the
+ kernel as a version which did not have major numbers
+ assigned to Digi systems. This #define is no
+ longer required allowing the same source tree for
+ multiple kernel releases.
+
+ 15. Used macros to replace kernel specific calls such
+ as put_fs_long, get_fs_long, put_user, and get_user
+ the kernel version is now detected and the macro
+ is defined as to correspond with the kernel it
+ is being compiled into. Again this was done to
+ allow one source tree for multiple kernel releases.
+
+ 16. Added support for the new 2.1.x development kernels
+ to digiInstall.
+
+Files affected : epca.c, digiConfig
+Release version : 1.1.0
+-----------------------------------------------------------------------
+Programmer : Daniel Taylor
+Date : April 25, 1997
+Description (Verbose) : Updated driver:
+ 1. Fixed DCD bug. (&tq_scheduler)
+ 2. Removed BH handler code, as it was only handling
+ hangups, and not being called for that.
+ 3. Namespace cleanup (DIGI_TIMER2 => DIGI_TIMER)
+ 4. Updated to 2.1.36, removed #ifdefs for earlier
+ kernel revisions.
+Files affected : epca.c
+Release version : 1.1.1 (BETA)
+-----------------------------------------------------------------------
diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c
index d8b267095..3e2ee97bd 100644
--- a/drivers/char/busmouse.c
+++ b/drivers/char/busmouse.c
@@ -56,7 +56,7 @@
static struct mouse_status mouse;
static int mouse_irq = MOUSE_IRQ;
-void bmouse_setup(char *str, int *ints)
+__initfunc(void bmouse_setup(char *str, int *ints))
{
if (ints[0] > 0)
mouse_irq=ints[1];
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 2e5d420fd..56748c068 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -103,6 +103,7 @@
#include <linux/major.h>
#include <linux/mm.h>
#include <linux/ioport.h>
+#include <linux/init.h>
#ifdef CONFIG_APM
#include <linux/apm_bios.h>
#endif
@@ -2010,7 +2011,7 @@ static void console_bh(void)
* Reads the information preserved by setup.s to determine the current display
* type and sets everything accordingly.
*/
-unsigned long con_init(unsigned long kmem_start)
+__initfunc(unsigned long con_init(unsigned long kmem_start))
{
const char *display_desc = "????";
int currcons = 0;
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index c2d1648e6..878ac0d72 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
#include "consolemap.h"
@@ -483,8 +484,8 @@ conv_uni_to_pc(long ucs)
* initialized. It must be possible to call kmalloc(..., GFP_KERNEL)
* from this function, hence the call from sys_setup.
*/
-void
-console_map_init(void)
+__initfunc(void
+console_map_init(void))
{
con_set_default_unimap();
}
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 0a1825ee8..efa895a69 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -1,5 +1,7 @@
+#define BLOCKMOVE
static char rcsid[] =
-"$Revision: 1.36.3.9 $$Date: 1996/10/07 19:47:13 $";
+"$Revision: 1.36.4.27 $$Date: 1997/03/26 10:30:00 $";
+
/*
* linux/drivers/char/cyclades.c
*
@@ -22,11 +24,128 @@ static char rcsid[] =
* This module exports the following rs232 io functions:
* int cy_init(void);
* int cy_open(struct tty_struct *tty, struct file *filp);
+ * and the following functions for modularization.
+ * int init_module(void);
+ * void cleanup_module(void);
*
* $Log: cyclades.c,v $
- * Revision 1.36.3.9 1996/10/07 19:47:13 bentson
- * add MOD_DEC_USE_COUNT in one return from cy_close (as
- * noted by Jon Lewis <jlewis@INORGANIC5.FDT.NET>)
+ * Revision 1.36.4.27 1997/03/26 10:30:00 daniel
+ * Changed for suport linux versions 2.1.X.
+ * Backward compatible with linux versions 2.0.X.
+ * Corrected illegal use of filler field in
+ * CH_CTRL struct.
+ * Deleted some debug messages.
+ *
+ * Revision 1.36.4.26 1997/02/27 12:00:00 daniel
+ * Included check for NULL tty pointer in cyz_poll.
+ *
+ * Revision 1.36.4.25 1997/02/26 16:28:30 bentson
+ * Bill Foster at Blarg! Online services noticed that
+ * some of the switch elements of -Z modem control
+ * lacked a closing "break;"
+ *
+ * Revision 1.36.4.24 1997/02/24 11:00:00 daniel
+ * Changed low water threshold for buffer xmit_buf
+ *
+ * Revision 1.36.4.23 1996/12/02 21:50:16 bentson
+ * Marcio provided fix to modem status fetch for -Z
+ *
+ * Revision 1.36.4.22 1996/10/28 22:41:17 bentson
+ * improve mapping of -Z control page (thanks to Steve
+ * Price <stevep@fa.tdktca.com> for help on this)
+ *
+ * Revision 1.36.4.21 1996/09/10 17:00:10 bentson
+ * shift from cpu-bound to memcopy in cyz_polling operation
+ *
+ * Revision 1.36.4.20 1996/09/09 18:30:32 Bentson
+ * Added support to set and report higher speeds.
+ *
+ * Revision 1.36.4.19c 1996/08/09 10:00:00 Marcio Saito
+ * Some fixes in the HW flow control for the BETA release.
+ * Don't try to register the IRQ.
+ *
+ * Revision 1.36.4.19 1996/08/08 16:23:18 Bentson
+ * make sure "cyc" appears in all kernel messages; all soft interrupts
+ * handled by same routine; recognize out-of-band reception; comment
+ * out some diagnostic messages; leave RTS/CTS flow control to hardware;
+ * fix race condition in -Z buffer management; only -Y needs to explictly
+ * flush chars; tidy up some startup messages;
+ *
+ * Revision 1.36.4.18 1996/07/25 18:57:31 bentson
+ * shift MOD_INC_USE_COUNT location to match
+ * serial.c; purge some diagnostic messages;
+ *
+ * Revision 1.36.4.17 1996/07/25 18:01:08 bentson
+ * enable modem status messages and fetch & process them; note
+ * time of last activity type for each port; set_line_char now
+ * supports more than line 0 and treats 0 baud correctly;
+ * get_modem_info senses rs_status;
+ *
+ * Revision 1.36.4.16 1996/07/20 08:43:15 bentson
+ * barely works--now's time to turn on
+ * more features 'til it breaks
+ *
+ * Revision 1.36.4.15 1996/07/19 22:30:06 bentson
+ * check more -Z board status; shorten boot message
+ *
+ * Revision 1.36.4.14 1996/07/19 22:20:37 bentson
+ * fix reference to ch_ctrl in startup; verify return
+ * values from cyz_issue_cmd and cyz_update_channel;
+ * more stuff to get modem control correct;
+ *
+ * Revision 1.36.4.13 1996/07/11 19:53:33 bentson
+ * more -Z stuff folded in; re-order changes to put -Z stuff
+ * after -Y stuff (to make changes clearer)
+ *
+ * Revision 1.36.4.12 1996/07/11 15:40:55 bentson
+ * Add code to poll Cyclom-Z. Add code to get & set RS-232 control.
+ * Add code to send break. Clear firmware ID word at startup (so
+ * that other code won't talk to inactive board).
+ *
+ * Revision 1.36.4.11 1996/07/09 05:28:29 bentson
+ * add code for -Z in set_line_char
+ *
+ * Revision 1.36.4.10 1996/07/08 19:28:37 bentson
+ * fold more -Z stuff (or in some cases, error messages)
+ * into driver; add text to "don't know what to do" messages.
+ *
+ * Revision 1.36.4.9 1996/07/08 18:38:38 bentson
+ * moved compile-time flags near top of file; cosmetic changes
+ * to narrow text (to allow 2-up printing); changed many declarations
+ * to "static" to limit external symbols; shuffled code order to
+ * coalesce -Y and -Z specific code, also to put internal functions
+ * in order of tty_driver structure; added code to recognize -Z
+ * ports (and for moment, do nothing or report error); add cy_startup
+ * to parse boot command line for extra base addresses for ISA probes;
+ *
+ * Revision 1.36.4.8 1996/06/25 17:40:19 bentson
+ * reorder some code, fix types of some vars (int vs. long),
+ * add cy_setup to support user declared ISA addresses
+ *
+ * Revision 1.36.4.7 1996/06/21 23:06:18 bentson
+ * dump ioctl based firmware load (it's now a user level
+ * program); ensure uninitialzed ports cannot be used
+ *
+ * Revision 1.36.4.6 1996/06/20 23:17:19 bentson
+ * rename vars and restructure some code
+ *
+ * Revision 1.36.4.5 1996/06/14 15:09:44 bentson
+ * get right status back after boot load
+ *
+ * Revision 1.36.4.4 1996/06/13 19:51:44 bentson
+ * successfully loads firmware
+ *
+ * Revision 1.36.4.3 1996/06/13 06:08:33 bentson
+ * add more of the code for the boot/load ioctls
+ *
+ * Revision 1.36.4.2 1996/06/11 21:00:51 bentson
+ * start to add Z functionality--starting with ioctl
+ * for loading firmware
+ *
+ * Revision 1.36.4.1 1996/06/10 18:03:02 bentson
+ * added code to recognize Z/PCI card at initialization; report
+ * presence, but card is not initialized (because firmware needs
+ * to be loaded)
*
* Revision 1.36.3.8 1996/06/07 16:29:00 bentson
* starting minor number at zero; added missing verify_area
@@ -38,7 +157,7 @@ static char rcsid[] =
* remove unused diagnostic statements; minor 0 is first;
*
* Revision 1.36.3.6 1996/03/13 13:21:17 marcio
- * The kernel function ioremap (available only in later 1.3.xx kernels)
+ * The kernel function vremap (available only in later 1.3.xx kernels)
* allows the access to memory addresses above the RAM. This revision
* of the driver supports PCI boards below 1Mb (device id 0x100) and
* above 1Mb (device id 0x101).
@@ -261,6 +380,52 @@ static char rcsid[] =
*
*/
+/* If you need to install more boards than NR_CARDS, change the constant
+ in the definition below. No other change is necessary to support up to
+ eight boards. Beyond that you'll have to extend cy_isa_addresses. */
+
+#define NR_CARDS 4
+
+/*
+ If the total number of ports is larger than NR_PORTS, change this
+ constant in the definition below. No other change is necessary to
+ support more boards/ports. */
+
+#define NR_PORTS 64
+
+#define SERIAL_PARANOIA_CHECK
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_THROTTLE
+#undef SERIAL_DEBUG_OTHER
+#undef SERIAL_DEBUG_IO
+#undef SERIAL_DEBUG_COUNT
+#undef SERIAL_DEBUG_DTR
+#undef CYCLOM_16Y_HACK
+#undef CYCLOM_ENABLE_MONITORING
+#undef CY_PCI_DEBUG
+
+
+#if 0
+#define PAUSE __asm__("nop");
+#else
+#define PAUSE ;
+#endif
+
+#define cy_min(a,b) (((a)<(b))?(a):(b))
+
+#define CHARS_IN_BUF(buf_ctrl) \
+ ((buf_ctrl->rx_put - \
+ buf_ctrl->rx_get + \
+ buf_ctrl->rx_bufsize) % \
+ buf_ctrl->rx_bufsize)
+
+#define SPACE_IN_BUF(buf_ctrl) \
+ ((buf_ctrl->tx_get - \
+ buf_ctrl->tx_put + \
+ buf_ctrl->tx_bufsize - 1) % \
+ buf_ctrl->tx_bufsize)
+
+
#include <linux/module.h>
#include <linux/errno.h>
@@ -280,7 +445,7 @@ static char rcsid[] =
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <asm/segment.h>
#include <asm/bitops.h>
#include <linux/config.h>
@@ -290,24 +455,34 @@ static char rcsid[] =
#include <linux/pci.h>
#include <linux/init.h>
-#define small_delay(x) for(j=0;j<x;j++)k++;
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= 131328
-#define SERIAL_PARANOIA_CHECK
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_THROTTLE
-#undef SERIAL_DEBUG_OTHER
-#undef SERIAL_DEBUG_IO
-#undef SERIAL_DEBUG_COUNT
-#undef SERIAL_DEBUG_DTR
-#undef CYCLOM_16Y_HACK
-#undef CYCLOM_ENABLE_MONITORING
+#include <asm/uaccess.h>
+
+#define memcpy_fromfs copy_from_user
+#define memcpy_tofs copy_to_user
+#define put_fs_long put_user
+#define vremap ioremap
+
+static unsigned long get_fs_long(unsigned long *addr)
+{
+ unsigned long result = 0;
+ int error = get_user (result, addr);
+ if (error)
+ printk ("cyclades: get_fs_long: error == %d\n", error);
+ return result;
+}
+
+#endif
#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
+#define IS_CYC_Z(card) ((card).num_chips == 1)
-#define WAKEUP_CHARS 256
+#define WAKEUP_CHARS (SERIAL_XMIT_SIZE-256)
#define STD_COM_FLAGS (0)
@@ -325,72 +500,39 @@ static int cy_wild_int_mask;
static unsigned char *intr_base_addr;
-/* This is the address lockup table. The driver will probe for Cyclom-Y/ISA
- boards at all addresses in here. If you want the driver to probe addresses
- in a different address, add it to this table.
- If the driver is probing some other board and causing problems, remove the
- address from this table. */
+/* This is the address lookup table. The driver will probe for
+ Cyclom-Y/ISA boards at all addresses in here. If you want the
+ driver to probe addresses at a different address, add it to
+ this table. If the driver is probing some other board and
+ causing problems, remove the offending address from this table.
+ The cy_setup function extracts additional addresses from the
+ boot options line. The form is "cyclades=address,address..."
+*/
static unsigned char *cy_isa_addresses[] = {
- (unsigned char *) 0xD0000,
- (unsigned char *) 0xD2000,
- (unsigned char *) 0xD4000,
- (unsigned char *) 0xD6000,
- (unsigned char *) 0xD8000,
- (unsigned char *) 0xDA000,
- (unsigned char *) 0xDC000,
- (unsigned char *) 0xDE000,
+ (unsigned char *) 0xD0000,
+ (unsigned char *) 0xD2000,
+ (unsigned char *) 0xD4000,
+ (unsigned char *) 0xD6000,
+ (unsigned char *) 0xD8000,
+ (unsigned char *) 0xDA000,
+ (unsigned char *) 0xDC000,
+ (unsigned char *) 0xDE000,
+ 0,0,0,0,0,0,0,0
};
-#define NR_ISA_ADDRESSES (sizeof(cy_isa_addresses)/sizeof(unsigned char *))
+#define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*))
/* This is the per-card data structure containing address, irq, number of
- channels, etc. This driver supports a maximum of NR_CARDS cards. If
- you need to install more boards, change this constant in the definition
- below. No other change is necessary to support more boards. */
-
-#define NR_CARDS 4
-
+ channels, etc. This driver supports a maximum of NR_CARDS cards.
+*/
static struct cyclades_card cy_card[NR_CARDS];
/* This is the per-channel data structure containing pointers, flags
- and variables for the port. This driver supports a maximum of NR_PORTS.
- If the total number of ports is larger than NR_PORTS, change this
- constant in the definition below. No other change is necessary to
- support more boards/ports. */
-
-#define NR_PORTS 64
-
+ and variables for the port. This driver supports a maximum of NR_PORTS.
+*/
static struct cyclades_port cy_port[NR_PORTS];
-/* The Cyclom-Ye has placed the sequential chips in non-sequential
- * address order. This look-up table overcomes that problem.
- */
-static int cy_chip_offset [] =
- { 0x0000,
- 0x0400,
- 0x0800,
- 0x0C00,
- 0x0200,
- 0x0600,
- 0x0A00,
- 0x0E00
- };
-
-/* PCI related definitions */
-
-static unsigned short cy_pci_nboard = 0;
-static unsigned short cy_isa_nboard = 0;
-static unsigned short cy_nboard = 0;
-static unsigned short cy_pci_dev_id[] = {
- PCI_DEVICE_ID_CYCLOM_Y_Lo,/* PCI below 1Mb */
- PCI_DEVICE_ID_CYCLOM_Y_Hi,/* PCI above 1Mb */
- 0 /* end of table */
- };
-
-int cy_detect_isa(void);
-int cy_detect_pci(void);
-
-static int cy_next_channel = 0; /* next minor available */
+static int cy_next_channel = 0; /* next minor available */
static int serial_refcount;
@@ -401,17 +543,18 @@ static struct termios *serial_termios_locked[NR_PORTS];
/* This is the per-irq data structure,
it maps an irq to the corresponding card */
-struct cyclades_card *IRQ_cards[16];
+static struct cyclades_card *IRQ_cards[16];
/*
* tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
+ * lock it in case the memcpy_fromfs blocks while swapping in a page,
* and some other program tries to do a serial write at the same time.
* Since the lock will only come under contention when the system is
* swapping and available memory is low, it makes sense to share one
* buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
+ * memory if large numbers of serial ports are open. This buffer is
+ * allocated when the first cy_open occurs.
*/
static unsigned char *tmp_buf = 0;
static struct semaphore tmp_buf_sem = MUTEX;
@@ -420,83 +563,127 @@ static struct semaphore tmp_buf_sem = MUTEX;
* This is used to look up the divisor speeds and the timeouts
* We're normally limited to 15 distinct baud rates. The extra
* are accessed via settings in info->flags.
- * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
- * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
- * HI VHI
+ * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ * HI VHI
*/
static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
- 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800,115200,150000,
- 0};
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
+ 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800,115200,150000,
+ 0};
static char baud_co[] = { /* 25 MHz clock option table */
- /* value => 00 01 02 03 04 */
- /* divide by 8 32 128 512 2048 */
- 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
- 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ /* value => 00 01 02 03 04 */
+ /* divide by 8 32 128 512 2048 */
+ 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
+ 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static char baud_bpr[] = { /* 25 MHz baud rate period table */
- 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
- 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15};
+ 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
+ 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15};
static char baud_cor3[] = { /* receive threshold */
- 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
- 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07};
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07};
+/* The Cyclom-Ye has placed the sequential chips in non-sequential
+ * address order. This look-up table overcomes that problem.
+ */
+static int cy_chip_offset [] =
+ { 0x0000,
+ 0x0400,
+ 0x0800,
+ 0x0C00,
+ 0x0200,
+ 0x0600,
+ 0x0A00,
+ 0x0E00
+ };
+
+/* PCI related definitions */
-static void shutdown(struct cyclades_port *);
-static int startup (struct cyclades_port *);
-static void cy_throttle(struct tty_struct *);
-static void cy_unthrottle(struct tty_struct *);
-static void config_setup(struct cyclades_port *);
+static unsigned short cy_pci_nboard = 0;
+static unsigned short cy_isa_nboard = 0;
+static unsigned short cy_nboard = 0;
+static unsigned short cy_pci_dev_id[] = {
+ PCI_DEVICE_ID_CYCLOM_Y_Lo,/* PCI below 1Mb */
+ PCI_DEVICE_ID_CYCLOM_Y_Hi,/* PCI above 1Mb */
+ PCI_DEVICE_ID_CYCLOM_Z_Lo,/* PCI below 1Mb */
+ PCI_DEVICE_ID_CYCLOM_Z_Hi,/* PCI above 1Mb */
+ 0 /* end of table */
+ };
+
+
+static void cy_start(struct tty_struct *);
+static void set_line_char(struct cyclades_port *);
+static void cy_probe(int, void *, struct pt_regs *);
+static void cyz_poll(unsigned long);
#ifdef CYCLOM_SHOW_STATUS
static void show_status(int);
#endif
+static int cyz_timeron = 0;
+static struct timer_list
+cyz_timerlist = {
+ NULL, NULL, 0, 0, cyz_poll
+};
+
+
+/**************************************************
+error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
+memcpy_tofs (to, from, count);
+***************************************************************
+error = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned long *));
+memcpy_fromfs(to, from, count);
+**************************************************/
+
+
static inline int
serial_paranoia_check(struct cyclades_port *info,
- kdev_t device, const char *routine)
+ kdev_t device, const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
static const char *badmagic =
- "Warning: bad magic number for serial struct (%s) in %s\n";
+ "cyc Warning: bad magic number for serial struct (%s) in %s\n";
static const char *badinfo =
- "Warning: null cyclades_port for (%s) in %s\n";
+ "cyc Warning: null cyclades_port for (%s) in %s\n";
static const char *badrange =
- "Warning: cyclades_port out of range for (%s) in %s\n";
+ "cyc Warning: cyclades_port out of range for (%s) in %s\n";
if (!info) {
- printk(badinfo, kdevname(device), routine);
- return 1;
+ printk(badinfo, kdevname(device), routine);
+ return 1;
}
if( (long)info < (long)(&cy_port[0])
|| (long)(&cy_port[NR_PORTS]) < (long)info ){
- printk(badrange, kdevname(device), routine);
- return 1;
+ printk(badrange, kdevname(device), routine);
+ return 1;
}
if (info->magic != CYCLADES_MAGIC) {
- printk(badmagic, kdevname(device), routine);
- return 1;
+ printk(badmagic, kdevname(device), routine);
+ return 1;
}
#endif
- return 0;
+ return 0;
} /* serial_paranoia_check */
+
/* The following diagnostic routines allow the driver to spew
information on the screen, even (especially!) during interrupts.
*/
-void
+static void
SP(char *data){
unsigned long flags;
save_flags(flags); cli();
console_print(data);
restore_flags(flags);
-}
-void
+}/* SP */
+
+static void
CP(char data){
unsigned long flags;
char scrn[2];
@@ -507,128 +694,278 @@ CP(char data){
restore_flags(flags);
}/* CP */
-void CP1(int data) { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP1 */
-void CP2(int data) { CP1((data>>4) & 0x0f); CP1( data & 0x0f); }/* CP2 */
-void CP4(int data) { CP2((data>>8) & 0xff); CP2(data & 0xff); }/* CP4 */
-void CP8(long data) { CP4((data>>16) & 0xffff); CP4(data & 0xffff); }/* CP8 */
+static void CP4(int data)
+ { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP4 */
+static void CP8(int data)
+ { CP4((data>>4) & 0x0f); CP4( data & 0x0f); }/* CP8 */
+static void CP16(int data)
+ { CP8((data>>8) & 0xff); CP8(data & 0xff); }/* CP16 */
+static void CP32(long data)
+ { CP16((data>>16) & 0xffff); CP16(data & 0xffff); }/* CP32 */
+
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver
+ * (also known as the "bottom half"). This can be called any
+ * number of times for any channel without harm.
+ */
+static inline void
+cy_sched_event(struct cyclades_port *info, int event)
+{
+ info->event |= 1 << event; /* remember what kind of event and who */
+ queue_task(&info->tqueue, &tq_cyclades); /* it belongs to */
+ mark_bh(CYCLADES_BH); /* then trigger event */
+} /* cy_sched_event */
+
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using cy_sched_event(), and they get done here.
+ *
+ * This is done through one level of indirection--the task queue.
+ * When a hardware interrupt service routine wants service by the
+ * driver's bottom half, it enqueues the appropriate tq_struct (one
+ * per port) to the tq_cyclades work queue and sets a request flag
+ * via mark_bh for processing that queue. When the time is right,
+ * do_cyclades_bh is called (because of the mark_bh) and it requests
+ * that the work queue be processed.
+ *
+ * Although this may seem unwieldy, it gives the system a way to
+ * pass an argument (in this case the pointer to the cyclades_port
+ * structure) to the bottom half of the driver. Previous kernels
+ * had to poll every port to see if that port needed servicing.
+ */
+static void
+do_cyclades_bh(void)
+{
+ run_task_queue(&tq_cyclades);
+} /* do_cyclades_bh */
+
+
+static void
+do_softint(void *private_)
+{
+ struct cyclades_port *info = (struct cyclades_port *) private_;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
+ tty_hangup(info->tty);
+ wake_up_interruptible(&info->open_wait);
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|
+ ASYNC_CALLOUT_ACTIVE);
+ }
+ if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
+ wake_up_interruptible(&info->open_wait);
+ }
+ if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
+ if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP))
+ && tty->ldisc.write_wakeup){
+ (tty->ldisc.write_wakeup)(tty);
+ }
+ wake_up_interruptible(&tty->write_wait);
+ }
+} /* do_softint */
+
+
+/***********************************************************/
+/********* Start of block of Cyclom-Y specific code ********/
/* This routine waits up to 1000 micro-seconds for the previous
command to the Cirrus chip to complete and then issues the
new command. An error is returned if the previous command
didn't finish within the time limit.
*/
-u_short
-write_cy_cmd(u_char *base_addr, u_char cmd, int index)
+static int
+cyy_issue_cmd(u_char *base_addr, u_char cmd, int index)
{
unsigned long flags;
volatile int i;
save_flags(flags); cli();
- /* Check to see that the previous command has completed */
- for(i = 0 ; i < 100 ; i++){
- if (base_addr[CyCCR<<index] == 0){
- break;
- }
- udelay(10L);
- }
- /* if the CCR never cleared, the previous command
- didn't finish within the "reasonable time" */
- if ( i == 100 ) {
- restore_flags(flags);
- return (-1);
- }
+ /* Check to see that the previous command has completed */
+ for(i = 0 ; i < 100 ; i++){
+ if (base_addr[CyCCR<<index] == 0){
+ break;
+ }
+ udelay(10L);
+ }
+ /* if the CCR never cleared, the previous command
+ didn't finish within the "reasonable time" */
+ if ( i == 100 ) {
+ restore_flags(flags);
+ return (-1);
+ }
- /* Issue the new command */
- base_addr[CyCCR<<index] = cmd;
+ /* Issue the new command */
+ base_addr[CyCCR<<index] = cmd;
restore_flags(flags);
return(0);
-} /* write_cy_cmd */
+} /* cyy_issue_cmd */
+static int probe_ready;
-/* cy_start and cy_stop provide software output flow control as a
- function of XON/XOFF, software CTS, and other such stuff. */
+/*
+ * Grab all interrupts in preparation for doing an automatic irq
+ * detection. dontgrab is a mask of irq's _not_ to grab. Returns a
+ * mask of irq's which were grabbed and should therefore be freed
+ * using free_all_interrupts().
+ */
+static int
+grab_all_interrupts(int dontgrab)
+{
+ int irq_lines = 0;
+ int i, mask;
+
+ for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
+ if (!(mask & dontgrab)
+ && !request_irq(i, cy_probe,
+ SA_INTERRUPT, "serial probe", NULL)) {
+ irq_lines |= mask;
+ }
+ }
+ return irq_lines;
+} /* grab_all_interrupts */
+/*
+ * Release all interrupts grabbed by grab_all_interrupts
+ */
static void
-cy_stop(struct tty_struct *tty)
+free_all_interrupts(int irq_lines)
{
- struct cyclades_card *cinfo;
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned char *base_addr;
- int chip,channel,index;
- unsigned long flags;
-
-#ifdef SERIAL_DEBUG_OTHER
- printk("cy_stop ttyC%d\n", info->line); /* */
-#endif
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ if (irq_lines & (1 << i))
+ free_irq(i,NULL);
+ }
+} /* free_all_interrupts */
- if (serial_paranoia_check(info, tty->device, "cy_stop"))
- return;
-
- cinfo = &cy_card[info->card];
- index = cinfo->bus_index;
- channel = info->line - cinfo->first_line;
- chip = channel>>2;
- channel &= 0x03;
- base_addr = (unsigned char*)
- (cy_card[info->card].base_addr + (cy_chip_offset[chip]<<index));
+/*
+ * This routine returns a bitfield of "wild interrupts". Basically,
+ * any unclaimed interrupts which is flapping around.
+ */
+static int
+check_wild_interrupts(void)
+{
+ int i, mask;
+ int wild_interrupts = 0;
+ int irq_lines;
+ unsigned long timeout;
+ unsigned long flags;
+
+ /*Turn on interrupts (they may be off) */
+ save_flags(flags); sti();
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)(channel & 0x0003); /* index channel */
- base_addr[CySRER<<index] &= ~CyTxMpty;
+ irq_lines = grab_all_interrupts(0);
+
+ /*
+ * Delay for 0.1 seconds -- we use a busy loop since this may
+ * occur during the bootup sequence
+ */
+ timeout = jiffies+10;
+ while (timeout >= jiffies)
+ ;
+
+ cy_triggered = 0; /* Reset after letting things settle */
+
+ timeout = jiffies+10;
+ while (timeout >= jiffies)
+ ;
+
+ for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
+ if ((cy_triggered & (1 << i)) &&
+ (irq_lines & (1 << i))) {
+ wild_interrupts |= mask;
+ }
+ }
+ free_all_interrupts(irq_lines);
restore_flags(flags);
+ return wild_interrupts;
+} /* check_wild_interrupts */
- return;
-} /* cy_stop */
-
-static void
-cy_start(struct tty_struct *tty)
+/*
+ * This routine is called by do_auto_irq(); it attempts to determine
+ * which interrupt a serial port is configured to use. It is not
+ * fool-proof, but it works a large part of the time.
+ */
+static int
+get_auto_irq(unsigned char *address)
{
- struct cyclades_card *cinfo;
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long timeout;
unsigned char *base_addr;
- int chip,channel,index;
- unsigned long flags;
-
-#ifdef SERIAL_DEBUG_OTHER
- printk("cy_start ttyC%d\n", info->line); /* */
-#endif
-
- if (serial_paranoia_check(info, tty->device, "cy_start"))
- return;
-
- cinfo = &cy_card[info->card];
- index = cinfo->bus_index;
- channel = info->line - cinfo->first_line;
- chip = channel>>2;
- channel &= 0x03;
- base_addr = (unsigned char*)
- (cy_card[info->card].base_addr + (cy_chip_offset[chip]<<index));
+ int index;
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)(channel & 0x0003);
+ index = 0; /* IRQ probing is only for ISA */
+ base_addr = address;
+ intr_base_addr = address;
+
+ /*
+ * Enable interrupts and see who answers
+ */
+ cy_irq_triggered = 0;
+ cli();
+ base_addr[CyCAR<<index] = 0;
+ cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
base_addr[CySRER<<index] |= CyTxMpty;
- restore_flags(flags);
-
- return;
-} /* cy_start */
-
+ probe_ready = 1;
+ sti();
+
+ timeout = jiffies+2;
+ while (timeout >= jiffies) {
+ if (cy_irq_triggered)
+ break;
+ }
+ probe_ready = 0;
+ return(cy_irq_triggered);
+} /* get_auto_irq */
/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver
- * (also known as the "bottom half"). This can be called any
- * number of times for any channel without harm.
+ * Calls get_auto_irq() multiple times, to make sure we don't get
+ * faked out by random interrupts
*/
-static inline void
-cy_sched_event(struct cyclades_port *info, int event)
+static int
+do_auto_irq(unsigned char *address)
{
- info->event |= 1 << event; /* remember what kind of event and who */
- queue_task_irq_off(&info->tqueue, &tq_cyclades); /* it belongs to */
- mark_bh(CYCLADES_BH); /* then trigger event */
-} /* cy_sched_event */
+ int irq_lines = 0;
+ int irq_try_1 = 0, irq_try_2 = 0;
+ int retries;
+ unsigned long flags;
+ /* Turn on interrupts (they may be off) */
+ save_flags(flags); sti();
+
+ probe_ready = 0;
+
+ cy_wild_int_mask = check_wild_interrupts();
+
+ irq_lines = grab_all_interrupts(cy_wild_int_mask);
+
+ for (retries = 0; retries < 5; retries++) {
+ if (!irq_try_1)
+ irq_try_1 = get_auto_irq(address);
+ if (!irq_try_2)
+ irq_try_2 = get_auto_irq(address);
+ if (irq_try_1 && irq_try_2) {
+ if (irq_try_1 == irq_try_2)
+ break;
+ irq_try_1 = irq_try_2 = 0;
+ }
+ }
+ restore_flags(flags);
+ free_all_interrupts(irq_lines);
+ return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
+} /* do_auto_irq */
-static int probe_ready;
/*
* This interrupt routine is used
@@ -638,30 +975,31 @@ static void
cy_probe(int irq, void *dev_id, struct pt_regs *regs)
{
int save_xir, save_car;
- int index = 0; /* probing interrupts is only for ISA */
+ int index = 0; /* probing interrupts is only for ISA */
if (!probe_ready) {
- *(intr_base_addr + (Cy_ClrIntr<<index)) = 0;
+ *(intr_base_addr + (Cy_ClrIntr<<index)) = 0;
return;
}
cy_irq_triggered = irq;
cy_triggered |= 1 << irq;
- if(intr_base_addr[CySVRR<<index] != 0) {
- save_xir = (u_char) intr_base_addr[CyTIR<<index];
- save_car = intr_base_addr[CyCAR<<index];
- if ((save_xir & 0x3) != 0){
- SP("channel ");
- CP2(save_xir);
- SP(" requesting unexpected interrupt\n");
- }
- intr_base_addr[CyCAR<<index] = (save_xir & 0x3);
- intr_base_addr[CySRER<<index] &= ~CyTxMpty;
- intr_base_addr[CyTIR<<index] = (save_xir & 0x3f);
- intr_base_addr[CyCAR<<index] = (save_car);
- }
- *(intr_base_addr + (Cy_ClrIntr<<index)) = 0; /* Cy_ClrIntr is 0x1800 */
+ if(intr_base_addr[CySVRR<<index] != 0) {
+ save_xir = (u_char) intr_base_addr[CyTIR<<index];
+ save_car = intr_base_addr[CyCAR<<index];
+ if ((save_xir & 0x3) != 0){
+ SP("channel ");
+ CP8(save_xir);
+ SP(" requesting unexpected interrupt\n");
+ }
+ intr_base_addr[CyCAR<<index] = (save_xir & 0x3);
+ intr_base_addr[CySRER<<index] &= ~CyTxMpty;
+ intr_base_addr[CyTIR<<index] = (save_xir & 0x3f);
+ intr_base_addr[CyCAR<<index] = (save_car);
+ }
+ *(intr_base_addr + (Cy_ClrIntr<<index)) = 0;
+ /* Cy_ClrIntr is 0x1800 */
return;
} /* cy_probe */
@@ -670,7 +1008,7 @@ cy_probe(int irq, void *dev_id, struct pt_regs *regs)
received, out buffer empty, modem change, etc.
*/
static void
-cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct tty_struct *tty;
int status;
@@ -703,8 +1041,8 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
do{
had_work = 0;
for ( chip = 0 ; chip < cinfo->num_chips ; chip ++) {
- base_addr = (unsigned char *)
- (cinfo->base_addr + (cy_chip_offset[chip]<<index));
+ base_addr = (unsigned char *)
+ (cinfo->base_addr + (cy_chip_offset[chip]<<index));
too_many = 0;
while ( (status = base_addr[CySVRR<<index]) != 0x00) {
had_work++;
@@ -712,12 +1050,12 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
no chip can monopolize the driver. This forces the
chips to be checked in a round-robin fashion (after
draining each of a bunch (1000) of characters).
- */
+ */
if(1000<too_many++){
break;
}
- if (status & CySRReceive) { /* reception interrupt */
- /* determine the channel and change to that context */
+ if (status & CySRReceive) { /* reception interrupt */
+ /* determine the channel & change to that context */
save_xir = (u_char) base_addr[CyRIR<<index];
channel = (u_short ) (save_xir & CyIRChannel);
i = channel + chip * 4 + cinfo->first_line;
@@ -746,82 +1084,84 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
continue;
}
if (tty->flip.count < TTY_FLIPBUF_SIZE){
- tty->flip.count++;
- if (data & info->read_status_mask){
- if(data & CyBREAK){
- *tty->flip.flag_buf_ptr++ =
- TTY_BREAK;
- *tty->flip.char_buf_ptr++ =
- base_addr[CyRDSR<<index];
- if (info->flags & ASYNC_SAK){
- do_SAK(tty);
- }
- }else if(data & CyFRAME){
- *tty->flip.flag_buf_ptr++ =
- TTY_FRAME;
- *tty->flip.char_buf_ptr++ =
- base_addr[CyRDSR<<index];
- }else if(data & CyPARITY){
- *tty->flip.flag_buf_ptr++ =
- TTY_PARITY;
- *tty->flip.char_buf_ptr++ =
- base_addr[CyRDSR<<index];
- }else if(data & CyOVERRUN){
- *tty->flip.flag_buf_ptr++ =
- TTY_OVERRUN;
- *tty->flip.char_buf_ptr++ = 0;
- /* If the flip buffer itself is
- overflowing, we still loose
- the next incoming character.
- */
- if(tty->flip.count < TTY_FLIPBUF_SIZE){
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ =
- TTY_NORMAL;
- *tty->flip.char_buf_ptr++ =
- base_addr[CyRDSR<<index];
- }
- /* These two conditions may imply */
- /* a normal read should be done. */
- /* }else if(data & CyTIMEOUT){ */
- /* }else if(data & CySPECHAR){ */
- }else{
- *tty->flip.flag_buf_ptr++ = 0;
- *tty->flip.char_buf_ptr++ = 0;
- }
- }else{
- *tty->flip.flag_buf_ptr++ = 0;
- *tty->flip.char_buf_ptr++ = 0;
- }
+ tty->flip.count++;
+ if (data & info->read_status_mask){
+ if(data & CyBREAK){
+ *tty->flip.flag_buf_ptr++ =
+ TTY_BREAK;
+ *tty->flip.char_buf_ptr++ =
+ base_addr[CyRDSR<<index];
+ if (info->flags & ASYNC_SAK){
+ do_SAK(tty);
+ }
+ }else if(data & CyFRAME){
+ *tty->flip.flag_buf_ptr++ =
+ TTY_FRAME;
+ *tty->flip.char_buf_ptr++ =
+ base_addr[CyRDSR<<index];
+ }else if(data & CyPARITY){
+ *tty->flip.flag_buf_ptr++ =
+ TTY_PARITY;
+ *tty->flip.char_buf_ptr++ =
+ base_addr[CyRDSR<<index];
+ }else if(data & CyOVERRUN){
+ *tty->flip.flag_buf_ptr++ =
+ TTY_OVERRUN;
+ *tty->flip.char_buf_ptr++ = 0;
+ /* If the flip buffer itself is
+ overflowing, we still loose
+ the next incoming character.
+ */
+ if(tty->flip.count
+ < TTY_FLIPBUF_SIZE){
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ =
+ TTY_NORMAL;
+ *tty->flip.char_buf_ptr++ =
+ base_addr[CyRDSR<<index];
+ }
+ /* These two conditions may imply */
+ /* a normal read should be done. */
+ /* }else if(data & CyTIMEOUT){ */
+ /* }else if(data & CySPECHAR){ */
+ }else{
+ *tty->flip.flag_buf_ptr++ = 0;
+ *tty->flip.char_buf_ptr++ = 0;
+ }
+ }else{
+ *tty->flip.flag_buf_ptr++ = 0;
+ *tty->flip.char_buf_ptr++ = 0;
+ }
}else{
- /* there was a software buffer overrun
- and nothing could be done about it!!! */
+ /* there was a software buffer
+ overrun and nothing could be
+ done about it!!! */
}
} else { /* normal character reception */
- /* load # characters available from the chip */
+ /* load # chars available from the chip */
char_count = base_addr[CyRDCR<<index];
#ifdef CYCLOM_ENABLE_MONITORING
- ++info->mon.int_count;
- info->mon.char_count += char_count;
- if (char_count > info->mon.char_max)
- info->mon.char_max = char_count;
- info->mon.char_last = char_count;
+ ++info->mon.int_count;
+ info->mon.char_count += char_count;
+ if (char_count > info->mon.char_max)
+ info->mon.char_max = char_count;
+ info->mon.char_last = char_count;
#endif
while(char_count--){
- if (tty->flip.count >= TTY_FLIPBUF_SIZE){
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE){
break;
}
- tty->flip.count++;
+ tty->flip.count++;
data = base_addr[CyRDSR<<index];
- *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
- *tty->flip.char_buf_ptr++ = data;
+ *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+ *tty->flip.char_buf_ptr++ = data;
#ifdef CYCLOM_16Y_HACK
- udelay(10L);
+ udelay(10L);
#endif
}
}
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+ queue_task(&tty->flip.tqueue, &tq_timer);
}
/* end of service */
base_addr[CyRIR<<index] = (save_xir & 0x3f);
@@ -829,18 +1169,19 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
- if (status & CySRTransmit) { /* transmission interrupt */
- /* Since we only get here when the transmit buffer is empty,
- we know we can always stuff a dozen characters. */
+ if (status & CySRTransmit) { /* transmission interrupt */
+ /* Since we only get here when the transmit buffer
+ is empty, we know we can always stuff a dozen
+ characters. */
- /* determine the channel and change to that context */
+ /* determine the channel & change to that context */
save_xir = (u_char) base_addr[CyTIR<<index];
channel = (u_short ) (save_xir & CyIRChannel);
i = channel + chip * 4 + cinfo->first_line;
save_car = base_addr[CyCAR<<index];
base_addr[CyCAR<<index] = save_xir;
- /* validate the port number (as configured and open) */
+ /* validate the port# (as configured and open) */
if( (i < 0) || (NR_PORTS <= i) ){
base_addr[CySRER<<index] &= ~CyTxMpty;
goto txend;
@@ -852,7 +1193,7 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
goto txdone;
}
- /* load the on-chip space available for outbound data */
+ /* load the on-chip space for outbound data */
char_count = info->xmit_fifo_size;
@@ -863,64 +1204,65 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
info->x_char = 0;
}
- if (info->x_break){
- /* The Cirrus chip requires the "Embedded Transmit
- Commands" of start break, delay, and end break
- sequences to be sent. The duration of the
- break is given in TICs, which runs at HZ
- (typically 100) and the PPR runs at 200 Hz,
- so the delay is duration * 200/HZ, and thus a
- break can run from 1/100 sec to about 5/4 sec.
- */
- base_addr[CyTDR<<index] = 0; /* start break */
- base_addr[CyTDR<<index] = 0x81;
- base_addr[CyTDR<<index] = 0; /* delay a bit */
- base_addr[CyTDR<<index] = 0x82;
- base_addr[CyTDR<<index] = info->x_break*200/HZ;
- base_addr[CyTDR<<index] = 0; /* terminate break */
- base_addr[CyTDR<<index] = 0x83;
- char_count -= 7;
- info->x_break = 0;
- }
+ if (info->x_break){
+ /* The Cirrus chip requires the "Embedded
+ Transmit Commands" of start break, delay,
+ and end break sequences to be sent. The
+ duration of the break is given in TICs,
+ which runs at HZ (typically 100) and the
+ PPR runs at 200 Hz, so the delay is
+ duration * 200/HZ, and thus a break can
+ run from 1/100 sec to about 5/4 sec.
+ */
+ base_addr[CyTDR<<index] = 0; /* start break */
+ base_addr[CyTDR<<index] = 0x81;
+ base_addr[CyTDR<<index] = 0; /* delay a bit */
+ base_addr[CyTDR<<index] = 0x82;
+ base_addr[CyTDR<<index] = info->x_break*200/HZ;
+ base_addr[CyTDR<<index] = 0; /* finish break */
+ base_addr[CyTDR<<index] = 0x83;
+ char_count -= 7;
+ info->x_break = 0;
+ }
while (char_count-- > 0){
if (!info->xmit_cnt){
- base_addr[CySRER<<index] &= ~CyTxMpty;
- goto txdone;
+ base_addr[CySRER<<index] &= ~CyTxMpty;
+ goto txdone;
}
- if (info->xmit_buf == 0){
- base_addr[CySRER<<index] &= ~CyTxMpty;
- goto txdone;
- }
- if (info->tty->stopped || info->tty->hw_stopped){
- base_addr[CySRER<<index] &= ~CyTxMpty;
- goto txdone;
- }
- /* Because the Embedded Transmit Commands have been
- enabled, we must check to see if the escape
- character, NULL, is being sent. If it is, we
- must ensure that there is room for it to be
- doubled in the output stream. Therefore we
- no longer advance the pointer when the character
- is fetched, but rather wait until after the check
- for a NULL output character. (This is necessary
- because there may not be room for the two chars
- needed to send a NULL.
- */
+ if (info->xmit_buf == 0){
+ base_addr[CySRER<<index] &= ~CyTxMpty;
+ goto txdone;
+ }
+ if (info->tty->stopped || info->tty->hw_stopped){
+ base_addr[CySRER<<index] &= ~CyTxMpty;
+ goto txdone;
+ }
+ /* Because the Embedded Transmit Commands have
+ been enabled, we must check to see if the
+ escape character, NULL, is being sent. If it
+ is, we must ensure that there is room for it
+ to be doubled in the output stream. Therefore
+ we no longer advance the pointer when the
+ character is fetched, but rather wait until
+ after the check for a NULL output character.
+ This is necessary because there may not be
+ room for the two chars needed to send a NULL.)
+ */
outch = info->xmit_buf[info->xmit_tail];
if( outch ){
- info->xmit_cnt--;
- info->xmit_tail = (info->xmit_tail + 1)
- & (PAGE_SIZE - 1);
- base_addr[CyTDR<<index] = outch;
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1)
+ & (PAGE_SIZE - 1);
+ base_addr[CyTDR<<index] = outch;
}else{
if(char_count > 1){
- info->xmit_cnt--;
- info->xmit_tail = (info->xmit_tail + 1)
- & (PAGE_SIZE - 1);
- base_addr[CyTDR<<index] = outch;
- base_addr[CyTDR<<index] = 0;
- char_count--;
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1)
+ & (PAGE_SIZE - 1);
+ base_addr[CyTDR<<index] = outch;
+ base_addr[CyTDR<<index] = 0;
+ char_count--;
}else{
}
}
@@ -939,10 +1281,11 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (status & CySRModem) { /* modem interrupt */
- /* determine the channel and change to that context */
+ /* determine the channel & change to that context */
save_xir = (u_char) base_addr[CyMIR<<index];
channel = (u_short ) (save_xir & CyIRChannel);
- info = &cy_port[channel + chip * 4 + cinfo->first_line];
+ info = &cy_port[channel + chip * 4
+ + cinfo->first_line];
info->last_active = jiffies;
save_car = base_addr[CyCAR<<index];
base_addr[CyCAR<<index] = save_xir;
@@ -950,32 +1293,40 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
mdm_change = base_addr[CyMISR<<index];
mdm_status = base_addr[CyMSVR1<<index];
- if(info->tty == 0){ /* nowhere to put the data, ignore it */
+ if(info->tty == 0){/* no place for data, ignore it*/
;
}else{
if((mdm_change & CyDCD)
&& (info->flags & ASYNC_CHECK_CD)){
if(mdm_status & CyDCD){
- cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP);
- }else if(!((info->flags & ASYNC_CALLOUT_ACTIVE)
- &&(info->flags & ASYNC_CALLOUT_NOHUP))){
- cy_sched_event(info, Cy_EVENT_HANGUP);
+ cy_sched_event(info,
+ Cy_EVENT_OPEN_WAKEUP);
+ }else if(!((info->flags
+ & ASYNC_CALLOUT_ACTIVE)
+ &&(info->flags
+ & ASYNC_CALLOUT_NOHUP))){
+ cy_sched_event(info,
+ Cy_EVENT_HANGUP);
}
}
if((mdm_change & CyCTS)
&& (info->flags & ASYNC_CTS_FLOW)){
if(info->tty->hw_stopped){
if(mdm_status & CyCTS){
- /* !!! cy_start isn't used because... */
+ /* cy_start isn't used
+ because... !!! */
info->tty->hw_stopped = 0;
- base_addr[CySRER<<index] |= CyTxMpty;
- cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ base_addr[CySRER<<index] |= CyTxMpty;
+ cy_sched_event(info,
+ Cy_EVENT_WRITE_WAKEUP);
}
}else{
if(!(mdm_status & CyCTS)){
- /* !!! cy_stop isn't used because... */
+ /* cy_stop isn't used
+ because ... !!! */
info->tty->hw_stopped = 1;
- base_addr[CySRER<<index] &= ~CyTxMpty;
+ base_addr[CySRER<<index] &=
+ ~CyTxMpty;
}
}
}
@@ -993,217 +1344,373 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
} while(had_work);
/* clear interrupts */
- *(card_base_addr + (Cy_ClrIntr<<index)) = 0; /* Cy_ClrIntr is 0x1800 */
+ *(card_base_addr + (Cy_ClrIntr<<index)) = 0;
+ /* Cy_ClrIntr is 0x1800 */
-} /* cy_interrupt */
+} /* cyy_interrupt */
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * cy_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using cy_sched_event(), and they get done here.
- *
- * This is done through one level of indirection--the task queue.
- * When a hardware interrupt service routine wants service by the
- * driver's bottom half, it enqueues the appropriate tq_struct (one
- * per port) to the tq_cyclades work queue and sets a request flag
- * via mark_bh for processing that queue. When the time is right,
- * do_cyclades_bh is called (because of the mark_bh) and it requests
- * that the work queue be processed.
- *
- * Although this may seem unwieldy, it gives the system a way to
- * pass an argument (in this case the pointer to the cyclades_port
- * structure) to the bottom half of the driver. Previous kernels
- * had to poll every port to see if that port needed servicing.
- */
-static void
-do_cyclades_bh(void)
-{
- run_task_queue(&tq_cyclades);
-} /* do_cyclades_bh */
+/***********************************************************/
+/********* End of block of Cyclom-Y specific code **********/
+/******** Start of block of Cyclom-Z specific code *********/
+/***********************************************************/
-static void
-do_softint(void *private_)
+
+static int
+cyz_fetch_msg( struct cyclades_card *cinfo,
+ u_long *channel, u_char *cmd, u_long **param)
{
- struct cyclades_port *info = (struct cyclades_port *) private_;
- struct tty_struct *tty;
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ unsigned long loc_doorbell;
+
+ firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
+ return (-1);
+ }
+ zfw_ctrl = (struct ZFW_CTRL *)
+ (cinfo->base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+
+ loc_doorbell = ((struct RUNTIME_9060 *)
+ (cinfo->ctl_addr))->loc_doorbell;
+ if (loc_doorbell){
+ *cmd = (char)(0xff & loc_doorbell);
+ *channel = board_ctrl->fwcmd_channel;
+ *param = board_ctrl->fwcmd_param;
+ ((struct RUNTIME_9060 *)
+ (cinfo->ctl_addr))->loc_doorbell = 0xffffffff;
+ return 1;
+ }
+ return 0;
+} /* cyz_fetch_msg */
- tty = info->tty;
- if (!tty)
- return;
- if (clear_bit(Cy_EVENT_HANGUP, &info->event)) {
- tty_hangup(info->tty);
- wake_up_interruptible(&info->open_wait);
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|
- ASYNC_CALLOUT_ACTIVE);
- }
- if (clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
- wake_up_interruptible(&info->open_wait);
+static int
+cyz_issue_cmd( struct cyclades_card *cinfo,
+ u_long channel, u_char cmd, u_long *param)
+{
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ volatile unsigned long *pci_doorbell;
+ int index;
+
+ firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
+ return (-1);
}
- if (clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
- if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP))
- && tty->ldisc.write_wakeup){
- (tty->ldisc.write_wakeup)(tty);
- }
- wake_up_interruptible(&tty->write_wait);
+ zfw_ctrl = (struct ZFW_CTRL *)
+ (cinfo->base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+
+ index = 0;
+ pci_doorbell = &((struct RUNTIME_9060 *)
+ (cinfo->ctl_addr))->pci_doorbell;
+ while( (*pci_doorbell & 0xff) != 0){
+ if (index++ == 100){
+ return(-1);
+ }
+ udelay(50L);
}
-} /* do_softint */
+ board_ctrl->hcmd_channel = channel;
+ board_ctrl->hcmd_param = param;
+ *pci_doorbell = (long)cmd;
+
+ return(0);
+} /* cyz_issue_cmd */
-/*
- * Grab all interrupts in preparation for doing an automatic irq
- * detection. dontgrab is a mask of irq's _not_ to grab. Returns a
- * mask of irq's which were grabbed and should therefore be freed
- * using free_all_interrupts().
- */
static int
-grab_all_interrupts(int dontgrab)
-{
- int irq_lines = 0;
- int i, mask;
-
- for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
- if (!(mask & dontgrab)
- && !request_irq(i, cy_probe, SA_INTERRUPT, "serial probe", NULL)) {
- irq_lines |= mask;
- }
+cyz_update_channel( struct cyclades_card *cinfo,
+ u_long channel, u_char mode, u_char cmd)
+{
+ struct FIRM_ID *firm_id =
+ (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+ struct ZFW_CTRL *zfw_ctrl;
+ struct CH_CTRL *ch_ctrl;
+
+ if (firm_id->signature != ZFIRM_ID){
+ return (-1);
}
- return irq_lines;
-} /* grab_all_interrupts */
+ zfw_ctrl =
+ (struct ZFW_CTRL *)(cinfo->base_addr + firm_id->zfwctrl_addr);
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+
+ ch_ctrl[channel].op_mode = (long)mode;
+
+ return cyz_issue_cmd(cinfo, channel, cmd, 0L);
+
+} /* cyz_update_channel */
+
-/*
- * Release all interrupts grabbed by grab_all_interrupts
- */
static void
-free_all_interrupts(int irq_lines)
+cyz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- int i;
-
- for (i = 0; i < 16; i++) {
- if (irq_lines & (1 << i))
- free_irq(i,NULL);
- }
-} /* free_all_interrupts */
+} /* cyz_interrupt */
-/*
- * This routine returns a bitfield of "wild interrupts". Basically,
- * any unclaimed interrupts which is flapping around.
- */
-static int
-check_wild_interrupts(void)
+
+static void
+cyz_poll(unsigned long arg)
{
- int i, mask;
- int wild_interrupts = 0;
- int irq_lines;
- unsigned long timeout;
- unsigned long flags;
-
- /*Turn on interrupts (they may be off) */
- save_flags(flags); sti();
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ struct CH_CTRL *ch_ctrl;
+ struct BUF_CTRL *buf_ctrl;
+ struct cyclades_card *cinfo;
+ struct cyclades_port *info;
+ struct tty_struct *tty;
+ int card, port;
+ int char_count, small_count;
+ char data;
+ u_long channel;
+ u_char cmd;
+ u_long *param;
- irq_lines = grab_all_interrupts(0);
-
- /*
- * Delay for 0.1 seconds -- we use a busy loop since this may
- * occur during the bootup sequence
- */
- timeout = jiffies+10;
- while (timeout >= jiffies)
- ;
-
- cy_triggered = 0; /* Reset after letting things settle */
-
- timeout = jiffies+10;
- while (timeout >= jiffies)
- ;
-
- for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
- if ((cy_triggered & (1 << i)) &&
- (irq_lines & (1 << i))) {
- wild_interrupts |= mask;
- }
- }
- free_all_interrupts(irq_lines);
- restore_flags(flags);
- return wild_interrupts;
-} /* check_wild_interrupts */
+ cyz_timerlist.expires = jiffies + 100;
-/*
- * This routine is called by do_auto_irq(); it attempts to determine
- * which interrupt a serial port is configured to use. It is not
- * fool-proof, but it works a large part of the time.
- */
-static int
-get_auto_irq(unsigned char *address)
-{
- unsigned long timeout;
- unsigned char *base_addr;
- int index;
+ for (card = 0 ; card < NR_CARDS ; card++){
+ cinfo = &cy_card[card];
+ if (!IS_CYC_Z(*cinfo)) continue;
- index = 0; /* IRQ probing is only for ISA */
- base_addr = address;
- intr_base_addr = address;
-
- /*
- * Enable interrupts and see who answers
- */
- cy_irq_triggered = 0;
- cli();
- base_addr[CyCAR<<index] = 0;
- write_cy_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
- base_addr[CySRER<<index] |= CyTxMpty;
- probe_ready = 1;
- sti();
-
- timeout = jiffies+2;
- while (timeout >= jiffies) {
- if (cy_irq_triggered)
- break;
- }
- probe_ready = 0;
- return(cy_irq_triggered);
-} /* get_auto_irq */
+ firm_id = (struct FIRM_ID *)
+ (cinfo->base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
+ continue;
+ }
-/*
- * Calls get_auto_irq() multiple times, to make sure we don't get
- * faked out by random interrupts
- */
-static int
-do_auto_irq(unsigned char *address)
-{
- int irq_lines = 0;
- int irq_try_1 = 0, irq_try_2 = 0;
- int retries;
- unsigned long flags;
+ zfw_ctrl =
+ (struct ZFW_CTRL *)
+ (cinfo->base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+
+ while( cyz_fetch_msg( cinfo, &channel, &cmd, &param) == 1){
+ char_count = 0;
+ info = &cy_port[ channel + cinfo->first_line ];
+ if((tty = info->tty) == 0) continue;
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+ buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+ info->jiffies[0] = jiffies;
+
+ switch(cmd){
+ case C_CM_PR_ERROR:
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = TTY_PARITY;
+ *tty->flip.char_buf_ptr++ = 0;
+ char_count++;
+ break;
+ case C_CM_FR_ERROR:
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = TTY_FRAME;
+ *tty->flip.char_buf_ptr++ = 0;
+ char_count++;
+ break;
+ case C_CM_RXBRK:
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = TTY_BREAK;
+ *tty->flip.char_buf_ptr++ = 0;
+ char_count++;
+ break;
+ case C_CM_MDCD:
+ if (info->flags & ASYNC_CHECK_CD){
+ if( ch_ctrl[channel].rs_status & C_RS_DCD){
+ /* SP("Open Wakeup\n"); */
+ cy_sched_event(info,
+ Cy_EVENT_OPEN_WAKEUP);
+ }else if(!((info->flags
+ & ASYNC_CALLOUT_ACTIVE)
+ &&(info->flags
+ & ASYNC_CALLOUT_NOHUP))){
+ /* SP("Hangup\n"); */
+ cy_sched_event(info,
+ Cy_EVENT_HANGUP);
+ }
+ }
+ break;
+ case C_CM_MCTS:
+ if (info->flags & ASYNC_CTS_FLOW) {
+ if(info->tty->hw_stopped){
+ if( ch_ctrl[channel].rs_status & C_RS_DCD){
+ /* cy_start isn't used because...
+ HW flow is handled by the board */
+ /* SP("Write Wakeup\n"); */
+ cy_sched_event(info,
+ Cy_EVENT_WRITE_WAKEUP);
+ }
+ }else{
+ if(!(ch_ctrl[channel].rs_status & C_RS_CTS)){
+ /* cy_stop isn't used because
+ HW flow is handled by the board */
+ /* SP("Write stop\n"); */
+ }
+ }
+ }
+ break;
+ case C_CM_MRI:
+ break;
+ case C_CM_MDSR:
+ break;
+ case C_CM_FATAL:
+ /* should do something with this !!! */
+ break;
+ }
+ if(char_count){
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ }
+ }
- /* Turn on interrupts (they may be off) */
- save_flags(flags); sti();
+ for (port = 0; port < board_ctrl->n_channel; port++){
+ info = &cy_port[ port + cinfo->first_line ];
+ tty = info->tty;
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
+ buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
- probe_ready = 0;
+ if ((char_count = CHARS_IN_BUF(buf_ctrl))){
+ info->last_active = jiffies;
+ info->jiffies[1] = jiffies;
- cy_wild_int_mask = check_wild_interrupts();
+#ifdef CYCLOM_ENABLE_MONITORING
+ info->mon.int_count++;
+ info->mon.char_count += char_count;
+ if (char_count > info->mon.char_max)
+ info->mon.char_max = char_count;
+ info->mon.char_last = char_count;
+#endif
+ if( tty == 0){
+ /* flush received characters */
+ buf_ctrl->rx_get =
+ (buf_ctrl->rx_get + char_count)
+ % buf_ctrl->rx_bufsize;
+ /* SP("-"); */
+ info->rflush_count++;
+ }else{
+#ifdef BLOCKMOVE
+ /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
+ for performance, but because of buffer boundaries, there
+ may be several steps to the operation */
+ while(0 < (small_count
+ = cy_min( (buf_ctrl->rx_bufsize - buf_ctrl->rx_get),
+ cy_min( (TTY_FLIPBUF_SIZE - tty->flip.count),
+ char_count)))){
+ memcpy(tty->flip.char_buf_ptr,
+ (char *)(cinfo->base_addr
+ + buf_ctrl->rx_bufaddr
+ + buf_ctrl->rx_get),
+ small_count);
+ tty->flip.char_buf_ptr += small_count;
+ memset(tty->flip.flag_buf_ptr,
+ TTY_NORMAL,
+ small_count);
+ tty->flip.flag_buf_ptr += small_count;
+ buf_ctrl->rx_get =
+ (buf_ctrl->rx_get + small_count)
+ % buf_ctrl->rx_bufsize;
+ char_count -= small_count;
+ tty->flip.count += small_count;
+ }
+#else
+ while(char_count--){
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE){
+ break;
+ }
+ data = *(char *) (cinfo->base_addr +
+ buf_ctrl->rx_bufaddr +
+ buf_ctrl->rx_get);
+ buf_ctrl->rx_get =
+ (buf_ctrl->rx_get + 1)
+ % buf_ctrl->rx_bufsize;
+
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+ *tty->flip.char_buf_ptr++ = data;
+ }
+#endif
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ }
+ }
- irq_lines = grab_all_interrupts(cy_wild_int_mask);
-
- for (retries = 0; retries < 5; retries++) {
- if (!irq_try_1)
- irq_try_1 = get_auto_irq(address);
- if (!irq_try_2)
- irq_try_2 = get_auto_irq(address);
- if (irq_try_1 && irq_try_2) {
- if (irq_try_1 == irq_try_2)
- break;
- irq_try_1 = irq_try_2 = 0;
+ if ((char_count = SPACE_IN_BUF(buf_ctrl))){
+ if( tty == 0){
+ goto ztxdone;
+ }
+
+ if(info->x_char) { /* send special char */
+ data = info->x_char;
+
+ *(char *) (cinfo->base_addr +
+ buf_ctrl->tx_bufaddr +
+ buf_ctrl->tx_put) = data;
+ buf_ctrl->tx_put =
+ (buf_ctrl->tx_put + 1)
+ % buf_ctrl->tx_bufsize;
+ info->x_char = 0;
+ char_count--;
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
+ if (info->x_break){
+ printk("cyc cyz_poll shouldn't see x_break\n");
+ info->x_break = 0;
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
+#ifdef BLOCKMOVE
+ while(0 < (small_count
+ = cy_min( (buf_ctrl->tx_bufsize - buf_ctrl->tx_put),
+ cy_min ( (PAGE_SIZE - info->xmit_tail),
+ cy_min( info->xmit_cnt, char_count))))){
+ memcpy((char *)(cinfo->base_addr
+ + buf_ctrl->tx_bufaddr
+ + buf_ctrl->tx_put),
+ &info->xmit_buf[info->xmit_tail],
+ small_count);
+ buf_ctrl->tx_put =
+ (buf_ctrl->tx_put + small_count)
+ % buf_ctrl->tx_bufsize;
+ char_count -= small_count;
+ info->xmit_cnt -= small_count;
+ info->xmit_tail =
+ (info->xmit_tail + small_count) & (PAGE_SIZE - 1);
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
+#else
+ while (info->xmit_cnt && char_count){
+ data = info->xmit_buf[info->xmit_tail];
+ info->xmit_cnt--;
+ info->xmit_tail =
+ (info->xmit_tail + 1) & (PAGE_SIZE - 1);
+
+ *(char *) (cinfo->base_addr +
+ buf_ctrl->tx_bufaddr +
+ buf_ctrl->tx_put) = data;
+ buf_ctrl->tx_put =
+ (buf_ctrl->tx_put + 1)
+ % buf_ctrl->tx_bufsize;
+ char_count--;
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
+#endif
+ ztxdone:
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+ cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ }
}
}
- restore_flags(flags);
- free_all_interrupts(irq_lines);
- return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
-} /* do_auto_irq */
+
+ /* poll every 40 ms */
+ cyz_timerlist.expires = jiffies + 4;
+ }
+ add_timer(&cyz_timerlist);
+
+ return;
+} /* cyz_poll */
+
+
+/********** End of block of Cyclom-Z specific code *********/
+/***********************************************************/
/* This is called whenever a port becomes active;
@@ -1217,72 +1724,130 @@ startup(struct cyclades_port * info)
int card,chip,channel,index;
if (info->flags & ASYNC_INITIALIZED){
- return 0;
+ return 0;
}
if (!info->type){
- if (info->tty){
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
- return 0;
+ if (info->tty){
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ return 0;
}
if (!info->xmit_buf){
- info->xmit_buf = (unsigned char *) get_free_page (GFP_KERNEL);
- if (!info->xmit_buf){
- return -ENOMEM;
- }
+ info->xmit_buf = (unsigned char *) get_free_page (GFP_KERNEL);
+ if (!info->xmit_buf){
+ return -ENOMEM;
+ }
}
- config_setup(info);
+ set_line_char(info);
card = info->card;
channel = (info->line) - (cy_card[card].first_line);
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
(cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
#ifdef SERIAL_DEBUG_OPEN
- printk("startup card %d, chip %d, channel %d, base_addr %lx",
- card, chip, channel, (long)base_addr);/**/
+ printk("cyc startup card %d, chip %d, channel %d, base_addr %lx\n",
+ card, chip, channel, (long)base_addr);/**/
#endif
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyRTPR<<index] = (info->default_timeout
- ? info->default_timeout
- : 0x02); /* 10ms rx timeout */
+ base_addr[CyRTPR<<index] = (info->default_timeout
+ ? info->default_timeout
+ : 0x02); /* 10ms rx timeout */
- write_cy_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index);
+ cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index);
- base_addr[CyCAR<<index] = (u_char)channel; /* !!! Is this needed? */
- base_addr[CyMSVR1<<index] = CyRTS;
- base_addr[CyMSVR2<<index] = CyDTR;
+ base_addr[CyCAR<<index] =
+ (u_char)channel; /* !!! Is this needed? */
+ base_addr[CyMSVR1<<index] = CyRTS;
+ base_addr[CyMSVR2<<index] = CyDTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: raising DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ printk("cyc:startup raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
#endif
- base_addr[CySRER<<index] |= CyRxData;
- info->flags |= ASYNC_INITIALIZED;
+ base_addr[CySRER<<index] |= CyRxData;
+ info->flags |= ASYNC_INITIALIZED;
+ if (info->tty){
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ restore_flags(flags);
+ } else {
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ struct CH_CTRL *ch_ctrl;
+ int retval;
+
+ base_addr = (unsigned char*) (cy_card[card].base_addr);
+
+ firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
+ return -ENODEV;
+ }
+
+ zfw_ctrl =
+ (struct ZFW_CTRL *)
+ (cy_card[card].base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc startup Z card %d, channel %d, base_addr %lx\n",
+ card, channel, (long)base_addr);/**/
+#endif
+
+ ch_ctrl[channel].op_mode = C_CH_ENABLE;
+ ch_ctrl[channel].intr_enable = C_IN_MDCD|C_IN_MCTS;
+ retval = cyz_issue_cmd( &cy_card[card],
+ channel, C_CM_IOCTL, 0L); /* was C_CM_RESET */
+ if (retval != 0){
+ printk("cyc:startup(1) retval was %x\n", retval);
+ }
+
+ /* set timeout !!! */
+ /* set RTS and DTR !!! */
+ ch_ctrl[channel].rs_control |=
+ C_RS_RTS | C_RS_DTR ;
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ channel, C_CM_IOCTLM, 0L);
+ if (retval != 0){
+ printk("cyc:startup(2) retval was %x\n", retval);
+ }
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:startup raising Z DTR\n");
+#endif
+
+ /* enable send, recv, modem !!! */
+
+ info->flags |= ASYNC_INITIALIZED;
if (info->tty){
clear_bit(TTY_IO_ERROR, &info->tty->flags);
}
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- restore_flags(flags);
+ }
#ifdef SERIAL_DEBUG_OPEN
- printk(" done\n");
+ printk(" cyc startup done\n");
#endif
- return 0;
+ return 0;
} /* startup */
-void
+
+static void
start_xmit( struct cyclades_port *info )
{
unsigned long flags;
@@ -1291,18 +1856,24 @@ start_xmit( struct cyclades_port *info )
card = info->card;
channel = (info->line) - (cy_card[card].first_line);
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = channel;
- base_addr[CySRER<<index] |= CyTxMpty;
- restore_flags(flags);
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = channel;
+ base_addr[CySRER<<index] |= CyTxMpty;
+ restore_flags(flags);
+ } else {
+ /* Don't have to do anything at this time */
+ }
} /* start_xmit */
+
/*
* This routine shuts down a serial port; interrupts are disabled,
* and DTR is dropped if the hangup on close termio flag is on.
@@ -1315,326 +1886,535 @@ shutdown(struct cyclades_port * info)
int card,chip,channel,index;
if (!(info->flags & ASYNC_INITIALIZED)){
- return;
+ return;
}
card = info->card;
channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
#ifdef SERIAL_DEBUG_OPEN
- printk("shutdown card %d, chip %d, channel %d, base_addr %lx\n",
- card, chip, channel, (long)base_addr);
+ printk("cyc shutdown Y card %d, chip %d, channel %d, base_addr %lx\n",
+ card, chip, channel, (long)base_addr);
#endif
- /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE
- SENT BEFORE DROPPING THE LINE !!! (Perhaps
- set some flag that is read when XMTY happens.)
- Other choices are to delay some fixed interval
- or schedule some later processing.
- */
- save_flags(flags); cli();
- if (info->xmit_buf){
- unsigned char * temp;
- temp = info->xmit_buf;
- info->xmit_buf = 0;
- free_page((unsigned long) temp);
- }
+ /* REALLY SHOULD WAIT FOR LAST CHARACTER TO BE
+ SENT BEFORE DROPPING THE LINE !!! (Perhaps
+ set some flag that is read when XMTY happens.)
+ Other choices are to delay some fixed interval
+ or schedule some later processing.
+ */
+ save_flags(flags); cli();
+ if (info->xmit_buf){
+ unsigned char * temp;
+ temp = info->xmit_buf;
+ info->xmit_buf = 0;
+ free_page((unsigned long) temp);
+ }
- base_addr[CyCAR<<index] = (u_char)channel;
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
- base_addr[CyMSVR1<<index] = ~CyRTS;
- base_addr[CyMSVR2<<index] = ~CyDTR;
+ base_addr[CyCAR<<index] = (u_char)channel;
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ base_addr[CyMSVR1<<index] = ~CyRTS;
+ base_addr[CyMSVR2<<index] = ~CyDTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: dropping DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ printk("cyc shutdown dropping DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
#endif
- }
- write_cy_cmd(base_addr,CyCHAN_CTL|CyDIS_RCVR,index);
- /* it may be appropriate to clear _XMIT at
- some later date (after testing)!!! */
+ }
+ cyy_issue_cmd(base_addr,CyCHAN_CTL|CyDIS_RCVR,index);
+ /* it may be appropriate to clear _XMIT at
+ some later date (after testing)!!! */
- if (info->tty){
- set_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (info->tty){
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ info->flags &= ~ASYNC_INITIALIZED;
+ restore_flags(flags);
+ } else {
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ struct CH_CTRL *ch_ctrl;
+ int retval;
+
+ base_addr = (unsigned char*) (cy_card[card].base_addr);
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n",
+ card, channel, (long)base_addr);
+#endif
+
+ firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
+ return;
}
- info->flags &= ~ASYNC_INITIALIZED;
- restore_flags(flags);
+
+ zfw_ctrl =
+ (struct ZFW_CTRL *)
+ (cy_card[card].base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+
+ save_flags(flags); cli();
+ if (info->xmit_buf){
+ unsigned char * temp;
+ temp = info->xmit_buf;
+ info->xmit_buf = 0;
+ free_page((unsigned long) temp);
+ }
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ ch_ctrl[channel].rs_control &=
+ ~(C_RS_RTS | C_RS_DTR );
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ channel, C_CM_IOCTLM, 0L);
+ if (retval != 0){
+ printk("cyc:shutdown retval was %x\n",
+ retval);
+ }
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:shutdown dropping Z DTR\n");
+#endif
+ }
+
+ if (info->tty){
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ info->flags &= ~ASYNC_INITIALIZED;
+
+ restore_flags(flags);
+ }
#ifdef SERIAL_DEBUG_OPEN
- printk(" done\n");
+ printk(" cyc shutdown done\n");
#endif
return;
} /* shutdown */
+
/*
- * This routine finds or computes the various line characteristics.
+ * ------------------------------------------------------------
+ * cy_open() and friends
+ * ------------------------------------------------------------
*/
-static void
-config_setup(struct cyclades_port * info)
+
+static int
+block_til_ready(struct tty_struct *tty, struct file * filp,
+ struct cyclades_port *info)
{
+ struct wait_queue wait = { current, NULL };
+ struct cyclades_card *cinfo;
unsigned long flags;
- unsigned char *base_addr;
- int card,chip,channel,index;
- unsigned cflag;
- int i;
-
- if (!info->tty || !info->tty->termios){
- return;
- }
- if (info->line == -1){
- return;
- }
- cflag = info->tty->termios->c_cflag;
+ int chip, channel,index;
+ int retval;
+ char *base_addr;
- /* baud rate */
- i = cflag & CBAUD;
-#ifdef CBAUDEX
-/* Starting with kernel 1.1.65, there is direct support for
- higher baud rates. The following code supports those
- changes. The conditional aspect allows this driver to be
- used for earlier as well as later kernel versions. (The
- mapping is slightly different from serial.c because there
- is still the possibility of supporting 75 kbit/sec with
- the Cyclades board.)
- */
- if (i & CBAUDEX) {
- if (i == B57600)
- i = 16;
- else if(i == B115200)
- i = 18;
-#ifdef B78600
- else if(i == B78600)
- i = 17;
-#endif
- else
- info->tty->termios->c_cflag &= ~CBAUDEX;
- }
-#endif
- if (i == 15) {
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- i += 1;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- i += 3;
- }
- info->tbpr = baud_bpr[i]; /* Tx BPR */
- info->tco = baud_co[i]; /* Tx CO */
- info->rbpr = baud_bpr[i]; /* Rx BPR */
- info->rco = baud_co[i]; /* Rx CO */
- if (baud_table[i] == 134) {
- info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
- /* get it right for 134.5 baud */
- } else if (baud_table[i]) {
- info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
- /* this needs to be propagated into the card info */
- } else {
- info->timeout = 0;
- }
- /* By tradition (is it a standard?) a baud rate of zero
- implies the line should be/has been closed. A bit
- later in this routine such a test is performed. */
-
- /* byte size and parity */
- info->cor5 = 0;
- info->cor4 = 0;
- info->cor3 = (info->default_threshold
- ? info->default_threshold
- : baud_cor3[i]); /* receive threshold */
- info->cor2 = CyETC;
- switch(cflag & CSIZE){
- case CS5:
- info->cor1 = Cy_5_BITS;
- break;
- case CS6:
- info->cor1 = Cy_6_BITS;
- break;
- case CS7:
- info->cor1 = Cy_7_BITS;
- break;
- case CS8:
- info->cor1 = Cy_8_BITS;
- break;
- }
- if(cflag & CSTOPB){
- info->cor1 |= Cy_2_STOP;
- }
- if (cflag & PARENB){
- if (cflag & PARODD){
- info->cor1 |= CyPARITY_O;
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (info->flags & ASYNC_CLOSING) {
+ interruptible_sleep_on(&info->close_wait);
+ if (info->flags & ASYNC_HUP_NOTIFY){
+ return -EAGAIN;
}else{
- info->cor1 |= CyPARITY_E;
+ return -ERESTARTSYS;
}
- }else{
- info->cor1 |= CyPARITY_NONE;
}
-
- /* CTS flow control flag */
- if (cflag & CRTSCTS){
- info->flags |= ASYNC_CTS_FLOW;
- info->cor2 |= CyCtsAE;
- }else{
- info->flags &= ~ASYNC_CTS_FLOW;
- info->cor2 &= ~CyCtsAE;
- }
- if (cflag & CLOCAL)
- info->flags &= ~ASYNC_CHECK_CD;
- else
- info->flags |= ASYNC_CHECK_CD;
-
- /***********************************************
- The hardware option, CyRtsAO, presents RTS when
- the chip has characters to send. Since most modems
- use RTS as reverse (inbound) flow control, this
- option is not used. If inbound flow control is
- necessary, DTR can be programmed to provide the
- appropriate signals for use with a non-standard
- cable. Contact Marcio Saito for details.
- ***********************************************/
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
-
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
-
- /* tx and rx baud rate */
-
- base_addr[CyTCOR<<index] = info->tco;
- base_addr[CyTBPR<<index] = info->tbpr;
- base_addr[CyRCOR<<index] = info->rco;
- base_addr[CyRBPR<<index] = info->rbpr;
-
- /* set line characteristics according configuration */
-
- base_addr[CySCHR1<<index] = START_CHAR(info->tty);
- base_addr[CySCHR2<<index] = STOP_CHAR(info->tty);
- base_addr[CyCOR1<<index] = info->cor1;
- base_addr[CyCOR2<<index] = info->cor2;
- base_addr[CyCOR3<<index] = info->cor3;
- base_addr[CyCOR4<<index] = info->cor4;
- base_addr[CyCOR5<<index] = info->cor5;
-
- write_cy_cmd(base_addr,CyCOR_CHANGE|CyCOR1ch|CyCOR2ch|CyCOR3ch,index);
-
- base_addr[CyCAR<<index] = (u_char)channel; /* !!! Is this needed? */
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+ if (info->flags & ASYNC_NORMAL_ACTIVE){
+ return -EBUSY;
+ }
+ if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_SESSION_LOCKOUT) &&
+ (info->session != current->session)){
+ return -EBUSY;
+ }
+ if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_PGRP_LOCKOUT) &&
+ (info->pgrp != current->pgrp)){
+ return -EBUSY;
+ }
+ info->flags |= ASYNC_CALLOUT_ACTIVE;
+ return 0;
+ }
- base_addr[CyRTPR<<index] = (info->default_timeout
- ? info->default_timeout
- : 0x02); /* 10ms rx timeout */
+ /*
+ * If non-blocking mode is set, then make the check up front
+ * and then exit.
+ */
+ if (filp->f_flags & O_NONBLOCK) {
+ if (info->flags & ASYNC_CALLOUT_ACTIVE){
+ return -EBUSY;
+ }
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
- if (C_CLOCAL(info->tty)) {
- base_addr[CySRER<<index] |= CyMdmCh; /* without modem intr */
- /* act on 1->0 modem transitions */
- base_addr[CyMCOR1<<index] = CyCTS;
- /* act on 0->1 modem transitions */
- base_addr[CyMCOR2<<index] = CyCTS;
- } else {
- base_addr[CySRER<<index] |= CyMdmCh; /* with modem intr */
- /* act on 1->0 modem transitions */
- base_addr[CyMCOR1<<index] = CyDSR|CyCTS|CyRI|CyDCD;
- /* act on 0->1 modem transitions */
- base_addr[CyMCOR2<<index] = CyDSR|CyCTS|CyRI|CyDCD;
- }
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, info->count is dropped by one, so that
+ * cy_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
+ info->line, info->count);/**/
+#endif
+ info->count--;
+#ifdef SERIAL_DEBUG_COUNT
+ printk("cyc block_til_ready: (%d): decrementing count to %d\n",
+ current->pid, info->count);
+#endif
+ info->blocked_open++;
- if(i == 0){ /* baud rate is zero, turn off line */
- base_addr[CyMSVR2<<index] = ~CyDTR;
+ cinfo = &cy_card[info->card];
+ channel = info->line - cinfo->first_line;
+ if (!IS_CYC_Z(*cinfo)) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cinfo->bus_index;
+ base_addr = (char *)(cinfo->base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ while (1) {
+ save_flags(flags); cli();
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){
+ base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyMSVR1<<index] = CyRTS;
+ base_addr[CyMSVR2<<index] = CyDTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: dropping DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ printk("cyc:block_til_ready raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
#endif
- }else{
- base_addr[CyMSVR2<<index] = CyDTR;
-#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: raising DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ }
+ restore_flags(flags);
+ current->state = TASK_INTERRUPTIBLE;
+ if (tty_hung_up_p(filp)
+ || !(info->flags & ASYNC_INITIALIZED) ){
+ if (info->flags & ASYNC_HUP_NOTIFY) {
+ retval = -EAGAIN;
+ }else{
+ retval = -ERESTARTSYS;
+ }
+ break;
+ }
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
+ && !(info->flags & ASYNC_CLOSING)
+ && (C_CLOCAL(tty)
+ || (base_addr[CyMSVR1<<index] & CyDCD))) {
+ restore_flags(flags);
+ break;
+ }
+ restore_flags(flags);
+ if (current->signal & ~current->blocked) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
+ info->line, info->count);/**/
#endif
+ schedule();
}
-
- if (info->tty){
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ } else {
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ struct CH_CTRL *ch_ctrl;
+ int retval;
+
+ base_addr = (char *)(cinfo->base_addr);
+ firm_id = (struct FIRM_ID *)
+ (base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
+ return -EINVAL;
}
- restore_flags(flags);
+ zfw_ctrl =
+ (struct ZFW_CTRL *)
+ (base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+
+ while (1) {
+ ch_ctrl[channel].rs_control |=
+ C_RS_RTS | C_RS_DTR ;
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ channel, C_CM_IOCTLM, 0L);
+ if (retval != 0){
+ printk("cyc:block_til_ready retval was %x\n", retval);
+ }
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:block_til_ready raising Z DTR\n");
+#endif
-} /* config_setup */
+ current->state = TASK_INTERRUPTIBLE;
+ if (tty_hung_up_p(filp)
+ || !(info->flags & ASYNC_INITIALIZED) ){
+ if (info->flags & ASYNC_HUP_NOTIFY) {
+ retval = -EAGAIN;
+ }else{
+ retval = -ERESTARTSYS;
+ }
+ break;
+ }
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
+ && !(info->flags & ASYNC_CLOSING)
+ && (C_CLOCAL(tty)
+ || (ch_ctrl[channel].rs_status & C_RS_DCD))) {
+ break;
+ }
+ if (current->signal & ~current->blocked) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
+ info->line, info->count);/**/
+#endif
+ schedule();
+ }
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+ if (!tty_hung_up_p(filp)){
+ info->count++;
+#ifdef SERIAL_DEBUG_COUNT
+ printk("cyc:block_til_ready (%d): incrementing count to %d\n",
+ current->pid, info->count);
+#endif
+ }
+ info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n",
+ info->line, info->count);/**/
+#endif
+ if (retval)
+ return retval;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+} /* block_til_ready */
-static void
-cy_put_char(struct tty_struct *tty, unsigned char ch)
+/*
+ * This routine is called whenever a serial port is opened. It
+ * performs the serial-specific initialization for the tty structure.
+ */
+int
+cy_open(struct tty_struct *tty, struct file * filp)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
+ struct cyclades_port *info;
+ int retval, line;
-#ifdef SERIAL_DEBUG_IO
- printk("cy_put_char ttyC%d\n", info->line);
+ line = MINOR(tty->device) - tty->driver.minor_start;
+ if ((line < 0) || (NR_PORTS <= line)){
+ return -ENODEV;
+ }
+ info = &cy_port[line];
+ if (info->line < 0){
+ return -ENODEV;
+ }
+
+ /* If the card's firmware hasn't been loaded,
+ treat it as absent from the system. This
+ will make the user pay attention.
+ */
+ if (IS_CYC_Z(cy_card[info->card])) {
+ struct FIRM_ID *firm_id =
+ (struct FIRM_ID *)
+ (cy_card[info->card].base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
+ printk("Cyclom-Z firmware not yet loaded\n");
+ return -ENODEV;
+ }
+ }
+#ifdef SERIAL_DEBUG_OTHER
+ printk("cyc:cy_open ttyC%d\n", info->line); /* */
+#endif
+ if (serial_paranoia_check(info, tty->device, "cy_open")){
+ return -ENODEV;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc:cy_open ttyC%d, count = %d\n",
+ info->line, info->count);/**/
+#endif
+ info->count++;
+#ifdef SERIAL_DEBUG_COUNT
+ printk("cyc:cy_open (%d): incrementing count to %d\n",
+ current->pid, info->count);
#endif
+ tty->driver_data = info;
+ info->tty = tty;
- if (serial_paranoia_check(info, tty->device, "cy_put_char"))
- return;
+ /* Some drivers have (incorrect/incomplete) code to test
+ against a race condition. Should add good code here!!! */
+ if (!tmp_buf) {
+ tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+ if (!tmp_buf){
+ return -ENOMEM;
+ }
+ }
- if (!tty || !info->xmit_buf)
- return;
+ if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->normal_termios;
+ else
+ *tty->termios = info->callout_termios;
+ }
+ /*
+ * Start up serial port
+ */
+ retval = startup(info);
+ if (retval){
+ return retval;
+ }
- save_flags(flags); cli();
- if (info->xmit_cnt >= PAGE_SIZE - 1) {
- restore_flags(flags);
- return;
- }
+ MOD_INC_USE_COUNT;
- info->xmit_buf[info->xmit_head++] = ch;
- info->xmit_head &= PAGE_SIZE - 1;
- info->xmit_cnt++;
- restore_flags(flags);
-} /* cy_put_char */
+ retval = block_til_ready(tty, filp, info);
+ if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc:cy_open returning after block_til_ready with %d\n",
+ retval);
+#endif
+ return retval;
+ }
+
+ info->session = current->session;
+ info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk(" cyc:cy_open done\n");/**/
+#endif
+ return 0;
+} /* cy_open */
+/*
+ * This routine is called when a particular tty device is closed.
+ */
static void
-cy_flush_chars(struct tty_struct *tty)
+cy_close(struct tty_struct * tty, struct file * filp)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
- unsigned char *base_addr;
- int card,chip,channel,index;
-
-#ifdef SERIAL_DEBUG_IO
- printk("cy_flush_chars ttyC%d\n", info->line); /* */
+
+#ifdef SERIAL_DEBUG_OTHER
+ printk("cyc:cy_close ttyC%d\n", info->line);
#endif
- if (serial_paranoia_check(info, tty->device, "cy_flush_chars"))
- return;
+ if (!info
+ || serial_paranoia_check(info, tty->device, "cy_close")){
+ return;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count);
+#endif
- if (info->xmit_cnt <= 0 || tty->stopped
- || tty->hw_stopped || !info->xmit_buf)
- return;
+ save_flags(flags); cli();
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ /* If the TTY is being hung up, nothing to do */
+ if (tty_hung_up_p(filp)) {
+ restore_flags(flags);
+ return;
+ }
+
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("cyc:cy_close: bad serial port count; tty->count is 1, "
+ "info->count is %d\n", info->count);
+ info->count = 1;
+ }
+#ifdef SERIAL_DEBUG_COUNT
+ printk("cyc:cy_close at (%d): decrementing count to %d\n",
+ current->pid, info->count - 1);
+#endif
+ if (--info->count < 0) {
+#ifdef SERIAL_DEBUG_COUNT
+ printk("cyc:cyc_close setting count to 0\n");
+#endif
+ info->count = 0;
+ }
+ if (info->count) {
+ MOD_DEC_USE_COUNT;
+ restore_flags(flags);
+ return;
+ }
+ info->flags |= ASYNC_CLOSING;
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ info->normal_termios = *tty->termios;
+ if (info->flags & ASYNC_CALLOUT_ACTIVE)
+ info->callout_termios = *tty->termios;
+ if (info->flags & ASYNC_INITIALIZED)
+ tty_wait_until_sent(tty, 5*HZ); /* 5 seconds timeout */
+ shutdown(info);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ info->event = 0;
+ info->tty = 0;
+ if (info->blocked_open) {
+ if (info->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + info->close_delay;
+ schedule();
+ }
+ wake_up_interruptible(&info->open_wait);
+ }
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+ ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = channel;
- base_addr[CySRER<<index] |= CyTxMpty;
+#ifdef SERIAL_DEBUG_OTHER
+ printk(" cyc:cy_close done\n");
+#endif
+
+ MOD_DEC_USE_COUNT;
restore_flags(flags);
-} /* cy_flush_chars */
+ return;
+} /* cy_close */
/* This routine gets called when tty_write has put something into
- the write_queue. If the port is not already transmitting stuff,
- start it off by enabling interrupts. The interrupt service
- routine will then ensure that the characters are sent. If the
- port is already active, there is no need to kick it.
+ * the write_queue. The characters may come from user space or
+ * kernel space.
+ *
+ * This routine will return the number of characters actually
+ * accepted for writing.
+ *
+ * If the port is not already transmitting stuff, start it off by
+ * enabling interrupts. The interrupt service routine will then
+ * ensure that the characters are sent.
+ * If the port is already active, there is no need to kick it.
+ *
*/
static int
cy_write(struct tty_struct * tty, int from_user,
@@ -1645,42 +2425,49 @@ cy_write(struct tty_struct * tty, int from_user,
int c, total = 0;
#ifdef SERIAL_DEBUG_IO
- printk("cy_write ttyC%d\n", info->line); /* */
+ printk("cyc:cy_write ttyC%d\n", info->line); /* */
#endif
if (serial_paranoia_check(info, tty->device, "cy_write")){
- return 0;
+ return 0;
}
-
+
if (!tty || !info->xmit_buf || !tmp_buf){
return 0;
}
+ if (from_user)
+ down(&tmp_buf_sem);
while (1) {
- save_flags(flags); cli();
- c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0){
- restore_flags(flags);
- break;
- }
+ save_flags(flags); cli();
+ c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0){
+ restore_flags(flags);
+ break;
+ }
- if (from_user) {
- down(&tmp_buf_sem);
- copy_from_user(tmp_buf, buf, c);
- c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- up(&tmp_buf_sem);
- } else
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- restore_flags(flags);
- buf += c;
- count -= c;
- total += c;
+ if (from_user) {
+ memcpy_fromfs(tmp_buf, buf, c);
+ c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ } else
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ total += c;
+#if 0
+ SP("CW");
+ CP16(c);
+ SP(" ");
+#endif
}
+ if (from_user)
+ up(&tmp_buf_sem);
if (info->xmit_cnt
@@ -1692,21 +2479,110 @@ cy_write(struct tty_struct * tty, int from_user,
} /* cy_write */
+/*
+ * This routine is called by the kernel to write a single
+ * character to the tty device. If the kernel uses this routine,
+ * it must call the flush_chars() routine (if defined) when it is
+ * done stuffing characters into the driver. If there is no room
+ * in the queue, the character is ignored.
+ */
+static void
+cy_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+
+#ifdef SERIAL_DEBUG_IO
+ printk("cyc:cy_put_char ttyC%d\n", info->line);
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "cy_put_char"))
+ return;
+
+ if (!tty || !info->xmit_buf)
+ return;
+
+ save_flags(flags); cli();
+ if (info->xmit_cnt >= PAGE_SIZE - 1) {
+ restore_flags(flags);
+ return;
+ }
+
+ info->xmit_buf[info->xmit_head++] = ch;
+ info->xmit_head &= PAGE_SIZE - 1;
+ info->xmit_cnt++;
+ restore_flags(flags);
+#if 0
+ SP("+");
+#endif
+} /* cy_put_char */
+
+
+/*
+ * This routine is called by the kernel after it has written a
+ * series of characters to the tty device using put_char().
+ */
+static void
+cy_flush_chars(struct tty_struct *tty)
+{
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+ unsigned char *base_addr;
+ int card,chip,channel,index;
+
+#ifdef SERIAL_DEBUG_IO
+ printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "cy_flush_chars"))
+ return;
+
+ if (info->xmit_cnt <= 0 || tty->stopped
+ || tty->hw_stopped || !info->xmit_buf)
+ return;
+
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = channel;
+ base_addr[CySRER<<index] |= CyTxMpty;
+ restore_flags(flags);
+ } else {
+ /* Since polling is already in place,
+ nothing further need be done. */
+ }
+} /* cy_flush_chars */
+
+
+/*
+ * This routine returns the numbers of characters the tty driver
+ * will accept for queuing to be written. This number is subject
+ * to change as output buffers get emptied, or if the output flow
+ * control is activated.
+ */
static int
cy_write_room(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int ret;
-
+ int ret;
+
#ifdef SERIAL_DEBUG_IO
- printk("cy_write_room ttyC%d\n", info->line); /* */
+ printk("cyc:cy_write_room ttyC%d\n", info->line); /* */
#endif
if (serial_paranoia_check(info, tty->device, "cy_write_room"))
- return 0;
+ return 0;
ret = PAGE_SIZE - info->xmit_cnt - 1;
if (ret < 0)
- ret = 0;
+ ret = 0;
return ret;
} /* cy_write_room */
@@ -1715,126 +2591,351 @@ static int
cy_chars_in_buffer(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-
+
#ifdef SERIAL_DEBUG_IO
- printk("cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */
+ printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
+ info->line, info->xmit_cnt); /* */
#endif
if (serial_paranoia_check(info, tty->device, "cy_chars_in_buffer"))
- return 0;
+ return 0;
return info->xmit_cnt;
} /* cy_chars_in_buffer */
-static void
-cy_flush_buffer(struct tty_struct *tty)
-{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
-
-#ifdef SERIAL_DEBUG_IO
- printk("cy_flush_buffer ttyC%d\n", info->line); /* */
-#endif
-
- if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
- return;
- save_flags(flags); cli();
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- 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);
-} /* cy_flush_buffer */
+/*
+ * ------------------------------------------------------------
+ * cy_ioctl() and friends
+ * ------------------------------------------------------------
+ */
-/* This routine is called by the upper-layer tty layer to signal
- that incoming characters should be throttled or that the
- throttle should be released.
+/*
+ * This routine finds or computes the various line characteristics.
+ * It used to be called config_setup
*/
static void
-cy_throttle(struct tty_struct * tty)
+set_line_char(struct cyclades_port * info)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
unsigned char *base_addr;
int card,chip,channel,index;
+ unsigned cflag;
+ int i;
-#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("throttle %s: %d....\n", _tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
- printk("cy_throttle ttyC%d\n", info->line);
-#endif
-
- if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
- return;
+ if (!info->tty || !info->tty->termios){
+ return;
}
-
- if (I_IXOFF(tty)) {
- info->x_char = STOP_CHAR(tty);
- /* Should use the "Send Special Character" feature!!! */
+ if (info->line == -1){
+ return;
}
+ cflag = info->tty->termios->c_cflag;
card = info->card;
- channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ channel = (info->line) - (cy_card[card].first_line);
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR1<<index] = ~CyRTS;
- restore_flags(flags);
+ if (!IS_CYC_Z(cy_card[card])) {
+ /* baud rate */
+ i = cflag & CBAUD;
+
+ if (i & CBAUDEX) {
+ if (i == B57600)
+ i = 16;
+ else if(i == B115200)
+ i = 18;
+#ifdef B76800
+ else if(i == B76800)
+ i = 17;
+#endif
+ else
+ info->tty->termios->c_cflag &= ~CBAUDEX;
+ }
- return;
-} /* cy_throttle */
+ if (i == 15) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ i += 1;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ i += 3;
+ }
+ info->tbpr = baud_bpr[i]; /* Tx BPR */
+ info->tco = baud_co[i]; /* Tx CO */
+ info->rbpr = baud_bpr[i]; /* Rx BPR */
+ info->rco = baud_co[i]; /* Rx CO */
+ if (baud_table[i] == 134) {
+ info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
+ /* get it right for 134.5 baud */
+ } else if (baud_table[i]) {
+ info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
+ /* this needs to be propagated into the card info */
+ } else {
+ info->timeout = 0;
+ }
+ /* By tradition (is it a standard?) a baud rate of zero
+ implies the line should be/has been closed. A bit
+ later in this routine such a test is performed. */
+
+ /* byte size and parity */
+ info->cor5 = 0;
+ info->cor4 = 0;
+ info->cor3 = (info->default_threshold
+ ? info->default_threshold
+ : baud_cor3[i]); /* receive threshold */
+ info->cor2 = CyETC;
+ switch(cflag & CSIZE){
+ case CS5:
+ info->cor1 = Cy_5_BITS;
+ break;
+ case CS6:
+ info->cor1 = Cy_6_BITS;
+ break;
+ case CS7:
+ info->cor1 = Cy_7_BITS;
+ break;
+ case CS8:
+ info->cor1 = Cy_8_BITS;
+ break;
+ }
+ if(cflag & CSTOPB){
+ info->cor1 |= Cy_2_STOP;
+ }
+ if (cflag & PARENB){
+ if (cflag & PARODD){
+ info->cor1 |= CyPARITY_O;
+ }else{
+ info->cor1 |= CyPARITY_E;
+ }
+ }else{
+ info->cor1 |= CyPARITY_NONE;
+ }
+
+ /* CTS flow control flag */
+ if (cflag & CRTSCTS){
+ info->flags |= ASYNC_CTS_FLOW;
+ info->cor2 |= CyCtsAE;
+ }else{
+ info->flags &= ~ASYNC_CTS_FLOW;
+ info->cor2 &= ~CyCtsAE;
+ }
+ if (cflag & CLOCAL)
+ info->flags &= ~ASYNC_CHECK_CD;
+ else
+ info->flags |= ASYNC_CHECK_CD;
+
+ /***********************************************
+ The hardware option, CyRtsAO, presents RTS when
+ the chip has characters to send. Since most modems
+ use RTS as reverse (inbound) flow control, this
+ option is not used. If inbound flow control is
+ necessary, DTR can be programmed to provide the
+ appropriate signals for use with a non-standard
+ cable. Contact Marcio Saito for details.
+ ***********************************************/
+
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
-static void
-cy_unthrottle(struct tty_struct * tty)
-{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
- unsigned char *base_addr;
- int card,chip,channel,index;
+ /* tx and rx baud rate */
+
+ base_addr[CyTCOR<<index] = info->tco;
+ base_addr[CyTBPR<<index] = info->tbpr;
+ base_addr[CyRCOR<<index] = info->rco;
+ base_addr[CyRBPR<<index] = info->rbpr;
+
+ /* set line characteristics according configuration */
+
+ base_addr[CySCHR1<<index] = START_CHAR(info->tty);
+ base_addr[CySCHR2<<index] = STOP_CHAR(info->tty);
+ base_addr[CyCOR1<<index] = info->cor1;
+ base_addr[CyCOR2<<index] = info->cor2;
+ base_addr[CyCOR3<<index] = info->cor3;
+ base_addr[CyCOR4<<index] = info->cor4;
+ base_addr[CyCOR5<<index] = info->cor5;
+
+ cyy_issue_cmd(base_addr,
+ CyCOR_CHANGE|CyCOR1ch|CyCOR2ch|CyCOR3ch,index);
+
+ base_addr[CyCAR<<index] =
+ (u_char)channel; /* !!! Is this needed? */
+
+ base_addr[CyRTPR<<index] = (info->default_timeout
+ ? info->default_timeout
+ : 0x02); /* 10ms rx timeout */
+
+ if (C_CLOCAL(info->tty)) {
+ base_addr[CySRER<<index] |= CyMdmCh; /* without modem intr */
+ /* act on 1->0 modem transitions */
+ base_addr[CyMCOR1<<index] = CyCTS;
+ /* act on 0->1 modem transitions */
+ base_addr[CyMCOR2<<index] = CyCTS;
+ } else {
+ base_addr[CySRER<<index] |= CyMdmCh; /* with modem intr */
+ /* act on 1->0 modem transitions */
+ base_addr[CyMCOR1<<index] = CyDSR|CyCTS|CyRI|CyDCD;
+ /* act on 0->1 modem transitions */
+ base_addr[CyMCOR2<<index] = CyDSR|CyCTS|CyRI|CyDCD;
+ }
-#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("throttle %s: %d....\n", _tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
- printk("cy_unthrottle ttyC%d\n", info->line);
+ if(i == 0){ /* baud rate is zero, turn off line */
+ base_addr[CyMSVR2<<index] = ~CyDTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_line_char dropping DTR\n");
+ printk(" status: 0x%x,
+ 0x%x\n", base_addr[CyMSVR1<<index],
+ base_addr[CyMSVR2<<index]);
+#endif
+ }else{
+ base_addr[CyMSVR2<<index] = CyDTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_line_char raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index],
+ base_addr[CyMSVR2<<index]);
#endif
+ }
- if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+ if (info->tty){
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+
+ restore_flags(flags);
+ } else {
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ struct CH_CTRL *ch_ctrl;
+ struct BUF_CTRL *buf_ctrl;
+ int retval;
+
+ firm_id = (struct FIRM_ID *)
+ (cy_card[card].base_addr + ID_ADDRESS);
+ if (firm_id->signature != ZFIRM_ID){
return;
- }
+ }
- if (I_IXOFF(tty)) {
- info->x_char = START_CHAR(tty);
- /* Should use the "Send Special Character" feature!!! */
- }
+ zfw_ctrl =
+ (struct ZFW_CTRL *)
+ (cy_card[card].base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
+ buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ /* baud rate */
+ switch(i = cflag & CBAUD){
+ /*
+ case B0: ch_ctrl->comm_baud = 0; break;
+ */
+ case B50: ch_ctrl->comm_baud = 50; break;
+ case B75: ch_ctrl->comm_baud = 75; break;
+ case B110: ch_ctrl->comm_baud = 110; break;
+ case B134: ch_ctrl->comm_baud = 134; break;
+ case B150: ch_ctrl->comm_baud = 150; break;
+ case B200: ch_ctrl->comm_baud = 200; break;
+ case B300: ch_ctrl->comm_baud = 300; break;
+ case B600: ch_ctrl->comm_baud = 600; break;
+ case B1200: ch_ctrl->comm_baud = 1200; break;
+ case B1800: ch_ctrl->comm_baud = 1800; break;
+ case B2400: ch_ctrl->comm_baud = 2400; break;
+ case B4800: ch_ctrl->comm_baud = 4800; break;
+ case B9600: ch_ctrl->comm_baud = 9600; break;
+ case B19200: ch_ctrl->comm_baud = 19200; break;
+ case B38400:
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI){
+ ch_ctrl->comm_baud = 57600;
+ }else if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI){
+ ch_ctrl->comm_baud = 115200;
+ }else{
+ ch_ctrl->comm_baud = 38400;
+ }
+ break;
+ case B57600: ch_ctrl->comm_baud = 57600; break;
+#ifdef B76800
+ case B76800: ch_ctrl->comm_baud = 76800; break;
+#endif
+ case B115200: ch_ctrl->comm_baud = 115200; break;
+ case B230400: ch_ctrl->comm_baud = 230400; break;
+ case B460800: ch_ctrl->comm_baud = 460800; break;
+ }
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST){
+ ch_ctrl->comm_baud = info->baud;
+ }
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR1<<index] = CyRTS;
- restore_flags(flags);
+ /* byte size and parity */
+ switch(cflag & CSIZE){
+ case CS5: ch_ctrl->comm_data_l = C_DL_CS5; break;
+ case CS6: ch_ctrl->comm_data_l = C_DL_CS6; break;
+ case CS7: ch_ctrl->comm_data_l = C_DL_CS7; break;
+ case CS8: ch_ctrl->comm_data_l = C_DL_CS8; break;
+ }
+ if(cflag & CSTOPB){
+ ch_ctrl->comm_data_l |= C_DL_2STOP;
+ }else{
+ ch_ctrl->comm_data_l |= C_DL_1STOP;
+ }
+ if (cflag & PARENB){
+ if (cflag & PARODD){
+ ch_ctrl->comm_parity = C_PR_ODD;
+ }else{
+ ch_ctrl->comm_parity = C_PR_EVEN;
+ }
+ }else{
+ ch_ctrl->comm_parity = C_PR_NONE;
+ }
+
+ /* CTS flow control flag */
+ if (cflag & CRTSCTS){
+ info->flags |= ASYNC_CTS_FLOW;
+ ch_ctrl->hw_flow |= C_RS_CTS | C_RS_RTS;
+ }else{
+ info->flags &= ~ASYNC_CTS_FLOW;
+ ch_ctrl->hw_flow &= ~(C_RS_CTS | C_RS_RTS);
+ }
+
+ retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTL, 0L);
+ if (retval != 0){
+ printk("cyc:set_line_char retval at %d was %x\n",
+ __LINE__, retval);
+ }
+
+ /* CD sensitivity */
+ if (cflag & CLOCAL){
+ info->flags &= ~ASYNC_CHECK_CD;
+ }else{
+ info->flags |= ASYNC_CHECK_CD;
+ }
+
+ if(i == 0){ /* baud rate is zero, turn off line */
+ ch_ctrl->rs_control &= ~C_RS_DTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_line_char dropping Z DTR\n");
+#endif
+ }else{
+ ch_ctrl->rs_control |= C_RS_DTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_line_char raising Z DTR\n");
+#endif
+ }
+
+ retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTLM, 0L);
+ if (retval != 0){
+ printk("cyc:set_line_char retval at %d was %x\n",
+ __LINE__, retval);
+ }
+
+ if (info->tty){
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ }
+
+} /* set_line_char */
- return;
-} /* cy_unthrottle */
static int
get_serial_info(struct cyclades_port * info,
@@ -1851,14 +2952,15 @@ get_serial_info(struct cyclades_port * info,
tmp.port = info->card * 0x100 + info->line - cinfo->first_line;
tmp.irq = cinfo->irq;
tmp.flags = info->flags;
- tmp.baud_base = 0; /*!!!*/
tmp.close_delay = info->close_delay;
+ tmp.baud_base = info->baud;
tmp.custom_divisor = 0; /*!!!*/
tmp.hub6 = 0; /*!!!*/
- copy_to_user(retinfo,&tmp,sizeof(*retinfo));
+ memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
return 0;
} /* get_serial_info */
+
static int
set_serial_info(struct cyclades_port * info,
struct serial_struct * new_info)
@@ -1867,18 +2969,19 @@ set_serial_info(struct cyclades_port * info,
struct cyclades_port old_info;
if (!new_info)
- return -EFAULT;
- copy_from_user(&new_serial,new_info,sizeof(new_serial));
+ return -EFAULT;
+ memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));
old_info = *info;
if (!suser()) {
- if ((new_serial.close_delay != info->close_delay) ||
- ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
- (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
- return -EPERM;
- info->flags = ((info->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- goto check_and_exit;
+ if ((new_serial.close_delay != info->close_delay) ||
+ ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
+ (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
+ return -EPERM;
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
+ info->baud = new_serial.baud_base;
+ goto check_and_exit;
}
@@ -1888,19 +2991,21 @@ set_serial_info(struct cyclades_port * info,
*/
info->flags = ((info->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
+ (new_serial.flags & ASYNC_FLAGS));
+ info->baud = new_serial.baud_base;
info->close_delay = new_serial.close_delay;
check_and_exit:
if (info->flags & ASYNC_INITIALIZED){
- config_setup(info);
- return 0;
+ set_line_char(info);
+ return 0;
}else{
return startup(info);
}
} /* set_serial_info */
+
static int
get_modem_info(struct cyclades_port * info, unsigned int *value)
{
@@ -1908,259 +3013,423 @@ get_modem_info(struct cyclades_port * info, unsigned int *value)
unsigned char *base_addr;
unsigned long flags;
unsigned char status;
+ unsigned long lstatus;
unsigned int result;
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ struct CH_CTRL *ch_ctrl;
card = info->card;
channel = (info->line) - (cy_card[card].first_line);
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- status = base_addr[CyMSVR1<<index];
- status |= base_addr[CyMSVR2<<index];
- restore_flags(flags);
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ status = base_addr[CyMSVR1<<index];
+ status |= base_addr[CyMSVR2<<index];
+ restore_flags(flags);
+
+ result = ((status & CyRTS) ? TIOCM_RTS : 0)
+ | ((status & CyDTR) ? TIOCM_DTR : 0)
+ | ((status & CyDCD) ? TIOCM_CAR : 0)
+ | ((status & CyRI) ? TIOCM_RNG : 0)
+ | ((status & CyDSR) ? TIOCM_DSR : 0)
+ | ((status & CyCTS) ? TIOCM_CTS : 0);
+ } else {
+ base_addr = (unsigned char*) (cy_card[card].base_addr);
+
+ if (cy_card[card].num_chips != 1){
+ return -EINVAL;
+ }
- result = ((status & CyRTS) ? TIOCM_RTS : 0)
- | ((status & CyDTR) ? TIOCM_DTR : 0)
- | ((status & CyDCD) ? TIOCM_CAR : 0)
- | ((status & CyRI) ? TIOCM_RNG : 0)
- | ((status & CyDSR) ? TIOCM_DSR : 0)
- | ((status & CyCTS) ? TIOCM_CTS : 0);
- put_user(result,(unsigned int *) value);
+ firm_id = (struct FIRM_ID *)
+ (cy_card[card].base_addr + ID_ADDRESS);
+ if (firm_id->signature == ZFIRM_ID){
+ zfw_ctrl =
+ (struct ZFW_CTRL *)
+ (cy_card[card].base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+ lstatus = ch_ctrl[channel].rs_status;
+ result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0)
+ | ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0)
+ | ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0)
+ | ((lstatus & C_RS_RI) ? TIOCM_RNG : 0)
+ | ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0)
+ | ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
+ }else{
+ result = 0;
+ return -ENODEV;
+ }
+
+ }
+ put_fs_long(result,(unsigned long *) value);
return 0;
} /* get_modem_info */
+
static int
set_modem_info(struct cyclades_port * info, unsigned int cmd,
unsigned int *value)
{
- int card,chip,channel,index;
- unsigned char *base_addr;
- unsigned long flags;
- unsigned int arg;
- int error;
-
- error = get_user(arg, value);
- if (error)
- return error;
+ int card,chip,channel,index;
+ unsigned char *base_addr;
+ unsigned long flags;
+ unsigned int arg = get_fs_long((unsigned long *) value);
+ struct FIRM_ID *firm_id;
+ struct ZFW_CTRL *zfw_ctrl;
+ struct BOARD_CTRL *board_ctrl;
+ struct CH_CTRL *ch_ctrl;
+ int retval;
card = info->card;
channel = (info->line) - (cy_card[card].first_line);
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
-
- switch (cmd) {
- case TIOCMBIS:
- if (arg & TIOCM_RTS){
- save_flags(flags); cli();
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ switch (cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS){
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyMSVR1<<index] = CyRTS;
+ restore_flags(flags);
+ }
+ if (arg & TIOCM_DTR){
+ save_flags(flags); cli();
base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR1<<index] = CyRTS;
- restore_flags(flags);
- }
- if (arg & TIOCM_DTR){
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR2<<index] = CyDTR;
+ base_addr[CyMSVR2<<index] = CyDTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: raising DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ printk("cyc:set_modem_info raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
#endif
- restore_flags(flags);
- }
- break;
- case TIOCMBIC:
- if (arg & TIOCM_RTS){
- save_flags(flags); cli();
+ restore_flags(flags);
+ }
+ break;
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS){
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyMSVR1<<index] = ~CyRTS;
+ restore_flags(flags);
+ }
+ if (arg & TIOCM_DTR){
+ save_flags(flags); cli();
base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR1<<index] = ~CyRTS;
- restore_flags(flags);
- }
- if (arg & TIOCM_DTR){
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR2<<index] = ~CyDTR;
+ base_addr[CyMSVR2<<index] = ~CyDTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: dropping DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ printk("cyc:set_modem_info dropping DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
#endif
- restore_flags(flags);
- }
- break;
- case TIOCMSET:
- if (arg & TIOCM_RTS){
- save_flags(flags); cli();
+ restore_flags(flags);
+ }
+ break;
+ case TIOCMSET:
+ if (arg & TIOCM_RTS){
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyMSVR1<<index] = CyRTS;
+ restore_flags(flags);
+ }else{
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyMSVR1<<index] = ~CyRTS;
+ restore_flags(flags);
+ }
+ if (arg & TIOCM_DTR){
+ save_flags(flags); cli();
base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR1<<index] = CyRTS;
- restore_flags(flags);
- }else{
- save_flags(flags); cli();
+ base_addr[CyMSVR2<<index] = CyDTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_modem_info raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+#endif
+ restore_flags(flags);
+ }else{
+ save_flags(flags); cli();
base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR1<<index] = ~CyRTS;
- restore_flags(flags);
+ base_addr[CyMSVR2<<index] = ~CyDTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_modem_info dropping DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+#endif
+ restore_flags(flags);
+ }
+ break;
+ default:
+ return -EINVAL;
}
- if (arg & TIOCM_DTR){
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR2<<index] = CyDTR;
+ } else {
+ base_addr = (unsigned char*) (cy_card[card].base_addr);
+
+ firm_id = (struct FIRM_ID *)
+ (cy_card[card].base_addr + ID_ADDRESS);
+ if (firm_id->signature == ZFIRM_ID){
+ zfw_ctrl =
+ (struct ZFW_CTRL *)
+ (cy_card[card].base_addr + firm_id->zfwctrl_addr);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+
+ switch (cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS){
+ ch_ctrl[channel].rs_control |= C_RS_RTS;
+ }
+ if (arg & TIOCM_DTR){
+ ch_ctrl[channel].rs_control |= C_RS_DTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: raising DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ printk("cyc:set_modem_info raising Z DTR\n");
#endif
- restore_flags(flags);
- }else{
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR2<<index] = ~CyDTR;
+ }
+ break;
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS){
+ ch_ctrl[channel].rs_control &= ~C_RS_RTS;
+ }
+ if (arg & TIOCM_DTR){
+ ch_ctrl[channel].rs_control &= ~C_RS_DTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: dropping DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+ printk("cyc:set_modem_info clearing Z DTR\n");
#endif
- restore_flags(flags);
- }
- break;
- default:
+ }
+ break;
+ case TIOCMSET:
+ if (arg & TIOCM_RTS){
+ ch_ctrl[channel].rs_control |= C_RS_RTS;
+ }else{
+ ch_ctrl[channel].rs_control &= ~C_RS_RTS;
+ }
+ if (arg & TIOCM_DTR){
+ ch_ctrl[channel].rs_control |= C_RS_DTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_modem_info raising Z DTR\n");
+#endif
+ }else{
+ ch_ctrl[channel].rs_control &= ~C_RS_DTR;
+#ifdef SERIAL_DEBUG_DTR
+ printk("cyc:set_modem_info clearing Z DTR\n");
+#endif
+ }
+ break;
+ default:
return -EINVAL;
- }
+ }
+ }else{
+ return -ENODEV;
+ }
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ channel, C_CM_IOCTLM,0L);
+ if (retval != 0){
+ printk("cyc:set_modem_info retval at %d was %x\n",
+ __LINE__, retval);
+ }
+ }
return 0;
} /* set_modem_info */
+
static void
send_break( struct cyclades_port * info, int duration)
-{ /* Let the transmit ISR take care of this (since it
- requires stuffing characters into the output stream).
- */
- info->x_break = duration;
- if (!info->xmit_cnt ) {
- start_xmit(info);
+{
+
+ if (!IS_CYC_Z(cy_card[info->card])) {
+ /* Let the transmit ISR take care of this (since it
+ requires stuffing characters into the output stream).
+ */
+ info->x_break = duration;
+ if (!info->xmit_cnt ) {
+ start_xmit(info);
+ }
+ } else {
+ /* For the moment we ignore the duration parameter!!!
+ A better implementation will use C_CM_SET_BREAK
+ and C_CM_CLR_BREAK with the appropriate delay.
+ */
+#if 0
+this appears to wedge the output data stream
+int retval;
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ (info->line) - (cy_card[info->card].first_line),
+ C_CM_SENDBRK, 0L);
+ if (retval != 0){
+ printk("cyc:send_break retval at %d was %x\n",
+ __LINE__, retval);
+ }
+#endif
}
} /* send_break */
+
static int
get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon)
{
- copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor));
- info->mon.int_count = 0;
- info->mon.char_count = 0;
- info->mon.char_max = 0;
- info->mon.char_last = 0;
- return 0;
-}
+ memcpy_tofs(mon, &info->mon, sizeof(struct cyclades_monitor));
+ info->mon.int_count = 0;
+ info->mon.char_count = 0;
+ info->mon.char_max = 0;
+ info->mon.char_last = 0;
+ return 0;
+}/* get_mon_info */
+
static int
set_threshold(struct cyclades_port * info, unsigned long value)
{
- unsigned char *base_addr;
- int card,channel,chip,index;
+ unsigned char *base_addr;
+ int card,channel,chip,index;
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ info->cor3 &= ~CyREC_FIFO;
+ info->cor3 |= value & CyREC_FIFO;
+ base_addr[CyCOR3<<index] = info->cor3;
+ cyy_issue_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index);
+ } else {
+ // Nothing to do!
+ }
+ return 0;
+}/* set_threshold */
- info->cor3 &= ~CyREC_FIFO;
- info->cor3 |= value & CyREC_FIFO;
- base_addr[CyCOR3<<index] = info->cor3;
- write_cy_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index);
- return 0;
-}
static int
get_threshold(struct cyclades_port * info, unsigned long *value)
{
- unsigned char *base_addr;
- int card,channel,chip,index;
- unsigned long tmp;
+ unsigned char *base_addr;
+ int card,channel,chip,index;
+ unsigned long tmp;
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ tmp = base_addr[CyCOR3<<index] & CyREC_FIFO;
+ put_fs_long(tmp,value);
+ } else {
+ // Nothing to do!
+ }
+ return 0;
+}/* get_threshold */
- tmp = base_addr[CyCOR3<<index] & CyREC_FIFO;
- put_user(tmp,value);
- return 0;
-}
static int
set_default_threshold(struct cyclades_port * info, unsigned long value)
{
- info->default_threshold = value & 0x0f;
- return 0;
-}
+ info->default_threshold = value & 0x0f;
+ return 0;
+}/* set_default_threshold */
+
static int
get_default_threshold(struct cyclades_port * info, unsigned long *value)
{
- put_user(info->default_threshold,value);
- return 0;
-}
+ put_fs_long(info->default_threshold,value);
+ return 0;
+}/* get_default_threshold */
+
static int
set_timeout(struct cyclades_port * info, unsigned long value)
{
- unsigned char *base_addr;
- int card,channel,chip,index;
+ unsigned char *base_addr;
+ int card,channel,chip,index;
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ base_addr[CyRTPR<<index] = value & 0xff;
+ } else {
+ // Nothing to do!
+ }
+ return 0;
+}/* set_timeout */
- base_addr[CyRTPR<<index] = value & 0xff;
- return 0;
-}
static int
get_timeout(struct cyclades_port * info, unsigned long *value)
{
- unsigned char *base_addr;
- int card,channel,chip,index;
- unsigned long tmp;
+ unsigned char *base_addr;
+ int card,channel,chip,index;
+ unsigned long tmp;
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ tmp = base_addr[CyRTPR<<index];
+ put_fs_long(tmp,value);
+ } else {
+ // Nothing to do!
+ }
+ return 0;
+}/* get_timeout */
- tmp = base_addr[CyRTPR<<index];
- put_user(tmp,value);
- return 0;
-}
static int
set_default_timeout(struct cyclades_port * info, unsigned long value)
{
- info->default_timeout = value & 0xff;
- return 0;
-}
+ info->default_timeout = value & 0xff;
+ return 0;
+}/* set_default_timeout */
+
static int
get_default_timeout(struct cyclades_port * info, unsigned long *value)
{
- put_user(info->default_timeout,value);
- return 0;
-}
+ put_fs_long(info->default_timeout,value);
+ return 0;
+}/* get_default_timeout */
+
+/*
+ * This routine allows the tty driver to implement device-
+ * specific ioctl's. If the ioctl number passed in cmd is
+ * not recognized by the driver, it should return ENOIOCTLCMD.
+ */
static int
cy_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
@@ -2170,7 +3439,8 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
int ret_val = 0;
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */
+ printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
+ info->line, cmd, arg); /* */
#endif
switch (cmd) {
@@ -2182,7 +3452,7 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
break;
}
ret_val = get_mon_info(info, (struct cyclades_monitor *)arg);
- break;
+ break;
case CYGETTHRESH:
error = verify_area(VERIFY_WRITE, (void *) arg
,sizeof(unsigned long));
@@ -2190,11 +3460,11 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
ret_val = error;
break;
}
- ret_val = get_threshold(info, (unsigned long *)arg);
- break;
+ ret_val = get_threshold(info, (unsigned long *)arg);
+ break;
case CYSETTHRESH:
ret_val = set_threshold(info, (unsigned long)arg);
- break;
+ break;
case CYGETDEFTHRESH:
error = verify_area(VERIFY_WRITE, (void *) arg
,sizeof(unsigned long));
@@ -2202,11 +3472,11 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
ret_val = error;
break;
}
- ret_val = get_default_threshold(info, (unsigned long *)arg);
- break;
+ ret_val = get_default_threshold(info, (unsigned long *)arg);
+ break;
case CYSETDEFTHRESH:
ret_val = set_default_threshold(info, (unsigned long)arg);
- break;
+ break;
case CYGETTIMEOUT:
error = verify_area(VERIFY_WRITE, (void *) arg
,sizeof(unsigned long));
@@ -2214,11 +3484,11 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
ret_val = error;
break;
}
- ret_val = get_timeout(info, (unsigned long *)arg);
- break;
+ ret_val = get_timeout(info, (unsigned long *)arg);
+ break;
case CYSETTIMEOUT:
ret_val = set_timeout(info, (unsigned long)arg);
- break;
+ break;
case CYGETDEFTIMEOUT:
error = verify_area(VERIFY_WRITE, (void *) arg
,sizeof(unsigned long));
@@ -2226,23 +3496,23 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
ret_val = error;
break;
}
- ret_val = get_default_timeout(info, (unsigned long *)arg);
- break;
+ ret_val = get_default_timeout(info, (unsigned long *)arg);
+ break;
case CYSETDEFTIMEOUT:
ret_val = set_default_timeout(info, (unsigned long)arg);
- break;
+ break;
case TCSBRK: /* SVID version: non-zero arg --> no break */
- ret_val = tty_check_change(tty);
- if (ret_val)
- return ret_val;
+ ret_val = tty_check_change(tty);
+ if (ret_val)
+ return ret_val;
tty_wait_until_sent(tty,0);
if (!arg)
send_break(info, HZ/4); /* 1/4 second */
break;
case TCSBRKP: /* support for POSIX tcsendbreak() */
- ret_val = tty_check_change(tty);
- if (ret_val)
- return ret_val;
+ ret_val = tty_check_change(tty);
+ if (ret_val)
+ return ret_val;
tty_wait_until_sent(tty,0);
send_break(info, arg ? arg*(HZ/10) : HZ/4);
break;
@@ -2254,19 +3524,31 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
/* The following commands are incompletely implemented!!! */
case TIOCGSOFTCAR:
- ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *) arg);
- break;
+ error = verify_area(VERIFY_WRITE, (void *) arg
+ ,sizeof(unsigned int *));
+ if (error){
+ ret_val = error;
+ break;
+ }
+ put_fs_long(C_CLOCAL(tty) ? 1 : 0,
+ (unsigned long *) arg);
+ break;
case TIOCSSOFTCAR:
- ret_val = get_user(arg,(unsigned int *) arg);
- if (ret_val)
- break;
+ error = verify_area(VERIFY_READ, (void *) arg
+ ,sizeof(unsigned long *));
+ if (error) {
+ ret_val = error;
+ break;
+ }
+
+ arg = get_fs_long((unsigned long *) arg);
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
break;
case TIOCMGET:
error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(unsigned int));
+ ,sizeof(unsigned int *));
if (error){
ret_val = error;
break;
@@ -2294,31 +3576,35 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
(struct serial_struct *) arg);
break;
default:
- ret_val = -ENOIOCTLCMD;
+ ret_val = -ENOIOCTLCMD;
}
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_ioctl done\n");
+ printk(" cyc:cy_ioctl done\n");
#endif
return ret_val;
} /* cy_ioctl */
-
-
+/*
+ * This routine allows the tty driver to be notified when
+ * device's termios settings have changed. Note that a
+ * well-designed tty driver should be prepared to accept the case
+ * where old == NULL, and try to do something rational.
+ */
static void
cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_set_termios ttyC%d\n", info->line);
+ printk("cyc:cy_set_termios ttyC%d\n", info->line);
#endif
if (tty->termios->c_cflag == old_termios->c_cflag)
return;
- config_setup(info);
+ set_line_char(info);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
@@ -2335,353 +3621,243 @@ cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
} /* cy_set_termios */
+/*
+ * void (*set_ldisc)(struct tty_struct *tty);
+ *
+ * This routine allows the tty driver to be notified when the
+ * device's termios settings have changed.
+ *
+ */
+
+
+/* This routine is called by the upper-layer tty layer to signal
+ that incoming characters should be throttled because the input
+ buffers are close to full.
+ */
static void
-cy_close(struct tty_struct * tty, struct file * filp)
+cy_throttle(struct tty_struct * tty)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
+ unsigned char *base_addr;
+ int card,chip,channel,index;
-#ifdef SERIAL_DEBUG_OTHER
- printk("cy_close ttyC%d\n", info->line);
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("cyc:throttle %s: %d....ttyC%d\n", _tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty), info->line);
#endif
- if (!info
- || serial_paranoia_check(info, tty->device, "cy_close")){
- return;
+ if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+ return;
}
-#ifdef SERIAL_DEBUG_OPEN
- printk("cy_close ttyC%d, count = %d\n", info->line, info->count);
-#endif
-
- save_flags(flags); cli();
- /* If the TTY is being hung up, nothing to do */
- if (tty_hung_up_p(filp)) {
- MOD_DEC_USE_COUNT;
- restore_flags(flags);
- return;
- }
-
- if ((tty->count == 1) && (info->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("cy_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
- info->count = 1;
- }
-#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d(%d): decrementing count to %d\n", __LINE__, current->pid, info->count - 1);
-#endif
- if (--info->count < 0) {
-#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: setting count to 0\n", __LINE__);
-#endif
- info->count = 0;
+ if (I_IXOFF(tty)) {
+ info->x_char = STOP_CHAR(tty);
+ /* Should use the "Send Special Character" feature!!! */
}
- if (info->count)
- {
- MOD_DEC_USE_COUNT;
+
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyMSVR1<<index] = ~CyRTS;
restore_flags(flags);
- return;
- }
- info->flags |= ASYNC_CLOSING;
- /*
- * Save the termios structure, since this port may have
- * separate termios for callout and dialin.
- */
- if (info->flags & ASYNC_NORMAL_ACTIVE)
- info->normal_termios = *tty->termios;
- if (info->flags & ASYNC_CALLOUT_ACTIVE)
- info->callout_termios = *tty->termios;
- if (info->flags & ASYNC_INITIALIZED)
- tty_wait_until_sent(tty, 30*HZ); /* 30 seconds timeout */
- shutdown(info);
- if (tty->driver.flush_buffer)
- tty->driver.flush_buffer(tty);
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
- info->event = 0;
- info->tty = 0;
- if (info->blocked_open) {
- if (info->close_delay) {
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + info->close_delay;
- schedule();
- }
- wake_up_interruptible(&info->open_wait);
+ } else {
+ // Nothing to do!
}
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
- ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
-#ifdef SERIAL_DEBUG_OTHER
- printk("cy_close done\n");
-#endif
-
- MOD_DEC_USE_COUNT;
- restore_flags(flags);
return;
-} /* cy_close */
+} /* cy_throttle */
+
/*
- * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
+ * This routine notifies the tty driver that it should signal
+ * that characters can now be sent to the tty without fear of
+ * overrunning the input buffers of the line disciplines.
*/
-void
-cy_hangup(struct tty_struct *tty)
+static void
+cy_unthrottle(struct tty_struct * tty)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
-
-#ifdef SERIAL_DEBUG_OTHER
- printk("cy_hangup ttyC%d\n", info->line); /* */
-#endif
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+ unsigned char *base_addr;
+ int card,chip,channel,index;
- if (serial_paranoia_check(info, tty->device, "cy_hangup"))
- return;
-
- shutdown(info);
- info->event = 0;
- info->count = 0;
-#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d(%d): setting count to 0\n", __LINE__, current->pid);
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("cyc:throttle %s: %d....ttyC%d\n", _tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty), info->line);
#endif
- info->tty = 0;
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
- wake_up_interruptible(&info->open_wait);
-} /* cy_hangup */
+ if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+ return;
+ }
+ if (I_IXOFF(tty)) {
+ info->x_char = START_CHAR(tty);
+ /* Should use the "Send Special Character" feature!!! */
+ }
-/*
- * ------------------------------------------------------------
- * cy_open() and friends
- * ------------------------------------------------------------
- */
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
-static int
-block_til_ready(struct tty_struct *tty, struct file * filp,
- struct cyclades_port *info)
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyMSVR1<<index] = CyRTS;
+ restore_flags(flags);
+ }else{
+ // Nothing to do!
+ }
+
+ return;
+} /* cy_unthrottle */
+
+
+/* cy_start and cy_stop provide software output flow control as a
+ function of XON/XOFF, software CTS, and other such stuff.
+*/
+static void
+cy_stop(struct tty_struct *tty)
{
- struct wait_queue wait = { current, NULL };
struct cyclades_card *cinfo;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned char *base_addr;
+ int chip,channel,index;
unsigned long flags;
- int chip, channel,index;
- int retval;
- char *base_addr;
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (info->flags & ASYNC_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
- if (info->flags & ASYNC_HUP_NOTIFY){
- return -EAGAIN;
- }else{
- return -ERESTARTSYS;
- }
- }
+#ifdef SERIAL_DEBUG_OTHER
+ printk("cyc:cy_stop ttyC%d\n", info->line); /* */
+#endif
- /*
- * If this is a callout device, then just make sure the normal
- * device isn't being used.
- */
- if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
- if (info->flags & ASYNC_NORMAL_ACTIVE){
- return -EBUSY;
- }
- if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
- (info->flags & ASYNC_SESSION_LOCKOUT) &&
- (info->session != current->session)){
- return -EBUSY;
- }
- if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
- (info->flags & ASYNC_PGRP_LOCKOUT) &&
- (info->pgrp != current->pgrp)){
- return -EBUSY;
- }
- info->flags |= ASYNC_CALLOUT_ACTIVE;
- return 0;
+ if (serial_paranoia_check(info, tty->device, "cy_stop"))
+ return;
+
+ cinfo = &cy_card[info->card];
+ channel = info->line - cinfo->first_line;
+ if (!IS_CYC_Z(*cinfo)) {
+ index = cinfo->bus_index;
+ chip = channel>>2;
+ channel &= 0x03;
+ base_addr = (unsigned char*)
+ (cy_card[info->card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] =
+ (u_char)(channel & 0x0003); /* index channel */
+ base_addr[CySRER<<index] &= ~CyTxMpty;
+ restore_flags(flags);
+ } else {
+ // Nothing to do!
}
- /*
- * If non-blocking mode is set, then make the check up front
- * and then exit.
- */
- if (filp->f_flags & O_NONBLOCK) {
- if (info->flags & ASYNC_CALLOUT_ACTIVE){
- return -EBUSY;
- }
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
+ return;
+} /* cy_stop */
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * cy_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: ttyC%d, count = %d\n",
- info->line, info->count);/**/
-#endif
- info->count--;
-#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d(%d): decrementing count to %d\n", __LINE__, current->pid, info->count);
+
+static void
+cy_start(struct tty_struct *tty)
+{
+ struct cyclades_card *cinfo;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned char *base_addr;
+ int chip,channel,index;
+ unsigned long flags;
+
+#ifdef SERIAL_DEBUG_OTHER
+ printk("cyc:cy_start ttyC%d\n", info->line); /* */
#endif
- info->blocked_open++;
+ if (serial_paranoia_check(info, tty->device, "cy_start"))
+ return;
+
cinfo = &cy_card[info->card];
channel = info->line - cinfo->first_line;
- chip = channel>>2;
- channel &= 0x03;
index = cinfo->bus_index;
- base_addr = (char *) (cinfo->base_addr + (cy_chip_offset[chip]<<index));
-
- while (1) {
- save_flags(flags); cli();
- if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){
- base_addr[CyCAR<<index] = (u_char)channel;
- base_addr[CyMSVR1<<index] = CyRTS;
- base_addr[CyMSVR2<<index] = CyDTR;
-#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: raising DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
-#endif
- }
- restore_flags(flags);
- current->state = TASK_INTERRUPTIBLE;
- if (tty_hung_up_p(filp)
- || !(info->flags & ASYNC_INITIALIZED) ){
- if (info->flags & ASYNC_HUP_NOTIFY) {
- retval = -EAGAIN;
- }else{
- retval = -ERESTARTSYS;
- }
- break;
- }
- save_flags(flags); cli();
- base_addr[CyCAR<<index] = (u_char)channel;
- if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
- && !(info->flags & ASYNC_CLOSING)
- && (C_CLOCAL(tty)
- || (base_addr[CyMSVR1<<index] & CyDCD))) {
- restore_flags(flags);
- break;
- }
- restore_flags(flags);
- if (current->signal & ~current->blocked) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready blocking: ttyC%d, count = %d\n",
- info->line, info->count);/**/
-#endif
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp)){
- info->count++;
-#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d(%d): incrementing count to %d\n", __LINE__, current->pid, info->count);
-#endif
+ if (!IS_CYC_Z(*cinfo)) {
+ chip = channel>>2;
+ channel &= 0x03;
+ base_addr = (unsigned char*)
+ (cy_card[info->card].base_addr
+ + (cy_chip_offset[chip]<<index));
+
+ save_flags(flags); cli();
+ base_addr[CyCAR<<index] = (u_char)(channel & 0x0003);
+ base_addr[CySRER<<index] |= CyTxMpty;
+ restore_flags(flags);
+ } else {
+ // Nothing to do!
}
- info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: ttyC%d, count = %d\n",
- info->line, info->count);/**/
-#endif
- if (retval)
- return retval;
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-} /* block_til_ready */
+
+ return;
+} /* cy_start */
+
/*
- * This routine is called whenever a serial port is opened. It
- * performs the serial-specific initialization for the tty structure.
+ * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
-int
-cy_open(struct tty_struct *tty, struct file * filp)
+static void
+cy_hangup(struct tty_struct *tty)
{
- struct cyclades_port *info;
- int retval, line;
-
- line = MINOR(tty->device) - tty->driver.minor_start;
- if ((line < 0) || (NR_PORTS <= line)){
- return -ENODEV;
- }
- info = &cy_port[line];
- if (info->line < 0){
- return -ENODEV;
- }
+ struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_open ttyC%d\n", info->line); /* */
-#endif
- if (serial_paranoia_check(info, tty->device, "cy_open")){
- return -ENODEV;
- }
-#ifdef SERIAL_DEBUG_OPEN
- printk("cy_open ttyC%d, count = %d\n", info->line, info->count);/**/
+ printk("cyc:cy_hangup ttyC%d\n", info->line); /* */
#endif
- info->count++;
-#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d(%d): incrementing count to %d\n", __LINE__, current->pid, info->count);
-#endif
- tty->driver_data = info;
- info->tty = tty;
- if (!tmp_buf) {
- tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
- if (!tmp_buf){
- return -ENOMEM;
- }
- }
-
- if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
- if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
- *tty->termios = info->normal_termios;
- else
- *tty->termios = info->callout_termios;
- }
- /*
- * Start up serial port
- */
- retval = startup(info);
- if (retval){
- return retval;
- }
-
- MOD_INC_USE_COUNT;
-
- retval = block_til_ready(tty, filp, info);
- if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
- printk("cy_open returning after block_til_ready with %d\n",
- retval);
+ if (serial_paranoia_check(info, tty->device, "cy_hangup"))
+ return;
+
+ shutdown(info);
+ info->event = 0;
+ info->count = 0;
+#ifdef SERIAL_DEBUG_COUNT
+ printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
#endif
- return retval;
- }
+ info->tty = 0;
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+ wake_up_interruptible(&info->open_wait);
+} /* cy_hangup */
- info->session = current->session;
- info->pgrp = current->pgrp;
-#ifdef SERIAL_DEBUG_OPEN
- printk("cy_open done\n");/**/
+static void
+cy_flush_buffer(struct tty_struct *tty)
+{
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+
+#ifdef SERIAL_DEBUG_IO
+ printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
#endif
- return 0;
-} /* cy_open */
+ if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
+ return;
+ save_flags(flags); cli();
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ 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);
+} /* cy_flush_buffer */
/*
@@ -2692,21 +3868,11 @@ cy_open(struct tty_struct *tty, struct file * filp)
* ---------------------------------------------------------------------
*/
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-static inline void
-show_version(void)
-{
- printk("Cyclom driver %s\n",rcsid);
-} /* show_version */
-/* initialize chips on card -- return number of valid
+/* initialize chips on Cyclom-Y card -- return number of valid
chips (which is number of ports/4) */
__initfunc(static int
-cy_init_card(unsigned char *true_base_addr,int index))
+cyy_init_card(unsigned char *true_base_addr,int index))
{
unsigned int chip_number;
unsigned char* base_addr;
@@ -2716,7 +3882,8 @@ cy_init_card(unsigned char *true_base_addr,int index))
udelay(500L);
for(chip_number=0; chip_number<CyMaxChipsPerCard; chip_number++){
- base_addr = true_base_addr + (cy_chip_offset[chip_number]<<index);
+ base_addr = true_base_addr
+ + (cy_chip_offset[chip_number]<<index);
udelay(1000L);
if(base_addr[CyCCR<<index] != 0x00){
/*************
@@ -2736,39 +3903,396 @@ cy_init_card(unsigned char *true_base_addr,int index))
and this must be a Cyclom-16Y, not a Cyclom-32Ye.
*/
if (chip_number == 4
- && *(true_base_addr + (cy_chip_offset[0]<<index) + (CyGFRCR<<index)) == 0){
- return chip_number;
+ && *(true_base_addr
+ + (cy_chip_offset[0]<<index)
+ + (CyGFRCR<<index)) == 0){
+ return chip_number;
}
base_addr[CyCCR<<index] = CyCHIP_RESET;
udelay(1000L);
if(base_addr[CyGFRCR<<index] == 0x00){
- /*
- printk(" chip #%d at %#6lx is not responding (GFRCR stayed 0)\n",
+ /*
+ printk(" chip #%d at %#6lx is not responding ",
chip_number, (unsigned long)base_addr);
- */
+ printk("(GFRCR stayed 0)\n",
+ */
return chip_number;
}
if((0xf0 & base_addr[CyGFRCR<<index]) != 0x40){
- /*
+ /*
printk(" chip #%d at %#6lx is not valid (GFRCR == %#2x)\n",
- chip_number, (unsigned long)base_addr, base_addr[CyGFRCR<<index]);
- */
+ chip_number, (unsigned long)base_addr,
+ base_addr[CyGFRCR<<index]);
+ */
return chip_number;
}
base_addr[CyGCR<<index] = CyCH0_SERIAL;
- base_addr[CyPPR<<index] = 244; /* better value than CyCLOCK_25_1MS * 5
- to run clock at 200 Hz */
+ base_addr[CyPPR<<index] = 244;
+ /* better value than CyCLOCK_25_1MS * 5
+ to run clock at 200 Hz */
- /*
+ /*
printk(" chip #%d at %#6lx is rev 0x%2x\n",
- chip_number, (unsigned long)base_addr, base_addr[CyGFRCR<<index]);
- */
+ chip_number, (unsigned long)base_addr,
+ base_addr[CyGFRCR<<index]);
+ */
}
return chip_number;
-} /* cy_init_card */
+} /* cyy_init_card */
+
+
+/*
+ * ---------------------------------------------------------------------
+ * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
+ * sets global variables and return the number of ISA boards found.
+ * ---------------------------------------------------------------------
+ */
+__initfunc(static int
+cy_detect_isa(void))
+{
+ unsigned int cy_isa_irq,nboard;
+ unsigned char *cy_isa_address;
+ unsigned short i,j,cy_isa_nchan;
+
+ nboard = 0;
+
+ /* scan the address table probing for Cyclom-Y/ISA boards */
+ for (i = 0 ; i < NR_ISA_ADDRS ; i++) {
+ cy_isa_address = cy_isa_addresses[i];
+ if (cy_isa_address == 0x0000) {
+ return(nboard);
+ }
+
+ /* probe for CD1400... */
+#if LINUX_VERSION_CODE >= 131328
+ cy_isa_address = vremap((unsigned int)cy_isa_address,0x2000);
+#endif
+ cy_isa_nchan = 4 * cyy_init_card(cy_isa_address,0);
+ if (cy_isa_nchan == 0) {
+ continue;
+ }
+
+ /* find out the board's irq by probing */
+ cy_isa_irq = do_auto_irq(cy_isa_address);
+ if (cy_isa_irq == 0) {
+ printk("Cyclom-Y/ISA found at 0x%x ",
+ (unsigned int) cy_isa_address);
+ printk("but the IRQ could not be detected.\n");
+ continue;
+ }
+
+ if((cy_next_channel+cy_isa_nchan) > NR_PORTS) {
+ printk("Cyclom-Y/ISA found at 0x%x ",
+ (unsigned int) cy_isa_address);
+ printk("but no more channels are available.\n");
+ return(nboard);
+ }
+ /* fill the next cy_card structure available */
+ for (j = 0 ; j < NR_CARDS ; j++) {
+ if (cy_card[j].base_addr == 0) break;
+ }
+ if (j == NR_CARDS) { /* no more cy_cards available */
+ printk("Cyclom-Y/ISA found at 0x%x ",
+ (unsigned int) cy_isa_address);
+ printk("but no more cards can be used .\n");
+ return(nboard);
+ }
+
+ /* allocate IRQ */
+ if(request_irq(cy_isa_irq, cyy_interrupt,
+ SA_INTERRUPT, "cyclomY", NULL))
+ {
+ printk("Cyclom-Y/ISA found at 0x%x ",
+ (unsigned int) cy_isa_address);
+ printk("but could not allocate IRQ#%d.\n",
+ cy_isa_irq);
+ return(nboard);
+ }
+
+ /* set cy_card */
+ cy_card[j].base_addr = (int) cy_isa_address;
+ cy_card[j].ctl_addr = 0;
+ cy_card[j].irq = (int) cy_isa_irq;
+ cy_card[j].bus_index = 0;
+ cy_card[j].first_line = cy_next_channel;
+ cy_card[j].num_chips = cy_isa_nchan/4;
+ IRQ_cards[cy_isa_irq] = &cy_card[j];
+ nboard++;
+
+ /* print message */
+ printk("Cyclom-Y/ISA #%d: 0x%x-0x%x, IRQ%d, ",
+ j+1, (unsigned int) cy_isa_address,
+ (unsigned int)(cy_isa_address + 0x1fff),
+ cy_isa_irq);
+ printk("%d channels starting from port %d.\n",
+ cy_isa_nchan, cy_next_channel);
+ cy_next_channel += cy_isa_nchan;
+ }
+ return(nboard);
+
+} /* cy_detect_isa */
+
+/*
+ * ---------------------------------------------------------------------
+ * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI.
+ * sets global variables and return the number of PCI boards found.
+ * ---------------------------------------------------------------------
+ */
+__initfunc(static int
+cy_detect_pci(void))
+{
+#ifdef CONFIG_PCI
+ unsigned char cyy_bus, cyy_dev_fn, cyy_rev_id;
+ unsigned long pci_intr_ctrl;
+ unsigned char cy_pci_irq;
+ unsigned int cy_pci_addr0, cy_pci_addr1, cy_pci_addr2;
+ unsigned short i,j,cy_pci_nchan;
+ unsigned short device_id,dev_index = 0,board_index = 0;
+
+ if(pcibios_present() == 0) { /* PCI bus not present */
+ return(0);
+ }
+ for (i = 0; i < NR_CARDS; i++) {
+ /* look for a Cyclades card by vendor and device id */
+ while((device_id = cy_pci_dev_id[dev_index]) != 0) {
+ if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES,
+ device_id,board_index,
+ &cyy_bus, &cyy_dev_fn) != 0)
+ {
+ dev_index++; /* try next device id */
+ board_index = 0;
+ } else {
+ board_index++;
+ break; /* found a board */
+ }
+ }
+
+ /* read PCI configuration area */
+ pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
+ PCI_INTERRUPT_LINE, &cy_pci_irq);
+ pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+ PCI_BASE_ADDRESS_0, &cy_pci_addr0);
+ pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+ PCI_BASE_ADDRESS_1, &cy_pci_addr1);
+ pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+ PCI_BASE_ADDRESS_2, &cy_pci_addr2);
+ pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
+ PCI_REVISION_ID, &cyy_rev_id);
+ if (device_id == 0){
+ break;
+ }else if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo)
+ || (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){
+#ifdef CY_PCI_DEBUG
+ printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
+ cyy_bus, cyy_dev_fn);
+ printk("rev_id=%d) IRQ%d\n",
+ cyy_rev_id, (int)cy_pci_irq);
+ printk("Cyclom-Y/PCI:found winaddr=0x%x ioaddr=0x%x\n",
+ cy_pci_addr2, cy_pci_addr1);
+#endif
+ cy_pci_addr1 &= 0xfffffffc;
+ cy_pci_addr2 &= 0xfffffff0;
+
+#if LINUX_VERSION_CODE < 131328
+ if ((ulong)cy_pci_addr2 >= 0x100000) /* above 1M? */
+#endif
+ cy_pci_addr2 =
+ (unsigned int) vremap(cy_pci_addr2,CyPCI_Ywin);
+
+#ifdef CY_PCI_DEBUG
+ printk("Cyclom-Y/PCI: relocate winaddr=0x%x ioaddr=0x%x\n",
+ cy_pci_addr2, cy_pci_addr1);
+#endif
+ cy_pci_nchan = 4 * cyy_init_card((unsigned char *)
+ cy_pci_addr2,1);
+ if(cy_pci_nchan == 0) {
+ printk("Cyclom-Y PCI host card with ");
+ printk("no Serial-Modules at 0x%x.\n",
+ (unsigned int) cy_pci_addr2);
+ continue;
+ }
+ if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
+ printk("Cyclom-Y/PCI found at 0x%x ",
+ (unsigned int) cy_pci_addr2);
+ printk("but no channels are available.\n");
+ return(i);
+ }
+ /* fill the next cy_card structure available */
+ for (j = 0 ; j < NR_CARDS ; j++) {
+ if (cy_card[j].base_addr == 0) break;
+ }
+ if (j == NR_CARDS) { /* no more cy_cards available */
+ printk("Cyclom-Y/PCI found at 0x%x ",
+ (unsigned int) cy_pci_addr2);
+ printk("but no more cards can be used.\n");
+ return(i);
+ }
+
+ /* allocate IRQ */
+ if(request_irq(cy_pci_irq, cyy_interrupt,
+ SA_INTERRUPT, "cyclomY", NULL))
+ {
+ printk("Cyclom-Y/PCI found at 0x%x ",
+ (unsigned int) cy_pci_addr2);
+ printk("but could not allocate IRQ%d.\n",
+ cy_pci_irq);
+ return(i);
+ }
+
+ /* set cy_card */
+ cy_card[j].base_addr = (int) cy_pci_addr2;
+ cy_card[j].ctl_addr = 0;
+ cy_card[j].irq = (int) cy_pci_irq;
+ cy_card[j].bus_index = 1;
+ cy_card[j].first_line = cy_next_channel;
+ cy_card[j].num_chips = cy_pci_nchan/4;
+ IRQ_cards[cy_pci_irq] = &cy_card[j];
+
+ /* enable interrupts in the PCI interface */
+ outw(inw(cy_pci_addr1+0x68)|0x0900,cy_pci_addr1+0x68);
+ pci_intr_ctrl = (unsigned long)
+ (inw(cy_pci_addr1+0x68)
+ | inw(cy_pci_addr1+0x6a)<<16);
+
+ /* print message */
+ printk("Cyclom-Y/PCI #%d: 0x%x-0x%x, IRQ%d, ",
+ j+1, cy_pci_addr2, (cy_pci_addr2 + CyPCI_Ywin - 1),
+ (int)cy_pci_irq);
+ printk("%d channels starting from port %d.\n",
+ cy_pci_nchan, cy_next_channel);
+
+ cy_next_channel += cy_pci_nchan;
+ }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){
+ /* print message */
+ printk("Cyclom-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+ cyy_bus, cyy_dev_fn);
+ printk("rev_id=%d) IRQ%d\n",
+ cyy_rev_id, (int)cy_pci_irq);
+ printk("Cyclom-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n",
+ cy_pci_addr2, cy_pci_addr0);
+ printk("Cyclom-Z/PCI not supported for low addresses\n");
+ break;
+ }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){
+#ifdef CY_PCI_DEBUG
+ printk("Cyclom-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+ cyy_bus, cyy_dev_fn);
+ printk("rev_id=%d) IRQ%d\n",
+ cyy_rev_id, (int)cy_pci_irq);
+ printk("Cyclom-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n",
+ cy_pci_addr2, cy_pci_addr0);
+#endif
+ cy_pci_addr2 &= 0xfffffff0;
+ cy_pci_addr2 = (unsigned int) vremap(
+ cy_pci_addr2 & PAGE_MASK,
+ PAGE_ALIGN(CyPCI_Zwin))
+ + (cy_pci_addr2 & (PAGE_SIZE-1));
+ cy_pci_addr0 &= 0xfffffff0;
+ cy_pci_addr0 = (unsigned int) vremap(
+ cy_pci_addr0 & PAGE_MASK,
+ PAGE_ALIGN(CyPCI_Zctl))
+ + (cy_pci_addr0 & (PAGE_SIZE-1));
+#ifdef CY_PCI_DEBUG
+ printk("Cyclom-Z/PCI: relocate winaddr=0x%x ctladdr=0x%x\n",
+ cy_pci_addr2, cy_pci_addr0);
+ ((struct RUNTIME_9060 *)(cy_pci_addr0))
+ ->loc_addr_base = WIN_CREG;
+ PAUSE
+ printk("Cyclom-Z/PCI: FPGA id %lx, ver %lx\n",
+ 0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_id,
+ 0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_version);
+ ((struct RUNTIME_9060 *)(cy_pci_addr0))
+ ->loc_addr_base = WIN_RAM;
+#endif
+ /* The following clears the firmware id word. This ensures
+ that the driver will not attempt to talk to the board
+ until it has been properly initialized.
+ */
+ PAUSE
+ *(unsigned long *)(cy_pci_addr2+ID_ADDRESS) = 0L;
+
+ /* This must be a Cyclom-8Zo/PCI. The extendable
+ version will have a different device_id and will
+ be allocated its maximum number of ports. */
+ cy_pci_nchan = 8;
+
+ /* fill the next cy_card structure available */
+ for (j = 0 ; j < NR_CARDS ; j++) {
+ if (cy_card[j].base_addr == 0) break;
+ }
+ if (j == NR_CARDS) { /* no more cy_cards available */
+ printk("Cyclom-Z/PCI found at 0x%x ",
+ (unsigned int) cy_pci_addr2);
+ printk("but no more cards can be used.\n");
+ return(i);
+ }
+
+ /* allocate IRQ only if board has an IRQ */
+ if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) {
+ if(request_irq(cy_pci_irq,cyz_interrupt,
+ SA_INTERRUPT,"cyclomZ",NULL))
+ {
+ printk("Could not allocate IRQ%d ",
+ (unsigned int) cy_pci_addr2);
+ printk("for Cyclom-Z/PCI at 0x%x.\n",
+ cy_pci_irq);
+ return(i);
+ }
+ }
+
+ /* set cy_card */
+ cy_card[j].base_addr = cy_pci_addr2;
+ cy_card[j].ctl_addr = cy_pci_addr0;
+ cy_card[j].irq = (int) cy_pci_irq;
+ cy_card[j].bus_index = 1;
+ cy_card[j].first_line = cy_next_channel;
+ cy_card[j].num_chips = 1;
+ IRQ_cards[cy_pci_irq] = &cy_card[j];
+
+ /* print message */
+ /* don't report IRQ if board is no IRQ */
+ if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) {
+ printk("Cyclom-Z/PCI #%d: 0x%x-0x%x, IRQ%d, ",
+ j+1,cy_pci_addr2,
+ (cy_pci_addr2 + CyPCI_Zwin - 1),
+ (int)cy_pci_irq);
+ }else{
+ printk("Cyclom-Z/PCI #%d: 0x%x-0x%x, ",
+ j+1,cy_pci_addr2,
+ (cy_pci_addr2 + CyPCI_Zwin - 1));
+ }
+ printk("%d channels starting from port %d.\n",
+ cy_pci_nchan,cy_next_channel);
+ cy_next_channel += cy_pci_nchan;
+ }
+ }
+ return(i);
+#else
+ return(0);
+#endif /* ifdef CONFIG_PCI */
+} /* cy_detect_pci */
+
+
+/*
+ * This routine prints out the appropriate serial driver version number
+ * and identifies which options were configured into this driver.
+ */
+static inline void
+show_version(void)
+{
+ char *rcsvers, *rcsdate, *tmp;
+ rcsvers = strchr(rcsid, ' '); rcsvers++;
+ tmp = strchr(rcsvers, ' '); *tmp++ = '\0';
+ rcsdate = strchr(tmp, ' '); rcsdate++;
+ tmp = strrchr(rcsdate, ' '); *tmp = '\0';
+ printk("Cyclom driver %s %s\n",
+ rcsvers, rcsdate);
+ printk("\tbuilt %s %s\n",
+ __DATE__, __TIME__);
+} /* show_version */
+
/* The serial driver boot-time initialization code!
Hardware I/O ports are mapped to character special devices on a
@@ -2783,15 +4307,18 @@ cy_init_card(unsigned char *true_base_addr,int index))
device driver because the Cyclom is more properly a multiplexer,
not just an aggregation of serial ports on one card.
- If there are more cards with more ports than have been statically
- allocated above, a warning is printed and the extra ports are ignored.
+ If there are more cards with more ports than have been
+ statically allocated above, a warning is printed and the
+ extra ports are ignored.
*/
+
__initfunc(int
cy_init(void))
{
- struct cyclades_port *info;
+ struct cyclades_port *info;
struct cyclades_card *cinfo;
- int board,port,i;
+ int number_z_boards = 0;
+ int board,port,i;
show_version();
@@ -2807,7 +4334,7 @@ cy_init(void))
cy_serial_driver.subtype = SERIAL_TYPE_NORMAL;
cy_serial_driver.init_termios = tty_std_termios;
cy_serial_driver.init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
cy_serial_driver.flags = TTY_DRIVER_REAL_RAW;
cy_serial_driver.refcount = &serial_refcount;
cy_serial_driver.table = serial_table;
@@ -2839,27 +4366,27 @@ cy_init(void))
cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
if (tty_register_driver(&cy_serial_driver))
- panic("Couldn't register Cyclom serial driver\n");
+ panic("Couldn't register Cyclom serial driver\n");
if (tty_register_driver(&cy_callout_driver))
- panic("Couldn't register Cyclom callout driver\n");
+ panic("Couldn't register Cyclom callout driver\n");
init_bh(CYCLADES_BH, do_cyclades_bh);
for (i = 0; i < 16; i++) {
- IRQ_cards[i] = 0;
+ IRQ_cards[i] = 0;
}
for (i = 0; i < NR_CARDS; i++) {
- /* base_addr=0 indicates board not found */
- cy_card[i].base_addr = 0;
+ /* base_addr=0 indicates board not found */
+ cy_card[i].base_addr = 0;
}
/* the code below is responsible to find the boards. Each different
type of board has its own detection routine. If a board is found,
the next cy_card structure available is set by the detection
- routine. These functions are responsible for checking the availability
- of cy_card and cy_port data structures and updating the
- cy_next_channel. */
+ routine. These functions are responsible for checking the
+ availability of cy_card and cy_port data structures and updating
+ the cy_next_channel. */
/* look for isa boards */
cy_isa_nboard = cy_detect_isa();
@@ -2871,289 +4398,195 @@ cy_init(void))
/* invalidate remaining cy_card structures */
for (i = 0 ; i < NR_CARDS ; i++) {
- if (cy_card[i].base_addr == 0) {
- cy_card[i].first_line = -1;
- }
+ if (cy_card[i].base_addr == 0) {
+ cy_card[i].first_line = -1;
+ cy_card[i].ctl_addr = 0;
+ cy_card[i].irq = 0;
+ cy_card[i].bus_index = 0;
+ cy_card[i].first_line = 0;
+ cy_card[i].num_chips = 0;
+ }
}
/* invalidate remaining cy_port structures */
for (i = cy_next_channel ; i < NR_PORTS ; i++) {
- cy_port[i].line = -1;
- cy_port[i].magic = -1;
+ cy_port[i].line = -1;
+ cy_port[i].magic = -1;
}
/* initialize per-port data structures for each valid board found */
for (board = 0 ; board < cy_nboard ; board++) {
- cinfo = &cy_card[board];
- for (port = cinfo->first_line ;
- port < cinfo->first_line + 4*cinfo->num_chips ;
- port++)
- {
- info = &cy_port[port];
- info->magic = CYCLADES_MAGIC;
- info->type = PORT_CIRRUS;
- info->card = board;
- info->line = port;
- info->flags = STD_COM_FLAGS;
- info->tty = 0;
- info->xmit_fifo_size = 12;
- info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS;
- info->cor2 = CyETC;
- info->cor3 = 0x08; /* _very_ small receive threshold */
- info->cor4 = 0;
- info->cor5 = 0;
- info->tbpr = baud_bpr[13]; /* Tx BPR */
- info->tco = baud_co[13]; /* Tx CO */
- info->rbpr = baud_bpr[13]; /* Rx BPR */
- info->rco = baud_co[13]; /* Rx CO */
- info->close_delay = 0;
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
+ cinfo = &cy_card[board];
+ if (cinfo->num_chips == 1){ /* Cyclom-8Zo/PCI */
+ number_z_boards++;
+ for (port = cinfo->first_line ;
+ port < cinfo->first_line + 8;
+ port++)
+ {
+ info = &cy_port[port];
+ info->magic = CYCLADES_MAGIC;
+ info->type = PORT_STARTECH;
+ info->card = board;
+ info->line = port;
+ info->flags = STD_COM_FLAGS;
+ info->tty = 0;
+ info->xmit_fifo_size = 0;
+ info->cor1 = 0;
+ info->cor2 = 0;
+ info->cor3 = 0;
+ info->cor4 = 0;
+ info->cor5 = 0;
+ info->tbpr = 0;
+ info->tco = 0;
+ info->rbpr = 0;
+ info->rco = 0;
+ info->close_delay = 0;
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: setting count to 0\n", __LINE__);
-#endif
- info->blocked_open = 0;
- info->default_threshold = 0;
- info->default_timeout = 0;
- info->tqueue.routine = do_softint;
- info->tqueue.data = info;
- info->callout_termios =cy_callout_driver.init_termios;
- info->normal_termios = cy_serial_driver.init_termios;
- info->open_wait = 0;
- info->close_wait = 0;
- /* info->session */
- /* info->pgrp */
- info->read_status_mask = CyTIMEOUT| CySPECHAR| CyBREAK
- | CyPARITY| CyFRAME| CyOVERRUN;
- /* info->timeout */
- }
+ printk("cyc:cy_init(1) setting Z count to 0\n");
+#endif
+ info->blocked_open = 0;
+ info->default_threshold = 0;
+ info->default_timeout = 0;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+ info->callout_termios =
+ cy_callout_driver.init_termios;
+ info->normal_termios =
+ cy_serial_driver.init_termios;
+ info->open_wait = 0;
+ info->close_wait = 0;
+ /* info->session */
+ /* info->pgrp */
+ info->read_status_mask = 0;
+ /* info->timeout */
+ /* Bentson's vars */
+ info->jiffies[0] = 0;
+ info->jiffies[1] = 0;
+ info->jiffies[2] = 0;
+ info->rflush_count = 0;
+ }
+ continue;
+ }else{ /* Cyclom-Y of some kind*/
+ for (port = cinfo->first_line ;
+ port < cinfo->first_line + 4*cinfo->num_chips ;
+ port++)
+ {
+ info = &cy_port[port];
+ info->magic = CYCLADES_MAGIC;
+ info->type = PORT_CIRRUS;
+ info->card = board;
+ info->line = port;
+ info->flags = STD_COM_FLAGS;
+ info->tty = 0;
+ info->xmit_fifo_size = 12;
+ info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS;
+ info->cor2 = CyETC;
+ info->cor3 = 0x08; /* _very_ small rcv threshold */
+ info->cor4 = 0;
+ info->cor5 = 0;
+ info->tbpr = baud_bpr[13]; /* Tx BPR */
+ info->tco = baud_co[13]; /* Tx CO */
+ info->rbpr = baud_bpr[13]; /* Rx BPR */
+ info->rco = baud_co[13]; /* Rx CO */
+ info->close_delay = 0;
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
+#ifdef SERIAL_DEBUG_COUNT
+ printk("cyc:cy_init(2) setting Y count to 0\n");
+#endif
+ info->blocked_open = 0;
+ info->default_threshold = 0;
+ info->default_timeout = 0;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+ info->callout_termios =
+ cy_callout_driver.init_termios;
+ info->normal_termios =
+ cy_serial_driver.init_termios;
+ info->open_wait = 0;
+ info->close_wait = 0;
+ /* info->session */
+ /* info->pgrp */
+ info->read_status_mask =
+ CyTIMEOUT| CySPECHAR| CyBREAK
+ | CyPARITY| CyFRAME| CyOVERRUN;
+ /* info->timeout */
+ }
+ }
+ }
+
+ if ( number_z_boards && !cyz_timeron){
+ cyz_timeron++;
+ cyz_timerlist.expires = jiffies + 1;
+ add_timer(&cyz_timerlist);
+#ifdef CY_PCI_DEBUG
+ printk("Cyclom-Z polling initialized\n");
+#endif
}
+
return 0;
} /* cy_init */
#ifdef MODULE
+/* See linux/drivers/char/riscom.c for ideas on how to
+ pass additional base addresses to the driver!!! */
int
init_module(void)
{
return(cy_init());
-}
+} /* init_module */
void
cleanup_module(void)
{
- unsigned long flags;
int i;
+ unsigned long flags;
+
+
+ if (cyz_timeron){
+ cyz_timeron = 0;
+ del_timer(&cyz_timerlist);
+ }
save_flags(flags);
cli();
- remove_bh(CYCLADES_BH);
+ remove_bh(CYCLADES_BH);
if (tty_unregister_driver(&cy_callout_driver))
- printk("Couldn't unregister Cyclom callout driver\n");
+ printk("Couldn't unregister Cyclom callout driver\n");
if (tty_unregister_driver(&cy_serial_driver))
- printk("Couldn't unregister Cyclom serial driver\n");
+ printk("Couldn't unregister Cyclom serial driver\n");
restore_flags(flags);
for (i = 0; i < NR_CARDS; i++) {
- if (cy_card[i].base_addr != 0)
- {
- free_irq(cy_card[i].irq,NULL);
- }
+ if (cy_card[i].base_addr != 0
+ && cy_card[i].irq)
+ {
+ free_irq(cy_card[i].irq,NULL);
+ }
}
-}
-#endif
-
-/*
- * ---------------------------------------------------------------------
- * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
- * sets global variables and return the number of ISA boards found.
- * ---------------------------------------------------------------------
- */
-__initfunc(int
-cy_detect_isa())
-{
- unsigned int cy_isa_irq,nboard;
- unsigned char *cy_isa_address;
- unsigned short i,j,cy_isa_nchan;
-
- nboard = 0;
-
- /* scan the address table probing for Cyclom-Y/ISA boards */
- for (i = 0 ; i < NR_ISA_ADDRESSES ; i++) {
- cy_isa_address = cy_isa_addresses[i];
- if (cy_isa_address == 0x0000) {
- return(nboard);
- }
-
- /* probe for CD1400... */
- cy_isa_nchan = 4 * cy_init_card(cy_isa_address,0);
- if (cy_isa_nchan == 0) {
- continue;
- }
-
- /* find out the board's irq by probing */
- cy_isa_irq = do_auto_irq(cy_isa_address);
- if (cy_isa_irq == 0) {
- printk("Cyclom-Y/ISA found at 0x%x but the IRQ could not be detected.\n",
- (unsigned int) cy_isa_address);
- continue;
- }
-
- if((cy_next_channel+cy_isa_nchan) > NR_PORTS) {
- printk("Cyclom-Y/ISA found at 0x%x but no more channel structures are available.\n",
- (unsigned int) cy_isa_address);
- return(nboard);
- }
- /* fill the next cy_card structure available */
- for (j = 0 ; j < NR_CARDS ; j++) {
- if (cy_card[j].base_addr == 0) break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclom-Y/ISA found at 0x%x but no more card structures are available.\n",
- (unsigned int) cy_isa_address);
- return(nboard);
- }
-
- /* allocate IRQ */
- if(request_irq(cy_isa_irq,cy_interrupt,SA_INTERRUPT,"cyclades",NULL))
- {
- printk("Cyclom-Y/ISA found at 0x%x but could not allocate interrupt IRQ#%d.\n",
- (unsigned int) cy_isa_address,cy_isa_irq);
- return(nboard);
- }
-
- /* set cy_card */
- cy_card[j].base_addr = (int) cy_isa_address;
- cy_card[j].irq = (int) cy_isa_irq;
- cy_card[j].bus_index = 0;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = cy_isa_nchan/4;
- IRQ_cards[cy_isa_irq] = &cy_card[j];
- nboard++;
-
- /* print message */
- printk("Cyclom-Y/ISA #%d: 0x%x-0x%x, IRQ%d, %d channels starting from port %d.\n",
- j+1,(unsigned int) cy_isa_address,
- (unsigned int)(cy_isa_address + 0x1fff),
- cy_isa_irq,cy_isa_nchan,cy_next_channel);
- cy_next_channel += cy_isa_nchan;
- }
- return(nboard);
-
-}
-
-/*
- * ---------------------------------------------------------------------
- * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI.
- * sets global variables and return the number of PCI boards found.
- * ---------------------------------------------------------------------
- */
-__initfunc(int
-cy_detect_pci())
+} /* cleanup_module */
+#else
+/* called by linux/init/main.c to parse command line options */
+void
+cy_setup(char *str, int *ints)
{
-#ifdef CONFIG_PCI
- unsigned char cyy_bus, cyy_dev_fn, cyy_rev_id;
- unsigned long pci_intr_ctrl;
- unsigned char cy_pci_irq;
- unsigned int cy_pci_address, cy_pci_io;
- unsigned short i,j,cy_pci_nchan;
- unsigned short device_id,dev_index = 0,board_index = 0;
-
- if(pcibios_present() == 0) { /* PCI bus not present */
- return(0);
- }
- for (i = 0; i < NR_CARDS; i++) {
- /* look for a Cyclom-Y card by vendor and device id */
- while((device_id = cy_pci_dev_id[dev_index]) != 0) {
- if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES,
- device_id,board_index,
- &cyy_bus, &cyy_dev_fn) != 0)
- {
- dev_index++; /* try next device id */
- board_index = 0;
- } else {
- board_index++;
- break; /* found a board */
- }
- }
- if (device_id == 0) break;
-
- /* read PCI configuration area */
- pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
- PCI_INTERRUPT_LINE, &cy_pci_irq);
- pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
- PCI_BASE_ADDRESS_1, &cy_pci_io);
- pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
- PCI_BASE_ADDRESS_2, &cy_pci_address);
- pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
- PCI_REVISION_ID, &cyy_rev_id);
- cy_pci_address &= 0xfffffff0;
- if ((ulong)cy_pci_address >= 0x100000) { /* above 1M? */
- cy_pci_address =
- (unsigned int) ioremap(cy_pci_address,0x4000);
- }
- cy_pci_io &= 0xfffffffc;
- cy_pci_nchan = 4 * cy_init_card((unsigned char *)
- cy_pci_address,1);
- if(cy_pci_nchan == 0) {
- printk("Cyclom-Y PCI host card with no Serial-Modules at 0x%x.\n",
- (unsigned int) cy_pci_address);
- continue;
- }
- if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
- printk("Cyclom-Y/PCI found at 0x%x but no more channel structures are available.\n",
- (unsigned int) cy_pci_address);
- return(i);
- }
-#ifdef CY_PCI_DEBUG
- printk("Cyclom-Ye/PCI #%d (bus=0x0%x, pci_id=0x%x, rev_id=%d).\n",
- i+1,cyy_bus,cyy_dev_fn,cyy_rev_id);
- printk("Cyclom-Ye/PCI: found at 0x%x, IRQ%d, ioaddr = 0x%lx.\n",
- cy_pci_address,(int)cy_pci_irq,cy_pci_io);
-#endif
- /* fill the next cy_card structure available */
- for (j = 0 ; j < NR_CARDS ; j++) {
- if (cy_card[j].base_addr == 0) break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclom-Y/PCI found at 0x%x but no more card structures are available.\n",
- (unsigned int) cy_pci_address);
- return(i);
- }
+ int i, j;
- /* allocate IRQ */
- if(request_irq(cy_pci_irq,cy_interrupt,SA_INTERRUPT,"cyclades",NULL))
- {
- printk("Cyclom-Y/PCI found at 0x%x but could not allocate interrupt IRQ%d.\n",
- (unsigned int) cy_pci_address,cy_pci_irq);
- return(i);
- }
+ for (i = 0 ; i < NR_ISA_ADDRS ; i++) {
+ if (cy_isa_addresses[i] == 0) break;
+ }
+ for (j = 1; j <= ints[0]; j++){
+ if ( i < NR_ISA_ADDRS ){
+ cy_isa_addresses[i++] = (unsigned char *)(ints[j]);
+ }
+ }
- /* set cy_card */
- cy_card[j].base_addr = (int) cy_pci_address;
- cy_card[j].irq = (int) cy_pci_irq;
- cy_card[j].bus_index = 1;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = cy_pci_nchan/4;
- IRQ_cards[cy_pci_irq] = &cy_card[j];
-
- /* enable interrupts in the PCI interface */
- outw(inw(cy_pci_io+0x68)|0x0900,cy_pci_io+0x68);
- pci_intr_ctrl = (unsigned long)(inw(cy_pci_io+0x68) | inw(cy_pci_io+0x6a)<<16);
-
- /* print message */
- printk("Cyclom-Y/PCI #%d: 0x%x-0x%x, IRQ%d, %d channels starting from port %d.\n",
- j+1,(unsigned int) cy_pci_address,
- (unsigned int)(cy_pci_address + 0x3fff),
- (int)cy_pci_irq,cy_pci_nchan,cy_next_channel);
-
- cy_next_channel += cy_pci_nchan;
- }
- return(i);
-#else
- return(0);
-#endif /* ifdef CONFIG_PCI */
-}
+} /* cy_setup */
+#endif
#ifdef CYCLOM_SHOW_STATUS
@@ -3181,7 +4614,8 @@ show_status(int line_num)
printk(" cy_port\n");
printk(" card line flags = %d %d %x\n",
info->card, info->line, info->flags);
- printk(" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n",
+ printk(" *tty read_status_mask timeout xmit_fifo_size ",
+ printk("= %lx %x %x %x\n",
(long)info->tty, info->read_status_mask,
info->timeout, info->xmit_fifo_size);
printk(" cor1,cor2,cor3,cor4,cor5 = %x %x %x %x %x\n",
@@ -3198,59 +4632,60 @@ show_status(int line_num)
save_flags(flags); cli();
- base_addr = (unsigned char*)
- (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ base_addr = (unsigned char*)
+ (cy_card[card].base_addr
+ + (cy_chip_offset[chip]<<index));
/* Global Registers */
- printk(" CyGFRCR %x\n", base_addr[CyGFRCR<<index]);
- printk(" CyCAR %x\n", base_addr[CyCAR<<index]);
- printk(" CyGCR %x\n", base_addr[CyGCR<<index]);
- printk(" CySVRR %x\n", base_addr[CySVRR<<index]);
- printk(" CyRICR %x\n", base_addr[CyRICR<<index]);
- printk(" CyTICR %x\n", base_addr[CyTICR<<index]);
- printk(" CyMICR %x\n", base_addr[CyMICR<<index]);
- printk(" CyRIR %x\n", base_addr[CyRIR<<index]);
- printk(" CyTIR %x\n", base_addr[CyTIR<<index]);
- printk(" CyMIR %x\n", base_addr[CyMIR<<index]);
- printk(" CyPPR %x\n", base_addr[CyPPR<<index]);
+ printk(" CyGFRCR %x\n", base_addr[CyGFRCR<<index]);
+ printk(" CyCAR %x\n", base_addr[CyCAR<<index]);
+ printk(" CyGCR %x\n", base_addr[CyGCR<<index]);
+ printk(" CySVRR %x\n", base_addr[CySVRR<<index]);
+ printk(" CyRICR %x\n", base_addr[CyRICR<<index]);
+ printk(" CyTICR %x\n", base_addr[CyTICR<<index]);
+ printk(" CyMICR %x\n", base_addr[CyMICR<<index]);
+ printk(" CyRIR %x\n", base_addr[CyRIR<<index]);
+ printk(" CyTIR %x\n", base_addr[CyTIR<<index]);
+ printk(" CyMIR %x\n", base_addr[CyMIR<<index]);
+ printk(" CyPPR %x\n", base_addr[CyPPR<<index]);
- base_addr[CyCAR<<index] = (u_char)channel;
+ base_addr[CyCAR<<index] = (u_char)channel;
/* Virtual Registers */
- printk(" CyRIVR %x\n", base_addr[CyRIVR<<index]);
- printk(" CyTIVR %x\n", base_addr[CyTIVR<<index]);
- printk(" CyMIVR %x\n", base_addr[CyMIVR<<index]);
- printk(" CyMISR %x\n", base_addr[CyMISR<<index]);
+ printk(" CyRIVR %x\n", base_addr[CyRIVR<<index]);
+ printk(" CyTIVR %x\n", base_addr[CyTIVR<<index]);
+ printk(" CyMIVR %x\n", base_addr[CyMIVR<<index]);
+ printk(" CyMISR %x\n", base_addr[CyMISR<<index]);
/* Channel Registers */
- printk(" CyCCR %x\n", base_addr[CyCCR<<index]);
- printk(" CySRER %x\n", base_addr[CySRER<<index]);
- printk(" CyCOR1 %x\n", base_addr[CyCOR1<<index]);
- printk(" CyCOR2 %x\n", base_addr[CyCOR2<<index]);
- printk(" CyCOR3 %x\n", base_addr[CyCOR3<<index]);
- printk(" CyCOR4 %x\n", base_addr[CyCOR4<<index]);
- printk(" CyCOR5 %x\n", base_addr[CyCOR5<<index]);
- printk(" CyCCSR %x\n", base_addr[CyCCSR<<index]);
- printk(" CyRDCR %x\n", base_addr[CyRDCR<<index]);
- printk(" CySCHR1 %x\n", base_addr[CySCHR1<<index]);
- printk(" CySCHR2 %x\n", base_addr[CySCHR2<<index]);
- printk(" CySCHR3 %x\n", base_addr[CySCHR3<<index]);
- printk(" CySCHR4 %x\n", base_addr[CySCHR4<<index]);
- printk(" CySCRL %x\n", base_addr[CySCRL<<index]);
- printk(" CySCRH %x\n", base_addr[CySCRH<<index]);
- printk(" CyLNC %x\n", base_addr[CyLNC<<index]);
- printk(" CyMCOR1 %x\n", base_addr[CyMCOR1<<index]);
- printk(" CyMCOR2 %x\n", base_addr[CyMCOR2<<index]);
- printk(" CyRTPR %x\n", base_addr[CyRTPR<<index]);
- printk(" CyMSVR1 %x\n", base_addr[CyMSVR1<<index]);
- printk(" CyMSVR2 %x\n", base_addr[CyMSVR2<<index]);
- printk(" CyRBPR %x\n", base_addr[CyRBPR<<index]);
- printk(" CyRCOR %x\n", base_addr[CyRCOR<<index]);
- printk(" CyTBPR %x\n", base_addr[CyTBPR<<index]);
- printk(" CyTCOR %x\n", base_addr[CyTCOR<<index]);
+ printk(" CyCCR %x\n", base_addr[CyCCR<<index]);
+ printk(" CySRER %x\n", base_addr[CySRER<<index]);
+ printk(" CyCOR1 %x\n", base_addr[CyCOR1<<index]);
+ printk(" CyCOR2 %x\n", base_addr[CyCOR2<<index]);
+ printk(" CyCOR3 %x\n", base_addr[CyCOR3<<index]);
+ printk(" CyCOR4 %x\n", base_addr[CyCOR4<<index]);
+ printk(" CyCOR5 %x\n", base_addr[CyCOR5<<index]);
+ printk(" CyCCSR %x\n", base_addr[CyCCSR<<index]);
+ printk(" CyRDCR %x\n", base_addr[CyRDCR<<index]);
+ printk(" CySCHR1 %x\n", base_addr[CySCHR1<<index]);
+ printk(" CySCHR2 %x\n", base_addr[CySCHR2<<index]);
+ printk(" CySCHR3 %x\n", base_addr[CySCHR3<<index]);
+ printk(" CySCHR4 %x\n", base_addr[CySCHR4<<index]);
+ printk(" CySCRL %x\n", base_addr[CySCRL<<index]);
+ printk(" CySCRH %x\n", base_addr[CySCRH<<index]);
+ printk(" CyLNC %x\n", base_addr[CyLNC<<index]);
+ printk(" CyMCOR1 %x\n", base_addr[CyMCOR1<<index]);
+ printk(" CyMCOR2 %x\n", base_addr[CyMCOR2<<index]);
+ printk(" CyRTPR %x\n", base_addr[CyRTPR<<index]);
+ printk(" CyMSVR1 %x\n", base_addr[CyMSVR1<<index]);
+ printk(" CyMSVR2 %x\n", base_addr[CyMSVR2<<index]);
+ printk(" CyRBPR %x\n", base_addr[CyRBPR<<index]);
+ printk(" CyRCOR %x\n", base_addr[CyRCOR<<index]);
+ printk(" CyTBPR %x\n", base_addr[CyTBPR<<index]);
+ printk(" CyTCOR %x\n", base_addr[CyTCOR<<index]);
restore_flags(flags);
} /* show_status */
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index dd035d58c..ef97f7255 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -34,6 +34,7 @@
#include <linux/delay.h> /* guess what */
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/init.h>
#include <asm/segment.h>
#include <asm/atarihw.h>
@@ -529,582 +530,7 @@ static struct file_operations dsp56k_fops = {
static int init_error = 0;
-void dsp56k_init(void)
-{
- if(!ATARIHW_PRESENT(DSP56K)) {
- init_error = 1;
- printk("DSP56k driver: Hardware not present\n");
- return;
- }
-
-#ifndef MODULE
- if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
- printk("DSP56k driver: Unable to register driver\n");
- return;
- }
-#endif /* !MODULE */
-
- dsp56k.in_use = 0;
-
- printk("DSP56k driver installed\n");
-}
-
-#ifdef MODULE
-int init_module(void)
-{
- int r;
-
- init_error = 0;
- dsp56k_init();
- if(init_error)
- return -EPERM;
-
- r = register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops);
- if(r) {
- printk("DSP56k driver: Unable to register driver\n");
- return r;
- }
-
- return 0;
-}
-
-void cleanup_module(void)
-{
- unregister_chrdev(DSP56K_MAJOR, "dsp56k");
-}
-#endif /* MODULE */
-/*
- * The DSP56001 Device Driver, saviour of the Free World(tm)
- *
- * Authors: Fredrik Noring <noring@lysator.liu.se>
- * lars brinkhoff <f93labr@dd.chalmers.se>
- * Tomas Berndtsson <tobe@lysator.liu.se>
- *
- * First version May 1996
- *
- * History:
- * 97-01-29 Tomas Berndtsson,
- * Integrated with Linux 2.1.21 kernel sources.
- * 97-02-15 Tomas Berndtsson,
- * Fixed for kernel 2.1.26
- *
- * BUGS:
- * Hmm... there must be something here :)
- *
- * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/malloc.h> /* for kmalloc() and kfree() */
-#include <linux/sched.h> /* for struct wait_queue etc */
-#include <linux/major.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/delay.h> /* guess what */
-#include <linux/fs.h>
-#include <linux/mm.h>
-
-#include <asm/segment.h>
-#include <asm/atarihw.h>
-#include <asm/traps.h>
-#include <asm/uaccess.h> /* For put_user and get_user */
-
-#include <asm/dsp56k.h>
-
-/* minor devices */
-#define DSP56K_DEV_56001 0 /* The only device so far */
-
-#define TIMEOUT 10 /* Host port timeout in number of tries */
-#define MAXIO 2048 /* Maximum number of words before sleep */
-#define DSP56K_MAX_BINARY_LENGTH (3*64*1024)
-
-#define DSP56K_TX_INT_ON dsp56k_host_interface.icr |= DSP56K_ICR_TREQ
-#define DSP56K_RX_INT_ON dsp56k_host_interface.icr |= DSP56K_ICR_RREQ
-#define DSP56K_TX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_TREQ
-#define DSP56K_RX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_RREQ
-
-#define DSP56K_TRANSMIT (dsp56k_host_interface.isr & DSP56K_ISR_TXDE)
-#define DSP56K_RECEIVE (dsp56k_host_interface.isr & DSP56K_ISR_RXDF)
-
-#define max(a,b) ((a) > (b) ? (a) : (b))
-#define min(a,b) ((a) < (b) ? (a) : (b))
-
-#define wait_some(n) \
-{ \
- current->state = TASK_INTERRUPTIBLE; \
- current->timeout = jiffies + n; \
- schedule(); \
-}
-
-#define handshake(count, maxio, timeout, ENABLE, f) \
-{ \
- long i, t, m; \
- while (count > 0) { \
- m = min(count, maxio); \
- for (i = 0; i < m; i++) { \
- for (t = 0; t < timeout && !ENABLE; t++) \
- wait_some(2); \
- if(!ENABLE) \
- return -EIO; \
- f; \
- } \
- count -= m; \
- if (m == maxio) wait_some(2); \
- } \
-}
-
-#define tx_wait(n) \
-{ \
- int t; \
- for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \
- wait_some(1); \
- if(!DSP56K_TRANSMIT) { \
- return -EIO; \
- } \
-}
-
-#define rx_wait(n) \
-{ \
- int t; \
- for(t = 0; t < n && !DSP56K_RECEIVE; t++) \
- wait_some(1); \
- if(!DSP56K_RECEIVE) { \
- return -EIO; \
- } \
-}
-
-/* DSP56001 bootstrap code */
-static char bootstrap[] = {
- 0x0c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x60, 0xf4, 0x00, 0x00, 0x00, 0x4f, 0x61, 0xf4,
- 0x00, 0x00, 0x7e, 0xa9, 0x06, 0x2e, 0x80, 0x00, 0x00, 0x47,
- 0x07, 0xd8, 0x84, 0x07, 0x59, 0x84, 0x08, 0xf4, 0xa8, 0x00,
- 0x00, 0x04, 0x08, 0xf4, 0xbf, 0x00, 0x0c, 0x00, 0x00, 0xfe,
- 0xb8, 0x0a, 0xf0, 0x80, 0x00, 0x7e, 0xa9, 0x08, 0xf4, 0xa0,
- 0x00, 0x00, 0x01, 0x08, 0xf4, 0xbe, 0x00, 0x00, 0x00, 0x0a,
- 0xa9, 0x80, 0x00, 0x7e, 0xad, 0x08, 0x4e, 0x2b, 0x44, 0xf4,
- 0x00, 0x00, 0x00, 0x03, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x01,
- 0x0e, 0xa0, 0x00, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb5, 0x08,
- 0x50, 0x2b, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb8, 0x08, 0x46,
- 0x2b, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x02, 0x0a, 0xf0, 0xaa,
- 0x00, 0x7e, 0xc9, 0x20, 0x00, 0x45, 0x0a, 0xf0, 0xaa, 0x00,
- 0x7e, 0xd0, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xc6, 0x0a, 0xa9,
- 0x80, 0x00, 0x7e, 0xc4, 0x08, 0x58, 0x6b, 0x0a, 0xf0, 0x80,
- 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xcd, 0x0a,
- 0xa9, 0x80, 0x00, 0x7e, 0xcb, 0x08, 0x58, 0xab, 0x0a, 0xf0,
- 0x80, 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xd4,
- 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xd2, 0x08, 0x58, 0xeb, 0x0a,
- 0xf0, 0x80, 0x00, 0x7e, 0xad};
-static int sizeof_bootstrap = 375;
-
-
-static struct dsp56k_device {
- int in_use;
- long maxio, timeout;
- int tx_wsize, rx_wsize;
-} dsp56k;
-
-static int dsp56k_reset(void)
-{
- u_char status;
-
- /* Power down the DSP */
- sound_ym.rd_data_reg_sel = 14;
- status = sound_ym.rd_data_reg_sel & 0xef;
- sound_ym.wd_data = status;
- sound_ym.wd_data = status | 0x10;
-
- udelay(10);
-
- /* Power up the DSP */
- sound_ym.rd_data_reg_sel = 14;
- sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef;
-
- return 0;
-}
-
-static int dsp56k_upload(u_char *bin, int len)
-{
- int i;
- u_char *p;
-
- dsp56k_reset();
-
- p = bootstrap;
- for (i = 0; i < sizeof_bootstrap/3; i++) {
- /* tx_wait(10); */
- dsp56k_host_interface.data.b[1] = *p++;
- dsp56k_host_interface.data.b[2] = *p++;
- dsp56k_host_interface.data.b[3] = *p++;
- }
- for (; i < 512; i++) {
- /* tx_wait(10); */
- dsp56k_host_interface.data.b[1] = 0;
- dsp56k_host_interface.data.b[2] = 0;
- dsp56k_host_interface.data.b[3] = 0;
- }
-
- for (i = 0; i < len; i++) {
- tx_wait(10);
- get_user(dsp56k_host_interface.data.b[1], bin++);
- get_user(dsp56k_host_interface.data.b[2], bin++);
- get_user(dsp56k_host_interface.data.b[3], bin++);
- }
-
- tx_wait(10);
- dsp56k_host_interface.data.l = 3; /* Magic execute */
-
- return 0;
-}
-
-static long dsp56k_read(struct inode *inode, struct file *file,
- char *buf, unsigned long count)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch(dev)
- {
- case DSP56K_DEV_56001:
- {
-
- long n;
-
- /* Don't do anything if nothing is to be done */
- if (!count) return 0;
-
- n = 0;
- switch (dsp56k.rx_wsize) {
- case 1: /* 8 bit */
- {
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
- put_user(dsp56k_host_interface.data.b[3], buf+n++));
- return n;
- }
- case 2: /* 16 bit */
- {
- short *data;
-
- count /= 2;
- data = (short*) buf;
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
- put_user(dsp56k_host_interface.data.w[1], data+n++));
- return 2*n;
- }
- case 3: /* 24 bit */
- {
- count /= 3;
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
- put_user(dsp56k_host_interface.data.b[1], buf+n++);
- put_user(dsp56k_host_interface.data.b[2], buf+n++);
- put_user(dsp56k_host_interface.data.b[3], buf+n++));
- return 3*n;
- }
- case 4: /* 32 bit */
- {
- long *data;
-
- count /= 4;
- data = (long*) buf;
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
- put_user(dsp56k_host_interface.data.l, data+n++));
- return 4*n;
- }
- }
- return -EFAULT;
- }
-
- default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
- return -ENXIO;
- }
-}
-
-static long dsp56k_write(struct inode *inode, struct file *file,
- const char *buf, unsigned long count)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch(dev)
- {
- case DSP56K_DEV_56001:
- {
- long n;
-
- /* Don't do anything if nothing is to be done */
- if (!count) return 0;
-
- n = 0;
- switch (dsp56k.tx_wsize) {
- case 1: /* 8 bit */
- {
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
- get_user(dsp56k_host_interface.data.b[3], buf+n++));
- return n;
- }
- case 2: /* 16 bit */
- {
- short *data;
-
- count /= 2;
- data = (short*) buf;
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
- get_user(dsp56k_host_interface.data.w[1], data+n++));
- return 2*n;
- }
- case 3: /* 24 bit */
- {
- count /= 3;
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
- get_user(dsp56k_host_interface.data.b[1], buf+n++);
- get_user(dsp56k_host_interface.data.b[2], buf+n++);
- get_user(dsp56k_host_interface.data.b[3], buf+n++));
- return 3*n;
- }
- case 4: /* 32 bit */
- {
- long *data;
-
- count /= 4;
- data = (long*) buf;
- handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
- get_user(dsp56k_host_interface.data.l, data+n++));
- return 4*n;
- }
- }
-
- return -EFAULT;
- }
- default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
- return -ENXIO;
- }
-}
-
-static int dsp56k_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch(dev)
- {
- case DSP56K_DEV_56001:
-
- switch(cmd) {
- case DSP56K_UPLOAD:
- {
- char *bin;
- int r, len;
- struct dsp56k_upload *binary = (struct dsp56k_upload *) arg;
-
- if(get_user(len, &binary->len) < 0)
- return -EFAULT;
- if(get_user(bin, &binary->bin) < 0)
- return -EFAULT;
-
- if (len == 0) {
- return -EINVAL; /* nothing to upload?!? */
- }
- if (len > DSP56K_MAX_BINARY_LENGTH) {
- return -EINVAL;
- }
-
- r = dsp56k_upload(bin, len);
- if (r < 0) {
- return r;
- }
-
- break;
- }
- case DSP56K_SET_TX_WSIZE:
- if (arg > 4 || arg < 1)
- return -EINVAL;
- dsp56k.tx_wsize = (int) arg;
- break;
- case DSP56K_SET_RX_WSIZE:
- if (arg > 4 || arg < 1)
- return -EINVAL;
- dsp56k.rx_wsize = (int) arg;
- break;
- case DSP56K_HOST_FLAGS:
- {
- int dir, out, status;
- struct dsp56k_host_flags *hf = (struct dsp56k_host_flags*) arg;
-
- if(get_user(dir, &hf->dir) < 0)
- return -EFAULT;
- if(get_user(out, &hf->out) < 0)
- return -EFAULT;
-
- if ((dir & 0x1) && (out & 0x1))
- dsp56k_host_interface.icr |= DSP56K_ICR_HF0;
- else if (dir & 0x1)
- dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
- if ((dir & 0x2) && (out & 0x2))
- dsp56k_host_interface.icr |= DSP56K_ICR_HF1;
- else if (dir & 0x2)
- dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
-
- status = 0;
- if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1;
- if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2;
- if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
- if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
-
- if(put_user(status, &hf->status) < 0)
- return -EFAULT;
- break;
- }
- case DSP56K_HOST_CMD:
- if (arg > 31 || arg < 0)
- return -EINVAL;
- dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) |
- DSP56K_CVR_HC);
- break;
- default:
- return -EINVAL;
- }
- return 0;
-
- default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
- return -ENXIO;
- }
-}
-
-/* As of 2.1.26 this should be dsp56k_poll,
- * but how do I then check device minor number?
- * Do I need this function at all???
- */
-#ifdef 0
-static int dsp56k_select(struct inode *inode, struct file *file, int sel_type,
- select_table *wait)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch(dev)
- {
- case DSP56K_DEV_56001:
-
- switch(sel_type) {
- case SEL_IN: /* read */
- return 1;
- case SEL_OUT: /* write */
- return 1;
- default:
- return 1;
- }
-
- default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
- return -ENXIO;
- }
-}
-#endif
-
-static int dsp56k_open(struct inode *inode, struct file *file)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch(dev)
- {
- case DSP56K_DEV_56001:
-
- if (dsp56k.in_use)
- return -EBUSY;
-
- dsp56k.in_use = 1;
- dsp56k.timeout = TIMEOUT;
- dsp56k.maxio = MAXIO;
- dsp56k.rx_wsize = dsp56k.tx_wsize = 4;
-
- DSP56K_TX_INT_OFF;
- DSP56K_RX_INT_OFF;
-
- /* Zero host flags */
- dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
- dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
-
- break;
-
- default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
- return -ENXIO;
- }
-
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif /* MODULE */
-
- return 0;
-}
-
-static void dsp56k_release(struct inode *inode, struct file *file)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch(dev)
- {
- case DSP56K_DEV_56001:
-
- dsp56k.in_use = 0;
-
- break;
- default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
- return;
- }
-
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif /* MODULE */
-}
-
-static struct file_operations dsp56k_fops = {
- NULL, /* no special dsp56k_lseek */
- dsp56k_read,
- dsp56k_write,
- NULL, /* no special dsp56k_readdir */
- NULL, /* dsp56k_poll? */
- dsp56k_ioctl,
- NULL, /* no special dsp56k_mmap */
- dsp56k_open,
- dsp56k_release,
- NULL, /* no special dsp56k_fsync */
- NULL, /* no special dsp56k_fasync */
- NULL, /* no special dsp56k_check_media_change */
- NULL /* no special dsp56k_revalidate */
-};
-
-
-/****** Init and module functions ******/
-
-static int init_error = 0;
-
-void dsp56k_init(void)
+__initfunc(void dsp56k_init(void))
{
if(!ATARIHW_PRESENT(DSP56K)) {
init_error = 1;
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
new file mode 100644
index 000000000..63da8b5cb
--- /dev/null
+++ b/drivers/char/epca.c
@@ -0,0 +1,4313 @@
+/*
+
+
+ Copyright (C) 1996 Digi International.
+
+ For technical support please email digiLinux@dgii.com or
+ call Digi tech support at (612) 912-3456
+
+ Much of this design and code came from epca.c which was
+ copyright (C) 1994, 1995 Troy De Jongh, and subsquently
+ modified by David Nugent, Christoph Lameter, Mike McLagan.
+
+ 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.
+
+--------------------------------------------------------------------------- */
+/* See README.epca for change history --DAT*/
+
+
+#ifdef MODVERSIONS
+#define MODULE
+#endif
+
+/* -----------------------------------------------------------------------
+ This way modules should work regardless if they defined MODULE or
+ MODVERSIONS. (MODVERSIONS is for the newer kernels ...
+-------------------------------------------------------------------------- */
+
+#ifdef MODULE
+#include <linux/config.h>
+#endif /* MODULE */
+
+#include <linux/version.h>
+
+#define NEW_MODULES
+
+#ifdef NEW_MODULES
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif /* MODVERSIONS */
+#endif /* NEW_MODULES */
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif /* MODULE */
+
+
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/tty_driver.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/ctype.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
+
+#include <asm/bitops.h>
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty_flip.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/major.h>
+#include <linux/ioport.h>
+
+#ifdef MODULE
+#ifndef NEW_MODULES
+char kernel_version[]=UTS_RELEASE;
+#endif /* NEW_MODULE */
+#endif /* MODULE */
+
+
+#ifdef CONFIG_PCI
+#define ENABLE_PCI
+#endif /* CONFIG_PCI */
+
+
+
+#include <asm/uaccess.h>
+#define putUser(arg1, arg2) put_user(arg1, (unsigned long *)arg2)
+#define getUser(arg1, arg2) get_user(arg1, (unsigned int *)arg2)
+
+
+
+#ifdef ENABLE_PCI
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/digiPCI.h>
+#endif /* ENABLE_PCI */
+
+#include <linux/digi1.h>
+#include <linux/digiFep1.h>
+#include <linux/epca.h>
+#include <linux/epcaconfig.h>
+
+/* ---------------------- Begin defines ------------------------ */
+
+#define VERSION "1.1.0"
+
+/* This major needs to be submitted to Linux to join the majors list */
+
+#define DIGIINFOMAJOR 35 /* For Digi specific ioctl */
+
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAXCARDS 7
+#define epcaassert(x, msg) if (!(x)) epca_error(__LINE__, msg)
+
+/* ----------------- Begin global definitions ------------------- */
+
+static char mesg[100];
+static int pc_refcount, nbdevs = 0, num_cards = 0, liloconfig = 0;
+static int digi_poller_inhibited = 1 ;
+
+static int setup_error_code = 0;
+static int invalid_lilo_config = 0;
+
+/* -----------------------------------------------------------------------
+ MAXBOARDS is typically 12, but ISA and EISA cards are restricted to
+ 7 below.
+--------------------------------------------------------------------------*/
+static struct board_info boards[7];
+
+
+/* ------------- Begin structures used for driver registeration ---------- */
+
+struct tty_driver pc_driver;
+struct tty_driver pc_callout;
+struct tty_driver pc_info;
+
+/* The below structures are used to initialize the tty_driver structures. */
+
+/* -------------------------------------------------------------------------
+ Note : MAX_ALLOC is currently limited to 0x100. This restriction is
+ placed on us by Linux not Digi.
+----------------------------------------------------------------------------*/
+static struct tty_struct *pc_table[MAX_ALLOC];
+static struct termios *pc_termios[MAX_ALLOC];
+static struct termios *pc_termios_locked[MAX_ALLOC];
+
+
+/* ------------------ Begin Digi specific structures -------------------- */
+
+/* ------------------------------------------------------------------------
+ digi_channels represents an array of structures that keep track of
+ each channel of the Digi product. Information such as transmit and
+ receive pointers, termio data, and signal definitions (DTR, CTS, etc ...)
+ are stored here. This structure is NOT used to overlay the cards
+ physical channel structure.
+-------------------------------------------------------------------------- */
+
+static struct channel digi_channels[MAX_ALLOC];
+
+/* ------------------------------------------------------------------------
+ card_ptr is an array used to hold the address of the
+ first channel structure of each card. This array will hold
+ the addresses of various channels located in digi_channels.
+-------------------------------------------------------------------------- */
+static struct channel *card_ptr[MAXCARDS];
+
+/* ---------------------- Begin function prototypes --------------------- */
+
+/* ----------------------------------------------------------------------
+ Begin generic memory functions. These functions will be alias
+ (point at) more specific functions dependant on the board being
+ configured.
+----------------------------------------------------------------------- */
+
+
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+#endif /* MODULE */
+
+static inline void memwinon(struct board_info *b, unsigned int win);
+static inline void memwinoff(struct board_info *b, unsigned int win);
+static inline void globalwinon(struct channel *ch);
+static inline void rxwinon(struct channel *ch);
+static inline void txwinon(struct channel *ch);
+static inline void memoff(struct channel *ch);
+static inline void assertgwinon(struct channel *ch);
+static inline void assertmemoff(struct channel *ch);
+
+/* ---- Begin more 'specific' memory functions for cx_like products --- */
+
+static inline void pcxem_memwinon(struct board_info *b, unsigned int win);
+static inline void pcxem_memwinoff(struct board_info *b, unsigned int win);
+static inline void pcxem_globalwinon(struct channel *ch);
+static inline void pcxem_rxwinon(struct channel *ch);
+static inline void pcxem_txwinon(struct channel *ch);
+static inline void pcxem_memoff(struct channel *ch);
+
+/* ------ Begin more 'specific' memory functions for the pcxe ------- */
+
+static inline void pcxe_memwinon(struct board_info *b, unsigned int win);
+static inline void pcxe_memwinoff(struct board_info *b, unsigned int win);
+static inline void pcxe_globalwinon(struct channel *ch);
+static inline void pcxe_rxwinon(struct channel *ch);
+static inline void pcxe_txwinon(struct channel *ch);
+static inline void pcxe_memoff(struct channel *ch);
+
+/* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */
+/* Note : pc64xe and pcxi share the same windowing routines */
+
+static inline void pcxi_memwinon(struct board_info *b, unsigned int win);
+static inline void pcxi_memwinoff(struct board_info *b, unsigned int win);
+static inline void pcxi_globalwinon(struct channel *ch);
+static inline void pcxi_rxwinon(struct channel *ch);
+static inline void pcxi_txwinon(struct channel *ch);
+static inline void pcxi_memoff(struct channel *ch);
+
+/* - Begin 'specific' do nothing memory functions needed for some cards - */
+
+static inline void dummy_memwinon(struct board_info *b, unsigned int win);
+static inline void dummy_memwinoff(struct board_info *b, unsigned int win);
+static inline void dummy_globalwinon(struct channel *ch);
+static inline void dummy_rxwinon(struct channel *ch);
+static inline void dummy_txwinon(struct channel *ch);
+static inline void dummy_memoff(struct channel *ch);
+static inline void dummy_assertgwinon(struct channel *ch);
+static inline void dummy_assertmemoff(struct channel *ch);
+
+/* ------------------- Begin declare functions ----------------------- */
+
+static inline struct channel *verifyChannel(register struct tty_struct *);
+static inline void pc_sched_event(struct channel *, int);
+static void epca_error(int, char *);
+static void pc_close(struct tty_struct *, struct file *);
+static void shutdown(struct channel *);
+static void pc_hangup(struct tty_struct *);
+static void pc_put_char(struct tty_struct *, unsigned char);
+static int pc_write_room(struct tty_struct *);
+static int pc_chars_in_buffer(struct tty_struct *);
+static void pc_flush_buffer(struct tty_struct *);
+static void pc_flush_chars(struct tty_struct *);
+static int block_til_ready(struct tty_struct *, struct file *,
+ struct channel *);
+static int pc_open(struct tty_struct *, struct file *);
+static void post_fep_init(unsigned int crd);
+static void epcapoll(unsigned long);
+static void doevent(int);
+static void fepcmd(struct channel *, int, int, int, int, int);
+static unsigned termios2digi_h(struct channel *ch, unsigned);
+static unsigned termios2digi_i(struct channel *ch, unsigned);
+static unsigned termios2digi_c(struct channel *ch, unsigned);
+static void epcaparam(struct tty_struct *, struct channel *);
+static void receive_data(struct channel *);
+static int pc_ioctl(struct tty_struct *, struct file *,
+ unsigned int, unsigned long);
+static void pc_set_termios(struct tty_struct *, struct termios *);
+static void do_softint(void *);
+static void pc_stop(struct tty_struct *);
+static void pc_start(struct tty_struct *);
+static void pc_throttle(struct tty_struct * tty);
+static void pc_unthrottle(struct tty_struct *tty);
+static void digi_send_break(struct channel *ch, int msec);
+static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
+void epca_setup(char *, int *);
+void console_print(const char *);
+
+static int get_termio(struct tty_struct *, struct termio *);
+static int pc_write(struct tty_struct *, int, const unsigned char *, int);
+int pc_init(void);
+
+#ifdef ENABLE_PCI
+static int init_PCI(int);
+static int get_PCI_configuration(char, char, unsigned int *, unsigned int *,
+ unsigned int *, unsigned int *,
+ unsigned int *, unsigned int *);
+#endif /* ENABLE_PCI */
+
+
+/* ------------------------------------------------------------------
+ Table of functions for each board to handle memory. Mantaining
+ parallelism is a *very* good idea here. The idea is for the
+ runtime code to blindly call these functions, not knowing/caring
+ about the underlying hardware. This stuff should contain no
+ conditionals; if more functionality is needed a different entry
+ should be established. These calls are the interface calls and
+ are the only functions that should be accessed. Anyone caught
+ making direct calls deserves what they get.
+-------------------------------------------------------------------- */
+
+static inline void memwinon(struct board_info *b, unsigned int win)
+{
+ (b->memwinon)(b, win);
+}
+
+static inline void memwinoff(struct board_info *b, unsigned int win)
+{
+ (b->memwinoff)(b, win);
+}
+
+static inline void globalwinon(struct channel *ch)
+{
+ (ch->board->globalwinon)(ch);
+}
+
+static inline void rxwinon(struct channel *ch)
+{
+ (ch->board->rxwinon)(ch);
+}
+
+static inline void txwinon(struct channel *ch)
+{
+ (ch->board->txwinon)(ch);
+}
+
+static inline void memoff(struct channel *ch)
+{
+ (ch->board->memoff)(ch);
+}
+static inline void assertgwinon(struct channel *ch)
+{
+ (ch->board->assertgwinon)(ch);
+}
+
+static inline void assertmemoff(struct channel *ch)
+{
+ (ch->board->assertmemoff)(ch);
+}
+
+/* ---------------------------------------------------------
+ PCXEM windowing is the same as that used in the PCXR
+ and CX series cards.
+------------------------------------------------------------ */
+
+static inline void pcxem_memwinon(struct board_info *b, unsigned int win)
+{
+ outb_p(FEPWIN|win, (int)b->port + 1);
+}
+
+static inline void pcxem_memwinoff(struct board_info *b, unsigned int win)
+{
+ outb_p(0, (int)b->port + 1);
+}
+
+static inline void pcxem_globalwinon(struct channel *ch)
+{
+ outb_p( FEPWIN, (int)ch->board->port + 1);
+}
+
+static inline void pcxem_rxwinon(struct channel *ch)
+{
+ outb_p(ch->rxwin, (int)ch->board->port + 1);
+}
+
+static inline void pcxem_txwinon(struct channel *ch)
+{
+ outb_p(ch->txwin, (int)ch->board->port + 1);
+}
+
+static inline void pcxem_memoff(struct channel *ch)
+{
+ outb_p(0, (int)ch->board->port + 1);
+}
+
+/* ----------------- Begin pcxe memory window stuff ------------------ */
+
+static inline void pcxe_memwinon(struct board_info *b, unsigned int win)
+{
+ outb_p(FEPWIN | win, (int)b->port + 1);
+}
+
+static inline void pcxe_memwinoff(struct board_info *b, unsigned int win)
+{
+ outb_p(inb((int)b->port) & ~FEPMEM,
+ (int)b->port + 1);
+ outb_p(0, (int)b->port + 1);
+}
+
+static inline void pcxe_globalwinon(struct channel *ch)
+{
+ outb_p( FEPWIN, (int)ch->board->port + 1);
+}
+
+static inline void pcxe_rxwinon(struct channel *ch)
+{
+ outb_p(ch->rxwin, (int)ch->board->port + 1);
+}
+
+static inline void pcxe_txwinon(struct channel *ch)
+{
+ outb_p(ch->txwin, (int)ch->board->port + 1);
+}
+
+static inline void pcxe_memoff(struct channel *ch)
+{
+ outb_p(0, (int)ch->board->port);
+ outb_p(0, (int)ch->board->port + 1);
+}
+
+/* ------------- Begin pc64xe and pcxi memory window stuff -------------- */
+
+static inline void pcxi_memwinon(struct board_info *b, unsigned int win)
+{
+ outb_p(inb((int)b->port) | FEPMEM, (int)b->port);
+}
+
+static inline void pcxi_memwinoff(struct board_info *b, unsigned int win)
+{
+ outb_p(inb((int)b->port) & ~FEPMEM, (int)b->port);
+}
+
+static inline void pcxi_globalwinon(struct channel *ch)
+{
+ outb_p(FEPMEM, (int)ch->board->port);
+}
+
+static inline void pcxi_rxwinon(struct channel *ch)
+{
+ outb_p(FEPMEM, (int)ch->board->port);
+}
+
+static inline void pcxi_txwinon(struct channel *ch)
+{
+ outb_p(FEPMEM, (int)ch->board->port);
+}
+
+static inline void pcxi_memoff(struct channel *ch)
+{
+ outb_p(0, (int)ch->board->port);
+}
+
+static inline void pcxi_assertgwinon(struct channel *ch)
+{
+ epcaassert(inb((int)ch->board->port) & FEPMEM, "Global memory off");
+}
+
+static inline void pcxi_assertmemoff(struct channel *ch)
+{
+ epcaassert(!(inb((int)ch->board->port) & FEPMEM), "Memory on");
+}
+
+
+/* ----------------------------------------------------------------------
+ Not all of the cards need specific memory windowing routines. Some
+ cards (Such as PCI) needs no windowing routines at all. We provide
+ these do nothing routines so that the same code base can be used.
+ The driver will ALWAYS call a windowing routine if it thinks it needs
+ to; regardless of the card. However, dependant on the card the routine
+ may or may not do anything.
+---------------------------------------------------------------------------*/
+
+static inline void dummy_memwinon(struct board_info *b, unsigned int win)
+{
+}
+
+static inline void dummy_memwinoff(struct board_info *b, unsigned int win)
+{
+}
+
+static inline void dummy_globalwinon(struct channel *ch)
+{
+}
+
+static inline void dummy_rxwinon(struct channel *ch)
+{
+}
+
+static inline void dummy_txwinon(struct channel *ch)
+{
+}
+
+static inline void dummy_memoff(struct channel *ch)
+{
+}
+
+static inline void dummy_assertgwinon(struct channel *ch)
+{
+}
+
+static inline void dummy_assertmemoff(struct channel *ch)
+{
+}
+
+/* ----------------- Begin verifyChannel function ----------------------- */
+static inline struct channel *verifyChannel(register struct tty_struct *tty)
+{ /* Begin verifyChannel */
+
+ /* --------------------------------------------------------------------
+ This routine basically provides a sanity check. It insures that
+ the channel returned is within the proper range of addresses as
+ well as properly initialized. If some bogus info gets passed in
+ through tty->driver_data this should catch it.
+ --------------------------------------------------------------------- */
+
+ if (tty)
+ { /* Begin if tty */
+
+ register struct channel *ch = (struct channel *)tty->driver_data;
+
+ if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs]))
+ {
+ if (ch->magic == EPCA_MAGIC)
+ return ch;
+ }
+
+ } /* End if tty */
+
+ /* Else return a NULL for invalid */
+ return NULL;
+
+} /* End verifyChannel */
+
+/* ------------------ Begin pc_sched_event ------------------------- */
+
+static inline void pc_sched_event(struct channel *ch, int event)
+{ /* Begin pc_sched_event */
+
+
+ /* ----------------------------------------------------------------------
+ We call this to schedule interrupt processing on some event. The
+ kernel sees our request and calls the related routine in OUR driver.
+ -------------------------------------------------------------------------*/
+
+ ch->event |= 1 << event;
+ queue_task(&ch->tqueue, &tq_scheduler);
+
+
+} /* End pc_sched_event */
+
+/* ------------------ Begin epca_error ------------------------- */
+
+static void epca_error(int line, char *msg)
+{ /* Begin epca_error */
+
+ printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg);
+ return;
+
+} /* End epca_error */
+
+/* ------------------ Begin pc_close ------------------------- */
+static void pc_close(struct tty_struct * tty, struct file * filp)
+{ /* Begin pc_close */
+
+ struct channel *ch;
+ unsigned long flags;
+
+ if (tty->driver.subtype == SERIAL_TYPE_INFO)
+ {
+ return;
+ }
+
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ { /* Begin if ch != NULL */
+
+ save_flags(flags);
+ cli();
+
+ if (tty_hung_up_p(filp))
+ {
+ restore_flags(flags);
+ return;
+ }
+
+ /* Check to see if the channel is open more than once */
+ if (ch->count-- > 1)
+ { /* Begin channel is open more than once */
+
+ /* -------------------------------------------------------------
+ Return without doing anything. Someone might still be using
+ the channel.
+ ---------------------------------------------------------------- */
+
+ restore_flags(flags);
+ return;
+ } /* End channel is open more than once */
+
+ /* Port open only once go ahead with shutdown & reset */
+
+ if (ch->count < 0)
+ {
+ ch->count = 0;
+ }
+
+ /* ---------------------------------------------------------------
+ Let the rest of the driver know the channel is being closed.
+ This becomes important if an open is attempted before close
+ is finished.
+ ------------------------------------------------------------------ */
+
+ ch->asyncflags |= ASYNC_CLOSING;
+
+ /* -------------------------------------------------------------
+ Save the termios structure, since this port may have
+ separate termios for callout and dialin.
+ --------------------------------------------------------------- */
+
+ if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
+ ch->normal_termios = *tty->termios;
+
+ if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
+ ch->callout_termios = *tty->termios;
+
+ tty->closing = 1;
+
+ if (ch->asyncflags & ASYNC_INITIALIZED)
+ {
+ /* Setup an event to indicate when the transmit buffer empties */
+ setup_empty_event(tty, ch);
+ tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
+ }
+
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+
+ shutdown(ch);
+ tty->closing = 0;
+ ch->event = 0;
+ ch->tty = NULL;
+
+ if (ch->blocked_open)
+ { /* Begin if blocked_open */
+
+ if (ch->close_delay)
+ {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + ch->close_delay;
+ schedule();
+ }
+
+ wake_up_interruptible(&ch->open_wait);
+
+ } /* End if blocked_open */
+
+ ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
+ ASYNC_CALLOUT_ACTIVE | ASYNC_CLOSING);
+ wake_up_interruptible(&ch->close_wait);
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+
+ restore_flags(flags);
+
+ } /* End if ch != NULL */
+
+} /* End pc_close */
+
+/* ------------------ Begin shutdown ------------------------- */
+
+static void shutdown(struct channel *ch)
+{ /* Begin shutdown */
+
+ unsigned long flags;
+ struct tty_struct *tty;
+ volatile struct board_chan *bc;
+
+ if (!(ch->asyncflags & ASYNC_INITIALIZED))
+ return;
+
+ save_flags(flags);
+ cli();
+ globalwinon(ch);
+
+ bc = ch->brdchan;
+
+ /* ------------------------------------------------------------------
+ In order for an event to be generated on the receipt of data the
+ idata flag must be set. Since we are shutting down, this is not
+ necessary clear this flag.
+ --------------------------------------------------------------------- */
+
+ if (bc)
+ bc->idata = 0;
+
+ tty = ch->tty;
+
+ /* ----------------------------------------------------------------
+ If we're a modem control device and HUPCL is on, drop RTS & DTR.
+ ------------------------------------------------------------------ */
+
+ if (tty->termios->c_cflag & HUPCL)
+ {
+ ch->omodem &= ~(ch->m_rts | ch->m_dtr);
+ fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
+ }
+
+ memoff(ch);
+
+ /* ------------------------------------------------------------------
+ The channel has officialy been closed. The next time it is opened
+ it will have to reinitialized. Set a flag to indicate this.
+ ---------------------------------------------------------------------- */
+
+ /* Prevent future Digi programmed interrupts from coming active */
+
+ ch->asyncflags &= ~ASYNC_INITIALIZED;
+ restore_flags(flags);
+
+} /* End shutdown */
+
+/* ------------------ Begin pc_hangup ------------------------- */
+
+static void pc_hangup(struct tty_struct *tty)
+{ /* Begin pc_hangup */
+
+ struct channel *ch;
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ { /* Begin if ch != NULL */
+
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+
+ shutdown(ch);
+
+#ifdef MODULE
+ if (ch->count)
+ MOD_DEC_USE_COUNT;
+#endif /* MODULE */
+
+
+ ch->tty = NULL;
+ ch->event = 0;
+ ch->count = 0;
+ restore_flags(flags);
+ ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | ASYNC_CALLOUT_ACTIVE);
+ wake_up_interruptible(&ch->open_wait);
+
+ } /* End if ch != NULL */
+
+} /* End pc_hangup */
+
+/* ------------------ Begin pc_write ------------------------- */
+
+static int pc_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int bytesAvailable)
+{ /* Begin pc_write */
+
+ register unsigned int head, tail;
+ register int dataLen;
+ register int size;
+ register int amountCopied;
+
+
+ struct channel *ch;
+ unsigned long flags;
+ int remain;
+ volatile struct board_chan *bc;
+
+
+ /* ----------------------------------------------------------------
+ pc_write is primarily called directly by the kernel routine
+ tty_write (Though it can also be called by put_char) found in
+ tty_io.c. pc_write is passed a line discipline buffer where
+ the data to be written out is stored. The line discipline
+ implementation itself is done at the kernel level and is not
+ brought into the driver.
+ ------------------------------------------------------------------- */
+
+ /* Stop users from hurting themselves on control minor */
+
+ if (tty->driver.subtype == SERIAL_TYPE_INFO)
+ {
+ return (0) ;
+ }
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) == NULL)
+ return 0;
+
+ /* Make a pointer to the channel data structure found on the board. */
+
+ bc = ch->brdchan;
+ size = ch->txbufsize;
+
+ if (from_user)
+ { /* Begin from_user */
+
+ save_flags(flags);
+ cli();
+
+ globalwinon(ch);
+
+ /* -----------------------------------------------------------------
+ Anding against size will wrap the pointer back to its begining
+ position if it is necessary. This will only work if size is
+ a power of 2 which should always be the case. Size is determined
+ by the cards on board FEP/OS.
+ -------------------------------------------------------------------- */
+
+ /* head refers to the next empty location in which data may be stored */
+
+ head = bc->tin & (size - 1);
+
+ /* tail refers to the next data byte to be transmitted */
+
+ tail = bc->tout;
+
+ /* Consider changing this to a do statement to make sure */
+
+ if (tail != bc->tout)
+ tail = bc->tout;
+
+ /* ------------------------------------------------------------------
+ Anding against size will wrap the pointer back to its begining
+ position if it is necessary. This will only work if size is
+ a power of 2 which should always be the case. Size is determined
+ by the cards on board FEP/OS.
+ --------------------------------------------------------------------- */
+
+ tail &= (size - 1);
+
+ /* -----------------------------------------------------------------
+ Two situations can affect how space in the transmit buffer
+ is calculated. You can have a situation where the transmit
+ in pointer (tin) head has wrapped around and actually has a
+ lower address than the transmit out pointer (tout) tail; or
+ the transmit in pointer (tin) head will not be wrapped around
+ yet, and have a higher address than the transmit out pointer
+ (tout) tail. Obviously space available in the transmit buffer
+ is calculated differently for each case.
+
+ Example 1:
+
+ Consider a 10 byte buffer where head is a pointer to the next
+ empty location in the buffer and tail is a pointer to the next
+ byte to transmit. In this example head will not have wrapped
+ around and therefore head > tail.
+
+ 0 1 2 3 4 5 6 7 8 9
+ tail head
+
+ The above diagram shows that buffer locations 2,3,4,5 and 6 have
+ data to be transmited, while head points at the next empty
+ location. To calculate how much space is available first we have
+ to determine if the head pointer (tin) has wrapped. To do this
+ compare the head pointer to the tail pointer, If head is equal
+ or greater than tail; then it has not wrapped; and the space may
+ be calculated by subtracting tail from head and then subtracting
+ that value from the buffers size. A one is subtracted from the
+ new value to indicate how much space is available between the
+ head pointer and end of buffer; as well as the space between the
+ begining of the buffer and the tail. If the head is not greater
+ or equal to the tail this indicates that the head has wrapped
+ around to the begining of the buffer. To calculate the space
+ available in this case simply subtract head from tail. This new
+ value minus one represents the space available betwwen the head
+ and tail pointers. In this example head (7) is greater than tail (2)
+ and therefore has not wrapped around. We find the space by first
+ subtracting tail from head (7-2=5). We then subtract this value
+ from the buffer size of ten and subtract one (10-5-1=4). The space
+ remaining is 4 bytes.
+
+ Example 2:
+
+ Consider a 10 byte buffer where head is a pointer to the next
+ empty location in the buffer and tail is a pointer to the next
+ byte to transmit. In this example head will wrapped around and
+ therefore head < tail.
+
+ 0 1 2 3 4 5 6 7 8 9
+ head tail
+
+ The above diagram shows that buffer locations 7,8,9,0 and 1 have
+ data to be transmited, while head points at the next empty
+ location. To find the space available we compare head to tail. If
+ head is not equal to, or greater than tail this indicates that head
+ has wrapped around. In this case head (2) is not equal to, or
+ greater than tail (7) and therefore has already wrapped around. To
+ calculate the available space between the two pointers we subtract
+ head from tail (7-2=5). We then subtract one from this new value
+ (5-1=4). We have 5 bytes empty remaining in the buffer. Unlike the
+ previous example these five bytes are located between the head and
+ tail pointers.
+
+ ----------------------------------------------------------------------- */
+
+ dataLen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);
+
+ /* ----------------------------------------------------------------------
+ In this case bytesAvailable has been passed into pc_write and
+ represents the amount of data that needs to be written. dataLen
+ represents the amount of space available on the card. Whichever
+ value is smaller will be the amount actually written.
+ bytesAvailable will then take on this newly calculated value.
+ ---------------------------------------------------------------------- */
+
+ bytesAvailable = MIN(dataLen, bytesAvailable);
+
+ /* First we read the data in from the file system into a temp buffer */
+
+ if (bytesAvailable)
+ { /* Begin bytesAvailable */
+
+ /* Can the user buffer be accessed at the moment ? */
+ if (verify_area(VERIFY_READ, (char*)buf, bytesAvailable))
+ bytesAvailable = 0; /* Can't do; try again later */
+ else /* Evidently it can, began transmission */
+ { /* Begin if area verified */
+ /* ---------------------------------------------------------------
+ The below function reads data from user memory. This routine
+ can not be used in an interrupt routine. (Because it may
+ generate a page fault) It can only be called while we can the
+ user context is accessible.
+
+ The prototype is :
+ inline void copy_from_user(void * to, const void * from,
+ unsigned long count);
+
+ You must include <asm/segment.h>
+ I also think (Check hackers guide) that optimization must
+ be turned ON. (Which sounds strange to me...)
+
+ Remember copy_from_user WILL generate a page fault if the
+ user memory being accessed has been swapped out. This can
+ cause this routine to temporarily sleep while this page
+ fault is occuring.
+
+ ----------------------------------------------------------------- */
+
+ copy_from_user(ch->tmp_buf, buf, bytesAvailable);
+
+ } /* End if area verified */
+
+ } /* End bytesAvailable */
+
+ /* ------------------------------------------------------------------
+ Set buf to this address for the moment. tmp_buf was allocated in
+ post_fep_init.
+ --------------------------------------------------------------------- */
+ buf = ch->tmp_buf;
+ memoff(ch);
+ restore_flags(flags);
+
+ } /* End from_user */
+
+ /* All data is now local */
+
+ amountCopied = 0;
+ save_flags(flags);
+ cli();
+
+ globalwinon(ch);
+
+ head = bc->tin & (size - 1);
+ tail = bc->tout;
+
+ if (tail != bc->tout)
+ tail = bc->tout;
+ tail &= (size - 1);
+
+ /* If head >= tail, head has not wrapped around. */
+ if (head >= tail)
+ { /* Begin head has not wrapped */
+
+ /* ---------------------------------------------------------------
+ remain (much like dataLen above) represents the total amount of
+ space available on the card for data. Here dataLen represents
+ the space existing between the head pointer and the end of
+ buffer. This is important because a memcpy cannot be told to
+ automatically wrap around when it hits the buffer end.
+ ------------------------------------------------------------------ */
+
+ dataLen = size - head;
+ remain = size - (head - tail) - 1;
+
+ } /* End head has not wrapped */
+ else
+ { /* Begin head has wrapped around */
+
+ remain = tail - head - 1;
+ dataLen = remain;
+
+ } /* End head has wrapped around */
+
+ /* -------------------------------------------------------------------
+ Check the space on the card. If we have more data than
+ space; reduce the amount of data to fit the space.
+ ---------------------------------------------------------------------- */
+
+ bytesAvailable = MIN(remain, bytesAvailable);
+
+ txwinon(ch);
+ while (bytesAvailable > 0)
+ { /* Begin while there is data to copy onto card */
+
+ /* -----------------------------------------------------------------
+ If head is not wrapped, the below will make sure the first
+ data copy fills to the end of card buffer.
+ ------------------------------------------------------------------- */
+
+ dataLen = MIN(bytesAvailable, dataLen);
+ memcpy(ch->txptr + head, buf, dataLen);
+ buf += dataLen;
+ head += dataLen;
+ amountCopied += dataLen;
+ bytesAvailable -= dataLen;
+
+ if (head >= size)
+ {
+ head = 0;
+ dataLen = tail;
+ }
+
+ } /* End while there is data to copy onto card */
+
+ ch->statusflags |= TXBUSY;
+ globalwinon(ch);
+ bc->tin = head;
+
+ if ((ch->statusflags & LOWWAIT) == 0)
+ {
+ ch->statusflags |= LOWWAIT;
+ bc->ilow = 1;
+ }
+ memoff(ch);
+ restore_flags(flags);
+
+ return(amountCopied);
+
+} /* End pc_write */
+
+/* ------------------ Begin pc_put_char ------------------------- */
+
+static void pc_put_char(struct tty_struct *tty, unsigned char c)
+{ /* Begin pc_put_char */
+
+
+ pc_write(tty, 0, &c, 1);
+ return;
+
+} /* End pc_put_char */
+
+/* ------------------ Begin pc_write_room ------------------------- */
+
+static int pc_write_room(struct tty_struct *tty)
+{ /* Begin pc_write_room */
+
+ int remain;
+ struct channel *ch;
+ unsigned long flags;
+ unsigned int head, tail;
+ volatile struct board_chan *bc;
+
+ remain = 0;
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ {
+ save_flags(flags);
+ cli();
+ globalwinon(ch);
+
+ bc = ch->brdchan;
+ head = bc->tin & (ch->txbufsize - 1);
+ tail = bc->tout;
+
+ if (tail != bc->tout)
+ tail = bc->tout;
+ /* Wrap tail if necessary */
+ tail &= (ch->txbufsize - 1);
+
+ if ((remain = tail - head - 1) < 0 )
+ remain += ch->txbufsize;
+
+ if (remain && (ch->statusflags & LOWWAIT) == 0)
+ {
+ ch->statusflags |= LOWWAIT;
+ bc->ilow = 1;
+ }
+ memoff(ch);
+ restore_flags(flags);
+ }
+
+ /* Return how much room is left on card */
+ return remain;
+
+} /* End pc_write_room */
+
+/* ------------------ Begin pc_chars_in_buffer ---------------------- */
+
+static int pc_chars_in_buffer(struct tty_struct *tty)
+{ /* Begin pc_chars_in_buffer */
+
+ int chars;
+ unsigned int ctail, head, tail;
+ int remain;
+ unsigned long flags;
+ struct channel *ch;
+ volatile struct board_chan *bc;
+
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) == NULL)
+ return(0);
+
+ save_flags(flags);
+ cli();
+ globalwinon(ch);
+
+ bc = ch->brdchan;
+ tail = bc->tout;
+ head = bc->tin;
+ ctail = ch->mailbox->cout;
+
+ if (tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
+ chars = 0;
+ else
+ { /* Begin if some space on the card has been used */
+
+ head = bc->tin & (ch->txbufsize - 1);
+ tail &= (ch->txbufsize - 1);
+
+ /* --------------------------------------------------------------
+ The logic here is basically opposite of the above pc_write_room
+ here we are finding the amount of bytes in the buffer filled.
+ Not the amount of bytes empty.
+ ------------------------------------------------------------------- */
+
+ if ((remain = tail - head - 1) < 0 )
+ remain += ch->txbufsize;
+
+ chars = (int)(ch->txbufsize - remain);
+
+ /* -------------------------------------------------------------
+ Make it possible to wakeup anything waiting for output
+ in tty_ioctl.c, etc.
+
+ If not already set. Setup an event to indicate when the
+ transmit buffer empties
+ ----------------------------------------------------------------- */
+
+ if (!(ch->statusflags & EMPTYWAIT))
+ setup_empty_event(tty,ch);
+
+ } /* End if some space on the card has been used */
+
+ memoff(ch);
+ restore_flags(flags);
+
+ /* Return number of characters residing on card. */
+ return(chars);
+
+} /* End pc_chars_in_buffer */
+
+/* ------------------ Begin pc_flush_buffer ---------------------- */
+
+static void pc_flush_buffer(struct tty_struct *tty)
+{ /* Begin pc_flush_buffer */
+
+ unsigned int tail;
+ unsigned long flags;
+ struct channel *ch;
+ volatile struct board_chan *bc;
+
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) == NULL)
+ return;
+
+ save_flags(flags);
+ cli();
+
+ globalwinon(ch);
+
+ bc = ch->brdchan;
+ tail = bc->tout;
+
+ /* Have FEP move tout pointer; effectively flushing transmit buffer */
+
+ fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
+
+ memoff(ch);
+ 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);
+
+} /* End pc_flush_buffer */
+
+/* ------------------ Begin pc_flush_chars ---------------------- */
+
+static void pc_flush_chars(struct tty_struct *tty)
+{ /* Begin pc_flush_chars */
+
+ struct channel * ch;
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ {
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ /* ----------------------------------------------------------------
+ If not already set and the transmitter is busy setup an event
+ to indicate when the transmit empties.
+ ------------------------------------------------------------------- */
+
+ if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
+ setup_empty_event(tty,ch);
+
+ restore_flags(flags);
+ }
+
+} /* End pc_flush_chars */
+
+/* ------------------ Begin block_til_ready ---------------------- */
+
+static int block_til_ready(struct tty_struct *tty,
+ struct file *filp, struct channel *ch)
+{ /* Begin block_til_ready */
+
+ struct wait_queue wait = {current, NULL};
+ int retval, do_clocal = 0;
+ unsigned long flags;
+
+
+ if (tty_hung_up_p(filp))
+ {
+ if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+ return(retval);
+ }
+
+ /* -----------------------------------------------------------------
+ If the device is in the middle of being closed, then block
+ until it's done, and then try again.
+ -------------------------------------------------------------------- */
+ if (ch->asyncflags & ASYNC_CLOSING)
+ {
+ interruptible_sleep_on(&ch->close_wait);
+
+ if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+ return -EAGAIN;
+ else
+ return -ERESTARTSYS;
+ }
+
+ /* -----------------------------------------------------------------
+ If this is a callout device, then just make sure the normal
+ device isn't being used.
+ -------------------------------------------------------------------- */
+
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT)
+ { /* A cud device has been opened */
+ if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
+ return -EBUSY;
+
+ if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+ (ch->asyncflags & ASYNC_SESSION_LOCKOUT) &&
+ (ch->session != current->session))
+ return -EBUSY;
+
+ if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+ (ch->asyncflags & ASYNC_PGRP_LOCKOUT) &&
+ (ch->pgrp != current->pgrp))
+ return -EBUSY;
+
+ ch->asyncflags |= ASYNC_CALLOUT_ACTIVE;
+
+ return 0;
+ } /* End a cud device has been opened */
+
+ if (filp->f_flags & O_NONBLOCK)
+ {
+ /* -----------------------------------------------------------------
+ If non-blocking mode is set, then make the check up front
+ and then exit.
+ -------------------------------------------------------------------- */
+
+ if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
+ return -EBUSY;
+
+ ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+
+ return 0;
+ }
+
+
+ if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
+ {
+ if (ch->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ }
+ else
+ {
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+ }
+
+ /* Block waiting for the carrier detect and the line to become free */
+
+ retval = 0;
+ add_wait_queue(&ch->open_wait, &wait);
+ save_flags(flags);
+ cli();
+
+
+ /* We dec count so that pc_close will know when to free things */
+ if (!tty_hung_up_p(filp))
+ ch->count--;
+
+ restore_flags(flags);
+
+ ch->blocked_open++;
+
+ while(1)
+ { /* Begin forever while */
+
+ current->state = TASK_INTERRUPTIBLE;
+
+ if (tty_hung_up_p(filp) ||
+ !(ch->asyncflags & ASYNC_INITIALIZED))
+ {
+ if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+ break;
+ }
+
+ if (!(ch->asyncflags & ASYNC_CLOSING) &&
+ !(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+ (do_clocal || (ch->imodem & ch->dcd)))
+ break;
+
+ if (current->signal & ~current->blocked)
+ {
+ retval = -ERESTARTSYS;
+ break;
+ }
+
+ /* ---------------------------------------------------------------
+ Allow someone else to be scheduled. We will occasionaly go
+ through this loop until one of the above conditions change.
+ The below schedule call will allow other processes to enter and
+ prevent this loop from hogging the cpu.
+ ------------------------------------------------------------------ */
+ schedule();
+
+ } /* End forever while */
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&ch->open_wait, &wait);
+ cli();
+ if (!tty_hung_up_p(filp))
+ ch->count++;
+ restore_flags(flags);
+
+ ch->blocked_open--;
+
+ if (retval)
+ return retval;
+
+ ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+
+ return 0;
+
+} /* End block_til_ready */
+
+/* ------------------ Begin pc_open ---------------------- */
+
+static int pc_open(struct tty_struct *tty, struct file * filp)
+{ /* Begin pc_open */
+
+ struct channel *ch;
+ unsigned long flags;
+ int line, retval, boardnum;
+ volatile struct board_chan *bc;
+ volatile unsigned int head;
+
+ /* Nothing "real" happens in open of control device */
+
+ if (tty->driver.subtype == SERIAL_TYPE_INFO)
+ {
+ return (0) ;
+ }
+
+ line = MINOR(tty->device) - tty->driver.minor_start;
+ if (line < 0 || line >= nbdevs)
+ {
+ printk(KERN_ERR "<Error> - pc_open : line out of range in pc_open\n");
+ tty->driver_data = NULL;
+ return(-ENODEV);
+ }
+
+#ifdef MODULE
+
+ MOD_INC_USE_COUNT;
+
+#endif
+
+ ch = &digi_channels[line];
+ boardnum = ch->boardnum;
+
+ /* Check status of board configured in system. */
+
+ /* -----------------------------------------------------------------
+ I check to see if the epca_setup routine detected an user error.
+ It might be better to put this in pc_init, but for the moment it
+ goes here.
+ ---------------------------------------------------------------------- */
+
+ if (invalid_lilo_config)
+ {
+ if (setup_error_code & INVALID_BOARD_TYPE)
+ printk(KERN_ERR "<Error> - pc_open: Invalid board type specified in LILO command\n");
+
+ if (setup_error_code & INVALID_NUM_PORTS)
+ printk(KERN_ERR "<Error> - pc_open: Invalid number of ports specified in LILO command\n");
+
+ if (setup_error_code & INVALID_MEM_BASE)
+ printk(KERN_ERR "<Error> - pc_open: Invalid board memory address specified in LILO command\n");
+
+ if (setup_error_code & INVALID_PORT_BASE)
+ printk(KERN_ERR "<Error> - pc_open: Invalid board port address specified in LILO command\n");
+
+ if (setup_error_code & INVALID_BOARD_STATUS)
+ printk(KERN_ERR "<Error> - pc_open: Invalid board status specified in LILO command\n");
+
+ if (setup_error_code & INVALID_ALTPIN)
+ printk(KERN_ERR "<Error> - pc_open: Invalid board altpin specified in LILO command\n");
+
+ tty->driver_data = NULL; /* Mark this device as 'down' */
+ return(-ENODEV);
+ }
+
+ if ((boardnum >= num_cards) || (boards[boardnum].status == DISABLED))
+ {
+ tty->driver_data = NULL; /* Mark this device as 'down' */
+ return(-ENODEV);
+ }
+
+ if (( bc = ch->brdchan) == 0)
+ {
+ tty->driver_data = NULL;
+ return(-ENODEV);
+ }
+
+ /* ------------------------------------------------------------------
+ Every time a channel is opened, increment a counter. This is
+ necessary because we do not wish to flush and shutdown the channel
+ until the last app holding the channel open, closes it.
+ --------------------------------------------------------------------- */
+
+ ch->count++;
+
+ /* ----------------------------------------------------------------
+ Set a kernel structures pointer to our local channel
+ structure. This way we can get to it when passed only
+ a tty struct.
+ ------------------------------------------------------------------ */
+
+ tty->driver_data = ch;
+
+ /* ----------------------------------------------------------------
+ If this is the first time the channel has been opened, initialize
+ the tty->termios struct otherwise let pc_close handle it.
+ -------------------------------------------------------------------- */
+
+ /* Should this be here except for SPLIT termios ? */
+ if (ch->count == 1)
+ {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = ch->normal_termios;
+ else
+ *tty->termios = ch->callout_termios;
+ }
+
+ ch->session = current->session;
+ ch->pgrp = current->pgrp;
+
+ save_flags(flags);
+ cli();
+
+ globalwinon(ch);
+ ch->statusflags = 0;
+
+ /* Save boards current modem status */
+ ch->imodem = bc->mstat;
+
+ /* ----------------------------------------------------------------
+ Set receive head and tail ptrs to each other. This indicates
+ no data available to read.
+ ----------------------------------------------------------------- */
+ head = bc->rin;
+ bc->rout = head;
+
+ /* Set the channels associated tty structure */
+ ch->tty = tty;
+
+ /* -----------------------------------------------------------------
+ The below routine generally sets up parity, baud, flow control
+ issues, etc.... It effect both control flags and input flags.
+ -------------------------------------------------------------------- */
+ epcaparam(tty,ch);
+
+ ch->asyncflags |= ASYNC_INITIALIZED;
+ memoff(ch);
+
+ restore_flags(flags);
+
+ retval = block_til_ready(tty, filp, ch);
+ if (retval)
+ {
+ return retval;
+ }
+
+ /* -------------------------------------------------------------
+ Set this again in case a hangup set it to zero while this
+ open() was waiting for the line...
+ --------------------------------------------------------------- */
+ ch->tty = tty;
+
+ save_flags(flags);
+ cli();
+ globalwinon(ch);
+
+ /* Enable Digi Data events */
+ bc->idata = 1;
+
+ memoff(ch);
+ restore_flags(flags);
+
+ return 0;
+
+} /* End pc_open */
+
+#ifdef MODULE
+/* -------------------- Begin init_module ---------------------- */
+int init_module()
+{ /* Begin init_module */
+
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ pc_init();
+
+ restore_flags(flags);
+
+ return(0);
+} /* End init_module */
+
+#endif
+#ifdef MODULE
+/* -------------------- Begin cleanup_module ---------------------- */
+void cleanup_module()
+{ /* Begin cleanup_module */
+
+ int count, crd;
+ struct board_info *bd;
+ struct channel *ch;
+ unsigned long flags;
+
+
+ save_flags(flags);
+ cli();
+
+ timer_table[DIGI_TIMER].fn = 0;
+
+ if ((tty_unregister_driver(&pc_driver)) ||
+ (tty_unregister_driver(&pc_callout)))
+ {
+ printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n");
+ restore_flags(flags);
+ return;
+ }
+
+ for (crd = 0; crd < num_cards; crd++)
+ { /* Begin for each card */
+
+ bd = &boards[crd];
+
+ if (!bd)
+ { /* Begin sanity check */
+ printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
+ return;
+ } /* End sanity check */
+
+ ch = card_ptr[crd];
+
+ for (count = 0; count < bd->numports; count++, ch++)
+ { /* Begin for each port */
+
+ if (ch)
+ {
+ if (ch->tty)
+ tty_hangup(ch->tty);
+ kfree_s(ch->tmp_buf, ch->txbufsize);
+ }
+
+ } /* End for each port */
+ } /* End for each card */
+
+
+ restore_flags(flags);
+
+} /* End cleanup_module */
+#endif /* MODULE */
+
+/* ------------------ Begin pc_init ---------------------- */
+
+int pc_init(void)
+{ /* Begin pc_init */
+
+ /* ----------------------------------------------------------------
+ pc_init is called by the operating system during boot up prior to
+ any open calls being made. In the older versions of Linux (Prior
+ to 2.0.0) an entry is made into tty_io.c. A pointer to the last
+ memory location (from kernel space) used (kmem_start) is passed
+ to pc_init. It is pc_inits responsibility to modify this value
+ for any memory that the Digi driver might need and then return
+ this value to the operating system. For example if the driver
+ wishes to allocate 1K of kernel memory, pc_init would return
+ (kmem_start + 1024). This memory (Between kmem_start and kmem_start
+ + 1024) would then be available for use exclusively by the driver.
+ In this case our driver does not allocate any of this kernel
+ memory.
+ ------------------------------------------------------------------*/
+
+ ulong flags, save_loops_per_sec;
+ int crd;
+ struct board_info *bd;
+ unsigned char board_id = 0;
+
+
+#ifdef ENABLE_PCI
+ int pci_boards_found, pci_count;
+
+ pci_count = 0;
+#endif /* ENABLE_PCI */
+
+ /* -----------------------------------------------------------------------
+ If epca_setup has not been ran by LILO set num_cards to defaults; copy
+ board structure defined by digiConfig into drivers board structure.
+ Note : If LILO has ran epca_setup then epca_setup will handle defining
+ num_cards as well as copying the data into the board structure.
+ -------------------------------------------------------------------------- */
+ if (!liloconfig)
+ { /* Begin driver has been configured via. epcaconfig */
+
+ nbdevs = NBDEVS;
+ num_cards = NUMCARDS;
+ memcpy((void *)&boards, (void *)&static_boards,
+ (sizeof(struct board_info) * NUMCARDS));
+ } /* End driver has been configured via. epcaconfig */
+
+ /* -----------------------------------------------------------------
+ Note : If lilo was used to configure the driver and the
+ ignore epcaconfig option was choosen (digiepca=2) then
+ nbdevs and num_cards will equal 0 at this point. This is
+ okay; PCI cards will still be picked up if detected.
+ --------------------------------------------------------------------- */
+
+ /* -----------------------------------------------------------
+ Set up interrupt, we will worry about memory allocation in
+ post_fep_init.
+ --------------------------------------------------------------- */
+
+
+ printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);
+
+#ifdef ENABLE_PCI
+
+ /* ------------------------------------------------------------------
+ NOTE : This code assumes that the number of ports found in
+ the boards array is correct. This could be wrong if
+ the card in question is PCI (And therefore has no ports
+ entry in the boards structure.) The rest of the
+ information will be valid for PCI because the begining
+ of pc_init scans for PCI and determines i/o and base
+ memory addresses. I am not sure if it is possible to
+ read the number of ports supported by the card prior to
+ it being booted (Since that is the state it is in when
+ pc_init is run). Because it is not possible to query the
+ number of supported ports until after the card has booted;
+ we are required to calculate the card_ptrs as the card is
+ is initialized (Inside post_fep_init). The negative thing
+ about this approach is that digiDload's call to GET_INFO
+ will have a bad port value. (Since this is called prior
+ to post_fep_init.)
+
+ --------------------------------------------------------------------- */
+
+ pci_boards_found = 0;
+ if (pcibios_present())
+ {
+ if(num_cards < MAXBOARDS)
+ pci_boards_found += init_PCI(num_cards);
+ num_cards += pci_boards_found;
+ }
+ else
+ {
+ printk(KERN_ERR "<Error> - No PCI BIOS found\n");
+ }
+
+#endif /* ENABLE_PCI */
+
+ memset(&pc_driver, 0, sizeof(struct tty_driver));
+ memset(&pc_callout, 0, sizeof(struct tty_driver));
+ memset(&pc_info, 0, sizeof(struct tty_driver));
+
+ pc_driver.magic = TTY_DRIVER_MAGIC;
+ pc_driver.name = "ttyD";
+ pc_driver.major = DIGI_MAJOR;
+ pc_driver.minor_start = 0;
+ pc_driver.num = MAX_ALLOC;
+ pc_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ pc_driver.subtype = SERIAL_TYPE_NORMAL;
+ pc_driver.init_termios = tty_std_termios;
+ pc_driver.init_termios.c_iflag = 0;
+ pc_driver.init_termios.c_oflag = 0;
+
+ pc_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
+ pc_driver.init_termios.c_lflag = 0;
+ pc_driver.flags = TTY_DRIVER_REAL_RAW;
+ pc_driver.refcount = &pc_refcount;
+ pc_driver.table = pc_table;
+
+ /* pc_termios is an array of pointers pointing at termios structs */
+ /* The below should get the first pointer */
+ pc_driver.termios = pc_termios;
+ pc_driver.termios_locked = pc_termios_locked;
+
+ /* ------------------------------------------------------------------
+ Setup entry points for the driver. These are primarily called by
+ the kernel in tty_io.c and n_tty.c
+ --------------------------------------------------------------------- */
+
+ pc_driver.open = pc_open;
+ pc_driver.close = pc_close;
+ pc_driver.write = pc_write;
+ pc_driver.write_room = pc_write_room;
+ pc_driver.flush_buffer = pc_flush_buffer;
+ pc_driver.chars_in_buffer = pc_chars_in_buffer;
+ pc_driver.flush_chars = pc_flush_chars;
+ pc_driver.put_char = pc_put_char;
+ pc_driver.ioctl = pc_ioctl;
+ pc_driver.set_termios = pc_set_termios;
+ pc_driver.stop = pc_stop;
+ pc_driver.start = pc_start;
+ pc_driver.throttle = pc_throttle;
+ pc_driver.unthrottle = pc_unthrottle;
+ pc_driver.hangup = pc_hangup;
+ pc_callout = pc_driver;
+
+ pc_callout.name = "cud";
+ pc_callout.major = DIGICU_MAJOR;
+ pc_callout.minor_start = 0;
+ pc_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
+ pc_callout.subtype = SERIAL_TYPE_CALLOUT;
+
+ pc_info = pc_driver;
+ pc_info.name = "digiCtl";
+ pc_info.major = DIGIINFOMAJOR;
+ pc_info.minor_start = 0;
+ pc_info.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+ pc_info.subtype = SERIAL_TYPE_INFO;
+
+
+ /* ---------------------------------------------------------------------
+ loops_per_sec hasn't been set at this point :-(, so fake it out...
+ I set it, so that I can use the __delay() function.
+ ------------------------------------------------------------------------ */
+ save_loops_per_sec = loops_per_sec;
+ loops_per_sec = 13L * 500000L;
+
+ save_flags(flags);
+ cli();
+
+ for (crd = 0; crd < num_cards; crd++)
+ { /* Begin for each card */
+
+ /* ------------------------------------------------------------------
+ This is where the appropriate memory handlers for the hardware is
+ set. Everything at runtime blindly jumps through these vectors.
+ ---------------------------------------------------------------------- */
+
+ /* defined in epcaconfig.h */
+ bd = &boards[crd];
+
+ switch (bd->type)
+ { /* Begin switch on bd->type {board type} */
+ case PCXEM:
+ case EISAXEM:
+ bd->memwinon = pcxem_memwinon ;
+ bd->memwinoff = pcxem_memwinoff ;
+ bd->globalwinon = pcxem_globalwinon ;
+ bd->txwinon = pcxem_txwinon ;
+ bd->rxwinon = pcxem_rxwinon ;
+ bd->memoff = pcxem_memoff ;
+ bd->assertgwinon = dummy_assertgwinon;
+ bd->assertmemoff = dummy_assertmemoff;
+ break;
+
+ case PCIXEM:
+ case PCIXRJ:
+ case PCIXR:
+ bd->memwinon = dummy_memwinon;
+ bd->memwinoff = dummy_memwinoff;
+ bd->globalwinon = dummy_globalwinon;
+ bd->txwinon = dummy_txwinon;
+ bd->rxwinon = dummy_rxwinon;
+ bd->memoff = dummy_memoff;
+ bd->assertgwinon = dummy_assertgwinon;
+ bd->assertmemoff = dummy_assertmemoff;
+ break;
+
+ case PCXE:
+ case PCXEVE:
+
+ bd->memwinon = pcxe_memwinon;
+ bd->memwinoff = pcxe_memwinoff;
+ bd->globalwinon = pcxe_globalwinon;
+ bd->txwinon = pcxe_txwinon;
+ bd->rxwinon = pcxe_rxwinon;
+ bd->memoff = pcxe_memoff;
+ bd->assertgwinon = dummy_assertgwinon;
+ bd->assertmemoff = dummy_assertmemoff;
+ break;
+
+ case PCXI:
+ case PC64XE:
+
+ bd->memwinon = pcxi_memwinon;
+ bd->memwinoff = pcxi_memwinoff;
+ bd->globalwinon = pcxi_globalwinon;
+ bd->txwinon = pcxi_txwinon;
+ bd->rxwinon = pcxi_rxwinon;
+ bd->memoff = pcxi_memoff;
+ bd->assertgwinon = pcxi_assertgwinon;
+ bd->assertmemoff = pcxi_assertmemoff;
+ break;
+
+ default:
+ break;
+
+ } /* End switch on bd->type */
+
+ /* ---------------------------------------------------------------
+ Some cards need a memory segment to be defined for use in
+ transmit and receive windowing operations. These boards
+ are listed in the below switch. In the case of the XI the
+ amount of memory on the board is variable so the memory_seg
+ is also variable. This code determines what they segment
+ should be.
+ ----------------------------------------------------------------- */
+
+ switch (bd->type)
+ { /* Begin switch on bd->type {board type} */
+
+ case PCXE:
+ case PCXEVE:
+ case PC64XE:
+ bd->memory_seg = 0xf000;
+ break;
+
+ case PCXI:
+ board_id = inb((int)bd->port);
+ if ((board_id & 0x1) == 0x1)
+ { /* Begin its an XI card */
+
+ /* Is it a 64K board */
+ if ((board_id & 0x30) == 0)
+ bd->memory_seg = 0xf000;
+
+ /* Is it a 128K board */
+ if ((board_id & 0x30) == 0x10)
+ bd->memory_seg = 0xe000;
+
+ /* Is is a 256K board */
+ if ((board_id & 0x30) == 0x20)
+ bd->memory_seg = 0xc000;
+
+ /* Is it a 512K board */
+ if ((board_id & 0x30) == 0x30)
+ bd->memory_seg = 0x8000;
+
+ } /* End it is an XI card */
+ else
+ {
+ printk(KERN_ERR "<Error> - Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
+ }
+ break;
+
+ } /* End switch on bd->type */
+
+ } /* End for each card */
+
+ if (tty_register_driver(&pc_driver))
+ panic("Couldn't register Digi PC/ driver");
+
+ if (tty_register_driver(&pc_callout))
+ panic("Couldn't register Digi PC/ callout");
+
+ if (tty_register_driver(&pc_info))
+ panic("Couldn't register Digi PC/ info ");
+
+ loops_per_sec = save_loops_per_sec; /* reset it to what it should be */
+
+ /* -------------------------------------------------------------------
+ Start up the poller to check for events on all enabled boards
+ ---------------------------------------------------------------------- */
+
+ timer_table[DIGI_TIMER].fn = (void *)epcapoll;
+ timer_table[DIGI_TIMER].expires = 0;
+
+ restore_flags(flags);
+
+ timer_active |= 1 << DIGI_TIMER;
+ return 0;
+
+} /* End pc_init */
+
+/* ------------------ Begin post_fep_init ---------------------- */
+
+static void post_fep_init(unsigned int crd)
+{ /* Begin post_fep_init */
+
+ int i;
+ unchar *memaddr;
+ volatile struct global_data *gd;
+ struct board_info *bd;
+ volatile struct board_chan *bc;
+ struct channel *ch;
+ int shrinkmem = 0, lowwater ;
+
+ /* -------------------------------------------------------------
+ This call is made by the user via. the ioctl call DIGI_INIT.
+ It is resposible for setting up all the card specific stuff.
+ ---------------------------------------------------------------- */
+ bd = &boards[crd];
+
+ /* -----------------------------------------------------------------
+ If this is a PCI board, get the port info. Remember PCI cards
+ do not have entries into the epcaconfig.h file, so we can't get
+ the number of ports from it. Unfortunetly, this means that anyone
+ doing a DIGI_GETINFO before the board has booted will get an invalid
+ number of ports returned (It should return 0). Calls to DIGI_GETINFO
+ after DIGI_INIT has been called will return the proper values.
+ ------------------------------------------------------------------- */
+
+ if (bd->type >= PCIXEM) /* If the board in question is PCI */
+ { /* Begin get PCI number of ports */
+
+ /* --------------------------------------------------------------------
+ Below we use XEMPORTS as a memory offset regardless of which PCI
+ card it is. This is because all of the supported PCI cards have
+ the same memory offset for the channel data. This will have to be
+ changed if we ever develop a PCI/XE card. NOTE : The FEP manual
+ states that the port offset is 0xC22 as opposed to 0xC02. This is
+ only true for PC/XE, and PC/XI cards; not for the XEM, or CX series.
+ On the PCI cards the number of ports is determined by reading a
+ ID PROM located in the box attached to the card. The card can then
+ determine the index the id to determine the number of ports available.
+ (FYI - The id should be located at 0x1ac (And may use up to 4 bytes
+ if the box in question is a XEM or CX)).
+ ------------------------------------------------------------------------ */
+
+ bd->numports = (unsigned short)*(unsigned char *)bus_to_virt((unsigned long)
+ (bd->re_map_membase + XEMPORTS));
+
+
+ epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");
+ nbdevs += (bd->numports);
+
+ } /* End get PCI number of ports */
+
+ if (crd != 0)
+ card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;
+ else
+ card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */
+
+ ch = card_ptr[crd];
+
+
+ epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");
+
+ if (bd->membase < (unsigned char *)0x100000)
+ memaddr = (unchar *) bd->membase;
+ else /* Else get special mapped memory above RAM */
+ memaddr = (unchar *)bd->re_map_membase;
+
+ /*
+ The below command is necessary because newer kernels (2.1.x and
+ up) do not have a 1:1 virtual to physical mapping. The below
+ call adjust for that.
+ */
+
+ memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);
+
+ /* -----------------------------------------------------------------
+ The below assignment will set bc to point at the BEGINING of
+ the cards channel structures. For 1 card there will be between
+ 8 and 64 of these structures.
+ -------------------------------------------------------------------- */
+
+ bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
+
+ /* -------------------------------------------------------------------
+ The below assignment will set gd to point at the BEGINING of
+ global memory address 0xc00. The first data in that global
+ memory actually starts at address 0xc1a. The command in
+ pointer begins at 0xd10.
+ ---------------------------------------------------------------------- */
+
+ gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
+
+ /* --------------------------------------------------------------------
+ XEPORTS (address 0xc22) points at the number of channels the
+ card supports. (For 64XE, XI, XEM, and XR use 0xc02)
+ ----------------------------------------------------------------------- */
+
+ if (((bd->type == PCXEVE) | (bd->type == PCXE)) &&
+ (*(ushort *)((ulong)memaddr + XEPORTS) < 3))
+ shrinkmem = 1;
+ if (bd->type < PCIXEM)
+ request_region((int)bd->port, 4, board_desc[bd->type]);
+
+ memwinon(bd, 0);
+
+ /* --------------------------------------------------------------------
+ Remember ch is the main drivers channels structure, while bc is
+ the cards channel structure.
+ ------------------------------------------------------------------------ */
+
+ /* For every port on the card do ..... */
+
+ for (i = 0; i < bd->numports; i++, ch++, bc++)
+ { /* Begin for each port */
+
+ ch->brdchan = bc;
+ ch->mailbox = gd;
+ ch->tqueue.routine = do_softint;
+ ch->tqueue.data = ch;
+ ch->board = &boards[crd];
+
+ switch (bd->type)
+ { /* Begin switch bd->type */
+
+ /* ----------------------------------------------------------------
+ Since some of the boards use different bitmaps for their
+ control signals we cannot hard code these values and retain
+ portability. We virtualize this data here.
+ ------------------------------------------------------------------- */
+ case EISAXEM:
+ case PCXEM:
+ case PCIXEM:
+ case PCIXRJ:
+ case PCIXR:
+ ch->m_rts = 0x02 ;
+ ch->m_dcd = 0x80 ;
+ ch->m_dsr = 0x20 ;
+ ch->m_cts = 0x10 ;
+ ch->m_ri = 0x40 ;
+ ch->m_dtr = 0x01 ;
+ break;
+
+ case PCXE:
+ case PCXEVE:
+ case PCXI:
+ case PC64XE:
+ ch->m_rts = 0x02 ;
+ ch->m_dcd = 0x08 ;
+ ch->m_dsr = 0x10 ;
+ ch->m_cts = 0x20 ;
+ ch->m_ri = 0x40 ;
+ ch->m_dtr = 0x80 ;
+ break;
+
+ } /* End switch bd->type */
+
+ if (boards[crd].altpin)
+ {
+ ch->dsr = ch->m_dcd;
+ ch->dcd = ch->m_dsr;
+ ch->digiext.digi_flags |= DIGI_ALTPIN;
+ }
+ else
+ {
+ ch->dcd = ch->m_dcd;
+ ch->dsr = ch->m_dsr;
+ }
+
+ ch->boardnum = crd;
+ ch->channelnum = i;
+ ch->magic = EPCA_MAGIC;
+ ch->tty = 0;
+
+ if (shrinkmem)
+ {
+ fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
+ shrinkmem = 0;
+ }
+
+ switch (bd->type)
+ { /* Begin switch bd->type */
+
+ case PCIXEM:
+ case PCIXRJ:
+ case PCIXR:
+ /* Cover all the 2MEG cards */
+ ch->txptr = memaddr + (((bc->tseg) << 4) & 0x1fffff);
+ ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x1fffff);
+ ch->txwin = FEPWIN | ((bc->tseg) >> 11);
+ ch->rxwin = FEPWIN | ((bc->rseg) >> 11);
+ break;
+
+ case PCXEM:
+ case EISAXEM:
+ /* Cover all the 32K windowed cards */
+ /* Mask equal to window size - 1 */
+ ch->txptr = memaddr + (((bc->tseg) << 4) & 0x7fff);
+ ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x7fff);
+ ch->txwin = FEPWIN | ((bc->tseg) >> 11);
+ ch->rxwin = FEPWIN | ((bc->rseg) >> 11);
+ break;
+
+ case PCXEVE:
+ case PCXE:
+ ch->txptr = memaddr + (((bc->tseg - bd->memory_seg) << 4) & 0x1fff);
+ ch->txwin = FEPWIN | ((bc->tseg - bd->memory_seg) >> 9);
+ ch->rxptr = memaddr + (((bc->rseg - bd->memory_seg) << 4) & 0x1fff);
+ ch->rxwin = FEPWIN | ((bc->rseg - bd->memory_seg) >>9 );
+ break;
+
+ case PCXI:
+ case PC64XE:
+ ch->txptr = memaddr + ((bc->tseg - bd->memory_seg) << 4);
+ ch->rxptr = memaddr + ((bc->rseg - bd->memory_seg) << 4);
+ ch->txwin = ch->rxwin = 0;
+ break;
+
+ } /* End switch bd->type */
+
+ ch->txbufhead = 0;
+ ch->txbufsize = bc->tmax + 1;
+
+ ch->rxbufhead = 0;
+ ch->rxbufsize = bc->rmax + 1;
+
+ lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2);
+
+ /* Set transmitter low water mark */
+ fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
+
+ /* Set receiver low water mark */
+
+ fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0);
+
+ /* Set receiver high water mark */
+
+ fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
+
+ bc->edelay = 100;
+ bc->idata = 1;
+
+ ch->startc = bc->startc;
+ ch->stopc = bc->stopc;
+ ch->startca = bc->startca;
+ ch->stopca = bc->stopca;
+
+ ch->fepcflag = 0;
+ ch->fepiflag = 0;
+ ch->fepoflag = 0;
+ ch->fepstartc = 0;
+ ch->fepstopc = 0;
+ ch->fepstartca = 0;
+ ch->fepstopca = 0;
+
+ ch->close_delay = 50;
+ ch->count = 0;
+ ch->blocked_open = 0;
+ ch->callout_termios = pc_callout.init_termios;
+ ch->normal_termios = pc_driver.init_termios;
+ ch->open_wait = 0;
+ ch->close_wait = 0;
+ ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
+ if (!(ch->tmp_buf))
+ {
+ printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
+
+ }
+ memset((void *)ch->tmp_buf,0,ch->txbufsize);
+ } /* End for each port */
+
+ printk(KERN_INFO
+ "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
+ VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
+ sprintf(mesg,
+ "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
+ VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
+ console_print(mesg);
+
+ memwinoff(bd, 0);
+
+} /* End post_fep_init */
+
+/* --------------------- Begin epcapoll ------------------------ */
+
+static void epcapoll(unsigned long ignored)
+{ /* Begin epcapoll */
+
+ unsigned long flags;
+ int crd;
+ volatile unsigned int head, tail;
+ struct channel *ch;
+ struct board_info *bd;
+
+ /* -------------------------------------------------------------------
+ This routine is called upon every timer interrupt. Even though
+ the Digi series cards are capable of generating interupts this
+ method of non-looping polling is more efficient. This routine
+ checks for card generated events (Such as receive data, are transmit
+ buffer empty) and acts on those events.
+ ----------------------------------------------------------------------- */
+
+ save_flags(flags);
+ cli();
+
+ for (crd = 0; crd < num_cards; crd++)
+ { /* Begin for each card */
+
+ bd = &boards[crd];
+ ch = card_ptr[crd];
+
+ if ((bd->status == DISABLED) || digi_poller_inhibited)
+ continue; /* Begin loop next interation */
+
+ /* -----------------------------------------------------------
+ assertmemoff is not needed here; indeed it is an empty subroutine.
+ It is being kept because future boards may need this as well as
+ some legacy boards.
+ ---------------------------------------------------------------- */
+
+ assertmemoff(ch);
+
+ globalwinon(ch);
+
+ /* ---------------------------------------------------------------
+ In this case head and tail actually refer to the event queue not
+ the transmit or receive queue.
+ ------------------------------------------------------------------- */
+
+ head = ch->mailbox->ein;
+ tail = ch->mailbox->eout;
+
+ /* If head isn't equal to tail we have an event */
+
+ if (head != tail)
+ doevent(crd);
+
+ memoff(ch);
+
+ } /* End for each card */
+
+ timer_table[DIGI_TIMER].fn = (void *)epcapoll;
+ timer_table[DIGI_TIMER].expires = jiffies + (HZ / 25);
+ timer_active |= 1 << DIGI_TIMER;
+
+ restore_flags(flags);
+
+} /* End epcapoll */
+
+/* --------------------- Begin doevent ------------------------ */
+
+static void doevent(int crd)
+{ /* Begin doevent */
+
+ volatile unchar *eventbuf;
+ struct channel *ch, *chan0;
+ static struct tty_struct *tty;
+ volatile struct board_info *bd;
+ volatile struct board_chan *bc;
+ register volatile unsigned int tail, head;
+ register int event, channel;
+ register int mstat, lstat;
+
+ /* -------------------------------------------------------------------
+ This subroutine is called by epcapoll when an event is detected
+ in the event queue. This routine responds to those events.
+ --------------------------------------------------------------------- */
+
+ bd = &boards[crd];
+
+ chan0 = card_ptr[crd];
+ epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
+
+ assertgwinon(chan0);
+
+ while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein))
+ { /* Begin while something in event queue */
+
+ assertgwinon(chan0);
+
+ if (bd->membase < (unsigned char *)0x100000)
+ eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->membase + tail + ISTART));
+ else
+ {
+ eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->re_map_membase + tail + ISTART));
+ }
+
+ /* Get the channel the event occured on */
+ channel = eventbuf[0];
+
+ /* Get the actual event code that occured */
+ event = eventbuf[1];
+
+ /* ----------------------------------------------------------------
+ The two assignments below get the current modem status (mstat)
+ and the previous modem status (lstat). These are useful becuase
+ an event could signal a change in modem signals itself.
+ ------------------------------------------------------------------- */
+
+ mstat = eventbuf[2];
+ lstat = eventbuf[3];
+
+ ch = chan0 + channel;
+
+ if ((unsigned)channel >= bd->numports || !ch)
+ {
+ if (channel >= bd->numports)
+ ch = chan0;
+ bc = ch->brdchan;
+ goto next;
+ }
+
+ if ((bc = ch->brdchan) == NULL)
+ goto next;
+
+ if (event & DATA_IND)
+ { /* Begin DATA_IND */
+
+ receive_data(ch);
+ assertgwinon(ch);
+
+ } /* End DATA_IND */
+ else
+ if (event & MODEMCHG_IND)
+ { /* Begin MODEMCHG_IND */
+
+ /* A modem signal change has been indicated */
+
+ ch->imodem = mstat;
+
+ if (ch->asyncflags & ASYNC_CHECK_CD)
+ {
+ if (mstat & ch->dcd) /* We are now receiving dcd */
+ wake_up_interruptible(&ch->open_wait);
+ else
+ pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */
+ }
+
+ } /* End MODEMCHG_IND */
+
+ tty = ch->tty;
+ if (tty)
+ { /* Begin if valid tty */
+
+ if (event & BREAK_IND)
+ { /* Begin if BREAK_IND */
+
+ /* A break has been indicated */
+
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = TTY_BREAK;
+
+ *tty->flip.char_buf_ptr++ = 0;
+
+ tty_schedule_flip(tty);
+
+ } /* End if BREAK_IND */
+ else
+ if (event & LOWTX_IND)
+ { /* Begin LOWTX_IND */
+
+ if (ch->statusflags & LOWWAIT)
+ { /* Begin if LOWWAIT */
+
+ ch->statusflags &= ~LOWWAIT;
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+
+ } /* End if LOWWAIT */
+
+ } /* End LOWTX_IND */
+ else
+ if (event & EMPTYTX_IND)
+ { /* Begin EMPTYTX_IND */
+
+ /* This event is generated by setup_empty_event */
+
+ ch->statusflags &= ~TXBUSY;
+ if (ch->statusflags & EMPTYWAIT)
+ { /* Begin if EMPTYWAIT */
+
+ ch->statusflags &= ~EMPTYWAIT;
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+
+ wake_up_interruptible(&tty->write_wait);
+
+ } /* End if EMPTYWAIT */
+
+ } /* End EMPTYTX_IND */
+
+ } /* End if valid tty */
+
+
+ next:
+ globalwinon(ch);
+
+ if (!bc)
+ printk(KERN_ERR "<Error> - bc == NULL in doevent!\n");
+ else
+ bc->idata = 1;
+
+ chan0->mailbox->eout = (tail + 4) & (IMAX - ISTART - 4);
+ globalwinon(chan0);
+
+ } /* End while something in event queue */
+
+} /* End doevent */
+
+/* --------------------- Begin fepcmd ------------------------ */
+
+static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
+ int byte2, int ncmds, int bytecmd)
+{ /* Begin fepcmd */
+
+ unchar *memaddr;
+ unsigned int head, cmdTail, cmdStart, cmdMax;
+ long count;
+ int n;
+
+ /* This is the routine in which commands may be passed to the card. */
+
+ if (ch->board->status == DISABLED)
+ {
+ return;
+ }
+
+ assertgwinon(ch);
+
+ /* Remember head (As well as max) is just an offset not a base addr */
+ head = ch->mailbox->cin;
+
+ /* cmdStart is a base address */
+ cmdStart = ch->mailbox->cstart;
+
+ /* ------------------------------------------------------------------
+ We do the addition below because we do not want a max pointer
+ relative to cmdStart. We want a max pointer that points at the
+ physical end of the command queue.
+ -------------------------------------------------------------------- */
+
+ cmdMax = (cmdStart + 4 + (ch->mailbox->cmax));
+
+ if (ch->board->membase < (unsigned char *)0x100000)
+ memaddr = ch->board->membase;
+ else
+ memaddr = ch->board->re_map_membase;
+
+ /*
+ The below command is necessary because newer kernels (2.1.x and
+ up) do not have a 1:1 virtual to physical mapping. The below
+ call adjust for that.
+ */
+
+ memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);
+
+ if (head >= (cmdMax - cmdStart) || (head & 03))
+ {
+ printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__,
+ cmd, head);
+ printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__,
+ cmdMax, cmdStart);
+ return;
+ }
+
+ if (bytecmd)
+ {
+ *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd;
+
+ *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum;
+ /* Below word_or_byte is bits to set */
+ *(volatile unchar *)(memaddr + head + cmdStart + 2) = (unchar)word_or_byte;
+ /* Below byte2 is bits to reset */
+ *(volatile unchar *)(memaddr + head + cmdStart + 3) = (unchar)byte2;
+
+ }
+ else
+ {
+ *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd;
+ *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum;
+ *(volatile ushort*)(memaddr + head + cmdStart + 2) = (ushort)word_or_byte;
+ }
+
+ head = (head + 4) & (cmdMax - cmdStart - 4);
+ ch->mailbox->cin = head;
+
+ count = FEPTIMEOUT;
+
+ for (;;)
+ { /* Begin forever loop */
+
+ count--;
+ if (count == 0)
+ {
+ printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
+ return;
+ }
+
+ head = ch->mailbox->cin;
+ cmdTail = ch->mailbox->cout;
+
+ n = (head - cmdTail) & (cmdMax - cmdStart - 4);
+
+ /* ----------------------------------------------------------
+ Basically this will break when the FEP acknowledges the
+ command by incrementing cmdTail (Making it equal to head).
+ ------------------------------------------------------------- */
+
+ if (n <= ncmds * (sizeof(short) * 4))
+ break; /* Well nearly forever :-) */
+
+ } /* End forever loop */
+
+} /* End fepcmd */
+
+/* ---------------------------------------------------------------------
+ Digi products use fields in their channels structures that are very
+ similar to the c_cflag and c_iflag fields typically found in UNIX
+ termios structures. The below three routines allow mappings
+ between these hardware "flags" and their respective Linux flags.
+------------------------------------------------------------------------- */
+
+/* --------------------- Begin termios2digi_h -------------------- */
+
+static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
+{ /* Begin termios2digi_h */
+
+ unsigned res = 0;
+
+ if (cflag & CRTSCTS)
+ {
+ ch->digiext.digi_flags |= (RTSPACE | CTSPACE);
+ res |= ((ch->m_cts) | (ch->m_rts));
+ }
+
+ if (ch->digiext.digi_flags & RTSPACE)
+ res |= ch->m_rts;
+
+ if (ch->digiext.digi_flags & DTRPACE)
+ res |= ch->m_dtr;
+
+ if (ch->digiext.digi_flags & CTSPACE)
+ res |= ch->m_cts;
+
+ if (ch->digiext.digi_flags & DSRPACE)
+ res |= ch->dsr;
+
+ if (ch->digiext.digi_flags & DCDPACE)
+ res |= ch->dcd;
+
+ if (res & (ch->m_rts))
+ ch->digiext.digi_flags |= RTSPACE;
+
+ if (res & (ch->m_cts))
+ ch->digiext.digi_flags |= CTSPACE;
+
+ return res;
+
+} /* End termios2digi_h */
+
+/* --------------------- Begin termios2digi_i -------------------- */
+static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
+{ /* Begin termios2digi_i */
+
+ unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
+ INPCK | ISTRIP|IXON|IXANY|IXOFF);
+
+ if (ch->digiext.digi_flags & DIGI_AIXON)
+ res |= IAIXON;
+ return res;
+
+} /* End termios2digi_i */
+
+/* --------------------- Begin termios2digi_c -------------------- */
+
+static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
+{ /* Begin termios2digi_c */
+
+ unsigned res = 0;
+
+#ifdef SPEED_HACK
+ /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */
+ if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200;
+ if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600;
+#endif /* SPEED_HACK */
+
+ if (cflag & CBAUDEX)
+ { /* Begin detected CBAUDEX */
+
+ ch->digiext.digi_flags |= DIGI_FAST;
+
+ /* -------------------------------------------------------------
+ HUPCL bit is used by FEP to indicate fast baud
+ table is to be used.
+ ----------------------------------------------------------------- */
+
+ res |= FEP_HUPCL;
+
+ } /* End detected CBAUDEX */
+ else ch->digiext.digi_flags &= ~DIGI_FAST;
+
+ /* -------------------------------------------------------------------
+ CBAUD has bit position 0x1000 set these days to indicate Linux
+ baud rate remap. Digi hardware can't handle the bit assignment.
+ (We use a different bit assignment for high speed.). Clear this
+ bit out.
+ ---------------------------------------------------------------------- */
+ res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
+
+ /* -------------------------------------------------------------
+ This gets a little confusing. The Digi cards have their own
+ representation of c_cflags controling baud rate. For the most
+ part this is identical to the Linux implementation. However;
+ Digi supports one rate (76800) that Linux doesn't. This means
+ that the c_cflag entry that would normally mean 76800 for Digi
+ actually means 115200 under Linux. Without the below mapping,
+ a stty 115200 would only drive the board at 76800. Since
+ the rate 230400 is also found after 76800, the same problem afflicts
+ us when we choose a rate of 230400. Without the below modificiation
+ stty 230400 would actually give us 115200.
+
+ There are two additional differences. The Linux value for CLOCAL
+ (0x800; 0004000) has no meaning to the Digi hardware. Also in
+ later releases of Linux; the CBAUD define has CBAUDEX (0x1000;
+ 0010000) ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX
+ should be checked for a screened out prior to termios2digi_c
+ returning. Since CLOCAL isn't used by the board this can be
+ ignored as long as the returned value is used only by Digi hardware.
+ ----------------------------------------------------------------- */
+
+ if (cflag & CBAUDEX)
+ {
+ /* -------------------------------------------------------------
+ The below code is trying to guarantee that only baud rates
+ 115200 and 230400 are remapped. We use exclusive or because
+ the various baud rates share common bit positions and therefore
+ can't be tested for easily.
+ ----------------------------------------------------------------- */
+
+
+ if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
+ (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
+ {
+ res += 1;
+ }
+ }
+
+ return res;
+
+} /* End termios2digi_c */
+
+/* --------------------- Begin epcaparam ----------------------- */
+
+static void epcaparam(struct tty_struct *tty, struct channel *ch)
+{ /* Begin epcaparam */
+
+ unsigned int cmdHead;
+ struct termios *ts;
+ volatile struct board_chan *bc;
+ unsigned mval, hflow, cflag, iflag;
+
+ bc = ch->brdchan;
+ epcaassert(bc !=0, "bc out of range");
+
+ assertgwinon(ch);
+
+ ts = tty->termios;
+
+ if ((ts->c_cflag & CBAUD) == 0)
+ { /* Begin CBAUD detected */
+
+ cmdHead = bc->rin;
+ bc->rout = cmdHead;
+ cmdHead = bc->tin;
+
+ /* Changing baud in mid-stream transmission can be wonderful */
+ /* ---------------------------------------------------------------
+ Flush current transmit buffer by setting cmdTail pointer (tout)
+ to cmdHead pointer (tin). Hopefully the transmit buffer is empty.
+ ----------------------------------------------------------------- */
+
+ fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
+ mval = 0;
+
+ } /* End CBAUD detected */
+ else
+ { /* Begin CBAUD not detected */
+
+ /* -------------------------------------------------------------------
+ c_cflags have changed but that change had nothing to do with BAUD.
+ Propagate the change to the card.
+ ---------------------------------------------------------------------- */
+
+ cflag = termios2digi_c(ch, ts->c_cflag);
+
+ if (cflag != ch->fepcflag)
+ {
+ ch->fepcflag = cflag;
+ /* Set baud rate, char size, stop bits, parity */
+ fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
+ }
+
+
+ /* ----------------------------------------------------------------
+ If the user has not forced CLOCAL and if the device is not a
+ CALLOUT device (Which is always CLOCAL) we set flags such that
+ the driver will wait on carrier detect.
+ ------------------------------------------------------------------- */
+
+ if ((ts->c_cflag & CLOCAL) || (tty->driver.subtype == SERIAL_TYPE_CALLOUT))
+ { /* Begin it is a cud device or a ttyD device with CLOCAL on */
+ ch->asyncflags &= ~ASYNC_CHECK_CD;
+ } /* End it is a cud device or a ttyD device with CLOCAL on */
+ else
+ { /* Begin it is a ttyD device */
+ ch->asyncflags |= ASYNC_CHECK_CD;
+ } /* End it is a ttyD device */
+
+ mval = ch->m_dtr | ch->m_rts;
+
+ } /* End CBAUD not detected */
+
+ iflag = termios2digi_i(ch, ts->c_iflag);
+
+ /* Check input mode flags */
+
+ if (iflag != ch->fepiflag)
+ {
+ ch->fepiflag = iflag;
+
+ /* ---------------------------------------------------------------
+ Command sets channels iflag structure on the board. Such things
+ as input soft flow control, handeling of parity errors, and
+ break handeling are all set here.
+ ------------------------------------------------------------------- */
+
+ /* break handeling, parity handeling, input stripping, flow control chars */
+ fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
+ }
+
+ /* ---------------------------------------------------------------
+ Set the board mint value for this channel. This will cause hardware
+ events to be generated each time the DCD signal (Described in mint)
+ changes.
+ ------------------------------------------------------------------- */
+ bc->mint = ch->dcd;
+
+ if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
+ if (ch->digiext.digi_flags & DIGI_FORCEDCD)
+ bc->mint = 0;
+
+ ch->imodem = bc->mstat;
+
+ hflow = termios2digi_h(ch, ts->c_cflag);
+
+ if (hflow != ch->hflow)
+ {
+ ch->hflow = hflow;
+
+ /* --------------------------------------------------------------
+ Hard flow control has been selected but the board is not
+ using it. Activate hard flow control now.
+ ----------------------------------------------------------------- */
+
+ fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
+ }
+
+
+ mval ^= ch->modemfake & (mval ^ ch->modem);
+
+ if (ch->omodem ^ mval)
+ {
+ ch->omodem = mval;
+
+ /* --------------------------------------------------------------
+ The below command sets the DTR and RTS mstat structure. If
+ hard flow control is NOT active these changes will drive the
+ output of the actual DTR and RTS lines. If hard flow control
+ is active, the changes will be saved in the mstat structure and
+ only asserted when hard flow control is turned off.
+ ----------------------------------------------------------------- */
+
+ /* First reset DTR & RTS; then set them */
+ fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
+ fepcmd(ch, SETMODEM, mval, 0, 0, 1);
+
+ }
+
+ if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc)
+ {
+ ch->fepstartc = ch->startc;
+ ch->fepstopc = ch->stopc;
+
+ /* ------------------------------------------------------------
+ The XON / XOFF characters have changed; propogate these
+ changes to the card.
+ --------------------------------------------------------------- */
+
+ fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
+ }
+
+ if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca)
+ {
+ ch->fepstartca = ch->startca;
+ ch->fepstopca = ch->stopca;
+
+ /* ---------------------------------------------------------------
+ Similar to the above, this time the auxilarly XON / XOFF
+ characters have changed; propogate these changes to the card.
+ ------------------------------------------------------------------ */
+
+ fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
+ }
+
+} /* End epcaparam */
+
+/* --------------------- Begin receive_data ----------------------- */
+
+static void receive_data(struct channel *ch)
+{ /* Begin receive_data */
+
+ unchar *rptr;
+ struct termios *ts = 0;
+ struct tty_struct *tty;
+ volatile struct board_chan *bc;
+ register int dataToRead, wrapgap, bytesAvailable;
+ register unsigned int tail, head;
+ unsigned int wrapmask;
+ int rc;
+
+
+ /* ---------------------------------------------------------------
+ This routine is called by doint when a receive data event
+ has taken place.
+ ------------------------------------------------------------------- */
+
+ globalwinon(ch);
+
+ if (ch->statusflags & RXSTOPPED)
+ return;
+
+ tty = ch->tty;
+ if (tty)
+ ts = tty->termios;
+
+ bc = ch->brdchan;
+
+ if (!bc)
+ {
+ printk(KERN_ERR "<Error> - bc is NULL in receive_data!\n");
+ return;
+ }
+
+ wrapmask = ch->rxbufsize - 1;
+
+ /* ---------------------------------------------------------------------
+ Get the head and tail pointers to the receiver queue. Wrap the
+ head pointer if it has reached the end of the buffer.
+ ------------------------------------------------------------------------ */
+
+ head = bc->rin;
+ head &= wrapmask;
+ tail = bc->rout & wrapmask;
+
+ bytesAvailable = (head - tail) & wrapmask;
+
+ if (bytesAvailable == 0)
+ return;
+
+ /* ------------------------------------------------------------------
+ If CREAD bit is off or device not open, set TX tail to head
+ --------------------------------------------------------------------- */
+
+ if (!tty || !ts || !(ts->c_cflag & CREAD))
+ {
+ bc->rout = head;
+ return;
+ }
+
+ if (tty->flip.count == TTY_FLIPBUF_SIZE)
+ return;
+
+ if (bc->orun)
+ {
+ bc->orun = 0;
+ printk(KERN_WARNING "overrun! DigiBoard device minor = %d\n",MINOR(tty->device));
+ }
+
+ rxwinon(ch);
+ rptr = tty->flip.char_buf_ptr;
+ rc = tty->flip.count;
+
+ while (bytesAvailable > 0)
+ { /* Begin while there is data on the card */
+
+ wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
+
+ /* ---------------------------------------------------------------
+ Even if head has wrapped around only report the amount of
+ data to be equal to the size - tail. Remember memcpy can't
+ automaticly wrap around the receive buffer.
+ ----------------------------------------------------------------- */
+
+ dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable;
+
+ /* --------------------------------------------------------------
+ Make sure we don't overflow the buffer
+ ----------------------------------------------------------------- */
+
+ if ((rc + dataToRead) > TTY_FLIPBUF_SIZE)
+ dataToRead = TTY_FLIPBUF_SIZE - rc;
+
+ if (dataToRead == 0)
+ break;
+
+ /* ---------------------------------------------------------------
+ Move data read from our card into the line disciplines buffer
+ for translation if necessary.
+ ------------------------------------------------------------------ */
+
+ if ((memcpy(rptr, ch->rxptr + tail, dataToRead)) != rptr)
+ printk(KERN_ERR "<Error> - receive_data : memcpy failed\n");
+
+ rc += dataToRead;
+ rptr += dataToRead;
+ tail = (tail + dataToRead) & wrapmask;
+ bytesAvailable -= dataToRead;
+
+ } /* End while there is data on the card */
+
+
+ tty->flip.count = rc;
+ tty->flip.char_buf_ptr = rptr;
+ globalwinon(ch);
+ bc->rout = tail;
+
+ /* Must be called with global data */
+ tty_schedule_flip(ch->tty);
+ return;
+
+} /* End receive_data */
+
+/* --------------------- Begin pc_ioctl ----------------------- */
+
+static int pc_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{ /* Begin pc_ioctl */
+
+ digiflow_t dflow;
+ int retval, error;
+ unsigned long flags;
+ unsigned int mflag, mstat;
+ unsigned char startc, stopc;
+ volatile struct board_chan *bc;
+ struct channel *ch = (struct channel *) tty->driver_data;
+
+ /* The control device has it's own set of commands */
+ if (tty->driver.subtype == SERIAL_TYPE_INFO)
+ { /* Begin if subtype is the control device */
+
+ switch (cmd)
+ { /* Begin switch cmd */
+
+ case DIGI_GETINFO:
+ { /* Begin case DIGI_GETINFO */
+
+ struct digi_info di ;
+ int brd;
+
+ getUser(brd, (unsigned int *)arg);
+
+ if ((error = verify_area(VERIFY_WRITE, (char*)arg, sizeof(di))))
+ {
+ printk(KERN_ERR "DIGI_GETINFO : verify area size 0x%x failed\n",sizeof(di));
+ return(error);
+ }
+
+ if ((brd < 0) || (brd >= num_cards) || (num_cards == 0))
+ return (-ENODEV);
+
+ memset(&di, 0, sizeof(di));
+
+ di.board = brd ;
+ di.status = boards[brd].status;
+ di.type = boards[brd].type ;
+ di.numports = boards[brd].numports ;
+ di.port = boards[brd].port ;
+ di.membase = boards[brd].membase ;
+
+ copy_to_user((char *)arg, &di, sizeof (di));
+ break;
+
+ } /* End case DIGI_GETINFO */
+
+ case DIGI_POLLER:
+ { /* Begin case DIGI_POLLER */
+
+ int brd = arg & 0xff000000 >> 16 ;
+ unsigned char state = arg & 0xff ;
+
+ if ((brd < 0) || (brd >= num_cards))
+ {
+ printk(KERN_ERR "<Error> - DIGI POLLER : brd not valid!\n");
+ return (-ENODEV);
+ }
+
+ digi_poller_inhibited = state ;
+ break ;
+
+ } /* End case DIGI_POLLER */
+
+ case DIGI_INIT:
+ { /* Begin case DIGI_INIT */
+
+ /* ------------------------------------------------------------
+ This call is made by the apps to complete the initilization
+ of the board(s). This routine is responsible for setting
+ the card to its initial state and setting the drivers control
+ fields to the sutianle settings for the card in question.
+ ---------------------------------------------------------------- */
+
+ int crd ;
+ for (crd = 0; crd < num_cards; crd++)
+ post_fep_init (crd);
+
+ break ;
+
+ } /* End case DIGI_INIT */
+
+
+ default:
+ return -ENOIOCTLCMD;
+
+ } /* End switch cmd */
+ return (0) ;
+
+ } /* End if subtype is the control device */
+
+ if (ch)
+ bc = ch->brdchan;
+ else
+ {
+ printk(KERN_ERR "<Error> - ch is NULL in pc_ioctl!\n");
+ return(-EINVAL);
+ }
+
+ save_flags(flags);
+
+ /* -------------------------------------------------------------------
+ For POSIX compliance we need to add more ioctls. See tty_ioctl.c
+ in /usr/src/linux/drivers/char for a good example. In particular
+ think about adding TCSETAF, TCSETAW, TCSETA, TCSETSF, TCSETSW, TCSETS.
+ ---------------------------------------------------------------------- */
+
+ switch (cmd)
+ { /* Begin switch cmd */
+
+ case TCGETS:
+ retval = verify_area(VERIFY_WRITE, (void *)arg,
+ sizeof(struct termios));
+
+ if (retval)
+ return(retval);
+
+ copy_to_user((struct termios *)arg,
+ tty->termios, sizeof(struct termios));
+ return(0);
+
+ case TCGETA:
+ return get_termio(tty, (struct termio *)arg);
+
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+
+ /* Setup an event to indicate when the transmit buffer empties */
+
+ setup_empty_event(tty,ch);
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ digi_send_break(ch, HZ/4); /* 1/4 second */
+ return 0;
+
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+
+ /* Setup an event to indicate when the transmit buffer empties */
+
+ setup_empty_event(tty,ch);
+ tty_wait_until_sent(tty, 0);
+ digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
+ return 0;
+
+ case TIOCGSOFTCAR:
+
+ error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
+ if (error)
+ return error;
+
+ putUser(C_CLOCAL(tty) ? 1 : 0,
+ (unsigned long *) arg);
+ return 0;
+
+ case TIOCSSOFTCAR:
+ /*RONNIE PUT VERIFY_READ (See above) check here */
+ {
+ unsigned int value;
+
+ getUser(value, (unsigned int *)arg);
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (value ? CLOCAL : 0));
+ return 0;
+ }
+
+ case TIOCMODG:
+ case TIOCMGET:
+
+ mflag = 0;
+
+ cli();
+ globalwinon(ch);
+ mstat = bc->mstat;
+ memoff(ch);
+ restore_flags(flags);
+
+ if (mstat & ch->m_dtr)
+ mflag |= TIOCM_DTR;
+
+ if (mstat & ch->m_rts)
+ mflag |= TIOCM_RTS;
+
+ if (mstat & ch->m_cts)
+ mflag |= TIOCM_CTS;
+
+ if (mstat & ch->dsr)
+ mflag |= TIOCM_DSR;
+
+ if (mstat & ch->m_ri)
+ mflag |= TIOCM_RI;
+
+ if (mstat & ch->dcd)
+ mflag |= TIOCM_CD;
+
+ error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
+
+ if (error)
+ return error;
+
+ putUser(mflag, (unsigned long *) arg);
+
+ break;
+
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMODS:
+ case TIOCMSET:
+
+ getUser(mstat, (unsigned int *)arg);
+
+ mflag = 0;
+ if (mstat & TIOCM_DTR)
+ mflag |= ch->m_dtr;
+
+ if (mstat & TIOCM_RTS)
+ mflag |= ch->m_rts;
+
+ switch (cmd)
+ { /* Begin switch cmd */
+
+ case TIOCMODS:
+ case TIOCMSET:
+ ch->modemfake = ch->m_dtr|ch->m_rts;
+ ch->modem = mflag;
+ break;
+
+ case TIOCMBIS:
+ ch->modemfake |= mflag;
+ ch->modem |= mflag;
+ break;
+
+ case TIOCMBIC:
+ ch->modemfake |= mflag;
+ ch->modem &= ~mflag;
+ break;
+
+ } /* End switch cmd */
+
+ cli();
+ globalwinon(ch);
+
+ /* --------------------------------------------------------------
+ The below routine generally sets up parity, baud, flow control
+ issues, etc.... It effect both control flags and input flags.
+ ------------------------------------------------------------------ */
+
+ epcaparam(tty,ch);
+ memoff(ch);
+ restore_flags(flags);
+ break;
+
+ case TIOCSDTR:
+ ch->omodem |= ch->m_dtr;
+ cli();
+ globalwinon(ch);
+ fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
+ memoff(ch);
+ restore_flags(flags);
+ break;
+
+ case TIOCCDTR:
+ ch->omodem &= ~ch->m_dtr;
+ cli();
+ globalwinon(ch);
+ fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
+ memoff(ch);
+ restore_flags(flags);
+ break;
+
+ case DIGI_GETA:
+ if ((error=
+ verify_area(VERIFY_WRITE, (char*)arg, sizeof(digi_t))))
+ {
+ printk(KERN_ERR "<Error> - Digi GETA failed\n");
+ return(error);
+ }
+
+ copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t));
+ break;
+
+ case DIGI_SETAW:
+ case DIGI_SETAF:
+ if ((cmd) == (DIGI_SETAW))
+ {
+ /* Setup an event to indicate when the transmit buffer empties */
+
+ setup_empty_event(tty,ch);
+ tty_wait_until_sent(tty, 0);
+ }
+ else
+ {
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ }
+
+ /* Fall Thru */
+
+ case DIGI_SETA:
+ if ((error =
+ verify_area(VERIFY_READ, (char*)arg,sizeof(digi_t))))
+ return(error);
+
+ copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t));
+
+ if (ch->digiext.digi_flags & DIGI_ALTPIN)
+ {
+ ch->dcd = ch->m_dsr;
+ ch->dsr = ch->m_dcd;
+ }
+ else
+ {
+ ch->dcd = ch->m_dcd;
+ ch->dsr = ch->m_dsr;
+ }
+
+ cli();
+ globalwinon(ch);
+
+ /* -----------------------------------------------------------------
+ The below routine generally sets up parity, baud, flow control
+ issues, etc.... It effect both control flags and input flags.
+ ------------------------------------------------------------------- */
+
+ epcaparam(tty,ch);
+ memoff(ch);
+ restore_flags(flags);
+ break;
+
+ case DIGI_GETFLOW:
+ case DIGI_GETAFLOW:
+ cli();
+ globalwinon(ch);
+ if ((cmd) == (DIGI_GETFLOW))
+ {
+ dflow.startc = bc->startc;
+ dflow.stopc = bc->stopc;
+ }
+ else
+ {
+ dflow.startc = bc->startca;
+ dflow.stopc = bc->stopca;
+ }
+ memoff(ch);
+ restore_flags(flags);
+
+ if ((error = verify_area(VERIFY_WRITE, (char*)arg,sizeof(dflow))))
+ return(error);
+
+ copy_to_user((char*)arg, &dflow, sizeof(dflow));
+ break;
+
+ case DIGI_SETAFLOW:
+ case DIGI_SETFLOW:
+ if ((cmd) == (DIGI_SETFLOW))
+ {
+ startc = ch->startc;
+ stopc = ch->stopc;
+ }
+ else
+ {
+ startc = ch->startca;
+ stopc = ch->stopca;
+ }
+
+ if ((error = verify_area(VERIFY_READ, (char*)arg,sizeof(dflow))))
+ return(error);
+
+ copy_from_user(&dflow, (char*)arg, sizeof(dflow));
+
+ if (dflow.startc != startc || dflow.stopc != stopc)
+ { /* Begin if setflow toggled */
+ cli();
+ globalwinon(ch);
+
+ if ((cmd) == (DIGI_SETFLOW))
+ {
+ ch->fepstartc = ch->startc = dflow.startc;
+ ch->fepstopc = ch->stopc = dflow.stopc;
+ fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
+ }
+ else
+ {
+ ch->fepstartca = ch->startca = dflow.startc;
+ ch->fepstopca = ch->stopca = dflow.stopc;
+ fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
+ }
+
+ if (ch->statusflags & TXSTOPPED)
+ pc_start(tty);
+
+ memoff(ch);
+ restore_flags(flags);
+
+ } /* End if setflow toggled */
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+
+ } /* End switch cmd */
+
+ return 0;
+
+} /* End pc_ioctl */
+
+/* --------------------- Begin pc_set_termios ----------------------- */
+
+static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{ /* Begin pc_set_termios */
+
+ struct channel *ch;
+ unsigned long flags;
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ { /* Begin if channel valid */
+
+ save_flags(flags);
+ cli();
+ globalwinon(ch);
+ epcaparam(tty, ch);
+ memoff(ch);
+
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ ((tty->termios->c_cflag & CRTSCTS) == 0))
+ tty->hw_stopped = 0;
+
+ if (!(old_termios->c_cflag & CLOCAL) &&
+ (tty->termios->c_cflag & CLOCAL))
+ wake_up_interruptible(&ch->open_wait);
+
+ restore_flags(flags);
+
+ } /* End if channel valid */
+
+} /* End pc_set_termios */
+
+/* --------------------- Begin do_softint ----------------------- */
+
+static void do_softint(void *private_)
+{ /* Begin do_softint */
+
+ struct channel *ch = (struct channel *) private_;
+
+
+ /* Called in response to a modem change event */
+
+ if (ch && ch->magic == EPCA_MAGIC)
+ { /* Begin EPCA_MAGIC */
+
+ struct tty_struct *tty = ch->tty;
+
+ if (tty && tty->driver_data)
+ {
+ if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event))
+ { /* Begin if clear_bit */
+
+ tty_hangup(tty);
+ wake_up_interruptible(&ch->open_wait);
+ ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+
+ } /* End if clear_bit */
+ }
+
+ } /* End EPCA_MAGIC */
+
+} /* End do_softint */
+
+/* ------------------------------------------------------------
+ pc_stop and pc_start provide software flow control to the
+ routine and the pc_ioctl routine.
+---------------------------------------------------------------- */
+
+/* --------------------- Begin pc_stop ----------------------- */
+
+static void pc_stop(struct tty_struct *tty)
+{ /* Begin pc_stop */
+
+ struct channel *ch;
+ unsigned long flags;
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ { /* Begin if valid channel */
+
+ save_flags(flags);
+ cli();
+
+ if ((ch->statusflags & TXSTOPPED) == 0)
+ { /* Begin if transmit stop requested */
+
+ globalwinon(ch);
+
+ /* STOP transmitting now !! */
+
+ fepcmd(ch, PAUSETX, 0, 0, 0, 0);
+
+ ch->statusflags |= TXSTOPPED;
+ memoff(ch);
+
+ } /* End if transmit stop requested */
+
+ restore_flags(flags);
+
+ } /* End if valid channel */
+
+} /* End pc_stop */
+
+/* --------------------- Begin pc_start ----------------------- */
+
+static void pc_start(struct tty_struct *tty)
+{ /* Begin pc_start */
+
+ struct channel *ch;
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ { /* Begin if channel valid */
+
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ /* Just in case output was resumed because of a change in Digi-flow */
+ if (ch->statusflags & TXSTOPPED)
+ { /* Begin transmit resume requested */
+
+ volatile struct board_chan *bc;
+
+ globalwinon(ch);
+ bc = ch->brdchan;
+ if (ch->statusflags & LOWWAIT)
+ bc->ilow = 1;
+
+ /* Okay, you can start transmitting again... */
+
+ fepcmd(ch, RESUMETX, 0, 0, 0, 0);
+
+ ch->statusflags &= ~TXSTOPPED;
+ memoff(ch);
+
+ } /* End transmit resume requested */
+
+ restore_flags(flags);
+
+ } /* End if channel valid */
+
+} /* End pc_start */
+
+/* ------------------------------------------------------------------
+ The below routines pc_throttle and pc_unthrottle are used
+ to slow (And resume) the receipt of data into the kernels
+ receive buffers. The exact occurence of this depends on the
+ size of the kernels receive buffer and what the 'watermarks'
+ are set to for that buffer. See the n_ttys.c file for more
+ details.
+______________________________________________________________________ */
+/* --------------------- Begin throttle ----------------------- */
+
+static void pc_throttle(struct tty_struct * tty)
+{ /* Begin pc_throttle */
+
+ struct channel *ch;
+ unsigned long flags;
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ { /* Begin if channel valid */
+
+
+ save_flags(flags);
+ cli();
+
+ if ((ch->statusflags & RXSTOPPED) == 0)
+ {
+ globalwinon(ch);
+ fepcmd(ch, PAUSERX, 0, 0, 0, 0);
+
+ ch->statusflags |= RXSTOPPED;
+ memoff(ch);
+ }
+ restore_flags(flags);
+
+ } /* End if channel valid */
+
+} /* End pc_throttle */
+
+/* --------------------- Begin unthrottle ----------------------- */
+
+static void pc_unthrottle(struct tty_struct *tty)
+{ /* Begin pc_unthrottle */
+
+ struct channel *ch;
+ unsigned long flags;
+ volatile struct board_chan *bc;
+
+
+ /* ---------------------------------------------------------
+ verifyChannel returns the channel from the tty struct
+ if it is valid. This serves as a sanity check.
+ ------------------------------------------------------------- */
+
+ if ((ch = verifyChannel(tty)) != NULL)
+ { /* Begin if channel valid */
+
+
+ /* Just in case output was resumed because of a change in Digi-flow */
+ save_flags(flags);
+ cli();
+
+ if (ch->statusflags & RXSTOPPED)
+ {
+
+ globalwinon(ch);
+ bc = ch->brdchan;
+ fepcmd(ch, RESUMERX, 0, 0, 0, 0);
+
+ ch->statusflags &= ~RXSTOPPED;
+ memoff(ch);
+ }
+ restore_flags(flags);
+
+ } /* End if channel valid */
+
+} /* End pc_unthrottle */
+
+/* --------------------- Begin digi_send_break ----------------------- */
+
+void digi_send_break(struct channel *ch, int msec)
+{ /* Begin digi_send_break */
+
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ globalwinon(ch);
+
+ /* --------------------------------------------------------------------
+ Maybe I should send an infinite break here, schedule() for
+ msec amount of time, and then stop the break. This way,
+ the user can't screw up the FEP by causing digi_send_break()
+ to be called (i.e. via an ioctl()) more than once in msec amount
+ of time. Try this for now...
+ ------------------------------------------------------------------------ */
+
+ fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
+ memoff(ch);
+
+ restore_flags(flags);
+
+} /* End digi_send_break */
+
+/* --------------------- Begin setup_empty_event ----------------------- */
+
+static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
+{ /* Begin setup_empty_event */
+
+ volatile struct board_chan *bc = ch->brdchan;
+ unsigned long int flags;
+
+ save_flags(flags);
+ cli();
+ globalwinon(ch);
+ ch->statusflags |= EMPTYWAIT;
+
+ /* ------------------------------------------------------------------
+ When set the iempty flag request a event to be generated when the
+ transmit buffer is empty (If there is no BREAK in progress).
+ --------------------------------------------------------------------- */
+
+ bc->iempty = 1;
+ memoff(ch);
+ restore_flags(flags);
+
+} /* End setup_empty_event */
+
+/* --------------------- Begin get_termio ----------------------- */
+
+static int get_termio(struct tty_struct * tty, struct termio * termio)
+{ /* Begin get_termio */
+ int error;
+
+ error = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
+ if (error)
+ return error;
+
+ kernel_termios_to_user_termio(termio, tty->termios);
+
+ return 0;
+} /* End get_termio */
+/* ---------------------- Begin epca_setup -------------------------- */
+void epca_setup(char *str, int *ints)
+{ /* Begin epca_setup */
+
+ struct board_info board;
+ int index, loop, last;
+ char *temp, *t2;
+ unsigned len;
+
+ /* ----------------------------------------------------------------------
+ If this routine looks a little strange it is because it is only called
+ if a LILO append command is given to boot the kernel with parameters.
+ In this way, we can provide the user a method of changing his board
+ configuration without rebuilding the kernel.
+ ----------------------------------------------------------------------- */
+ if (!liloconfig)
+ liloconfig = 1;
+
+ memset(&board, 0, sizeof(board));
+
+ /* Assume the data is int first, later we can change it */
+ /* I think that array position 0 of ints holds the number of args */
+ for (last = 0, index = 1; index <= ints[0]; index++)
+ switch(index)
+ { /* Begin parse switch */
+
+ case 1:
+ board.status = ints[index];
+
+ /* ---------------------------------------------------------
+ We check for 2 (As opposed to 1; because 2 is a flag
+ instructing the driver to ignore epcaconfig.) For this
+ reason we check for 2.
+ ------------------------------------------------------------ */
+ if (board.status == 2)
+ { /* Begin ignore epcaconfig as well as lilo cmd line */
+ nbdevs = 0;
+ num_cards = 0;
+ return;
+ } /* End ignore epcaconfig as well as lilo cmd line */
+
+ if (board.status > 2)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid board status 0x%x\n", board.status);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_BOARD_STATUS;
+ return;
+ }
+ last = index;
+ break;
+
+ case 2:
+ board.type = ints[index];
+ if (board.type >= PCIXEM)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid board type 0x%x\n", board.type);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_BOARD_TYPE;
+ return;
+ }
+ last = index;
+ break;
+
+ case 3:
+ board.altpin = ints[index];
+ if (board.altpin > 1)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid board altpin 0x%x\n", board.altpin);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_ALTPIN;
+ return;
+ }
+ last = index;
+ break;
+
+ case 4:
+ board.numports = ints[index];
+ if ((board.numports < 2) || (board.numports > 256))
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid board numports 0x%x\n", board.numports);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_NUM_PORTS;
+ return;
+ }
+ nbdevs += board.numports;
+ last = index;
+ break;
+
+ case 5:
+ board.port = (unsigned char *)ints[index];
+ if (board.port <= 0)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_PORT_BASE;
+ return;
+ }
+ last = index;
+ break;
+
+ case 6:
+ board.membase = (unsigned char *)ints[index];
+ if (board.membase <= 0)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_MEM_BASE;
+ return;
+ }
+ last = index;
+ break;
+
+ default:
+ printk(KERN_ERR "<Error> - epca_setup: Too many integer parms\n");
+ return;
+
+ } /* End parse switch */
+
+ while (str && *str)
+ { /* Begin while there is a string arg */
+
+ /* find the next comma or terminator */
+ temp = str;
+
+ /* While string is not null, and a comma hasn't been found */
+ while (*temp && (*temp != ','))
+ temp++;
+
+ if (!*temp)
+ temp = NULL;
+ else
+ *temp++ = 0;
+
+ /* Set index to the number of args + 1 */
+ index = last + 1;
+
+ switch(index)
+ {
+ case 1:
+ len = strlen(str);
+ if (strncmp("Disable", str, len) == 0)
+ board.status = 0;
+ else
+ if (strncmp("Enable", str, len) == 0)
+ board.status = 1;
+ else
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid status %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_BOARD_STATUS;
+ return;
+ }
+ last = index;
+ break;
+
+ case 2:
+
+ for(loop = 0; loop < EPCA_NUM_TYPES; loop++)
+ if (strcmp(board_desc[loop], str) == 0)
+ break;
+
+
+ /* ---------------------------------------------------------------
+ If the index incremented above refers to a legitamate board
+ type set it here.
+ ------------------------------------------------------------------*/
+
+ if (index < EPCA_NUM_TYPES)
+ board.type = loop;
+ else
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid board type: %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_BOARD_TYPE;
+ return;
+ }
+ last = index;
+ break;
+
+ case 3:
+ len = strlen(str);
+ if (strncmp("Disable", str, len) == 0)
+ board.altpin = 0;
+ else
+ if (strncmp("Enable", str, len) == 0)
+ board.altpin = 1;
+ else
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid altpin %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_ALTPIN;
+ return;
+ }
+ last = index;
+ break;
+
+ case 4:
+ t2 = str;
+ while (isdigit(*t2))
+ t2++;
+
+ if (*t2)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid port count %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_NUM_PORTS;
+ return;
+ }
+
+ /* ------------------------------------------------------------
+ There is not a man page for simple_strtoul but the code can be
+ found in vsprintf.c. The first argument is the string to
+ translate (To an unsigned long obviously), the second argument
+ can be the address of any character variable or a NULL. If a
+ variable is given, the end pointer of the string will be stored
+ in that variable; if a NULL is given the the end pointer will
+ not be returned. The last argument is the base to use. If
+ a 0 is indicated, the routine will attempt to determine the
+ proper base by looking at the values prefix (A '0' for octal,
+ a 'x' for hex, etc ... If a value is given it will use that
+ value as the base.
+ ---------------------------------------------------------------- */
+ board.numports = simple_strtoul(str, NULL, 0);
+ nbdevs += board.numports;
+ last = index;
+ break;
+
+ case 5:
+ t2 = str;
+ while (isxdigit(*t2))
+ t2++;
+
+ if (*t2)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid i/o address %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_PORT_BASE;
+ return;
+ }
+
+ board.port = (unsigned char *)simple_strtoul(str, NULL, 16);
+ last = index;
+ break;
+
+ case 6:
+ t2 = str;
+ while (isxdigit(*t2))
+ t2++;
+
+ if (*t2)
+ {
+ printk(KERN_ERR "<Error> - epca_setup: Invalid memory base %s\n",str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_MEM_BASE;
+ return;
+ }
+
+ board.membase = (unsigned char *)simple_strtoul(str, NULL, 16);
+ last = index;
+ break;
+
+ default:
+ printk(KERN_ERR "PC/Xx: Too many string parms\n");
+ return;
+ }
+ str = temp;
+
+ } /* End while there is a string arg */
+
+
+ if (last < 6)
+ {
+ printk(KERN_ERR "PC/Xx: Insufficient parms specified\n");
+ return;
+ }
+
+ /* I should REALLY validate the stuff here */
+
+ /* Copies our local copy of board into boards */
+ memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board));
+
+
+ /* Does this get called once per lilo arg are what ? */
+
+ printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
+ num_cards, board_desc[board.type],
+ board.numports, (int)board.port, (unsigned int) board.membase);
+
+ num_cards++;
+
+} /* End epca_setup */
+
+
+
+#ifdef ENABLE_PCI
+/* --------------------- Begin get_PCI_configuration ---------------------- */
+
+int get_PCI_configuration(char bus, char device_fn,
+ unsigned int *base_addr0, unsigned int *base_addr1,
+ unsigned int *base_addr2, unsigned int *base_addr3,
+ unsigned int *base_addr4, unsigned int *base_addr5)
+{ /* Begin get_PCI_configuration */
+
+ int error;
+
+ error = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0,
+ base_addr0);
+
+ error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1,
+ base_addr1);
+
+ error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_2,
+ base_addr2);
+
+ error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_3,
+ base_addr3);
+
+ error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_4,
+ base_addr4);
+
+ error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_5,
+ base_addr5);
+
+ /* ------------------------------------------------------------------------
+ NOTE - The code below mask out either the 2 or 4 bits dependant on the
+ space being addressed. (base_addr value reflecting io space, have their
+ first 2 bits mask out, while base_addr value reflecting mem space, have
+ their first 4 bits mask out.) These bits are flag bits and should always
+ be 0 when used as an address.
+ ---------------------------------------------------------------------------- */
+
+ if ((*base_addr0) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+ (*base_addr0) &= PCI_BASE_ADDRESS_IO_MASK;
+ else
+ (*base_addr0) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ if ((*base_addr1) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+ (*base_addr1) &= PCI_BASE_ADDRESS_IO_MASK;
+ else
+ (*base_addr1) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ if ((*base_addr2) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+ (*base_addr2) &= PCI_BASE_ADDRESS_IO_MASK;
+ else
+ (*base_addr2) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ if ((*base_addr3) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+ (*base_addr3) &= PCI_BASE_ADDRESS_IO_MASK;
+ else
+ (*base_addr3) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ if ((*base_addr4) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+ (*base_addr4) &= PCI_BASE_ADDRESS_IO_MASK;
+ else
+ (*base_addr4) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ if ((*base_addr5) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+ (*base_addr5) &= PCI_BASE_ADDRESS_IO_MASK;
+ else
+ (*base_addr5) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ if (error)
+ {
+ printk(KERN_ERR "<Error> - DIGI PCI error: board not initializing due to error\n");
+ return(0);
+ }
+ return(1);
+} /* End get_PCI_configuration */
+
+/* ------------------------ Begin init_PCI --------------------------- */
+
+int init_PCI(int boards_found)
+{ /* Begin init_PCI */
+
+ unsigned char bus, device_fn;
+ int i, pci_count = 0;
+ unsigned int base_addr0, base_addr1, base_addr2,
+ base_addr3, base_addr4, base_addr5;
+
+ base_addr0 = base_addr1 = base_addr2 = 0;
+ base_addr3 = base_addr4 = base_addr5 = 0;
+
+ for(i = 0; i < (MAXBOARDS - boards_found); i++)
+ { /* Begin for each POSSIBLE remaining board */
+
+ if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_XR,
+ i, &bus, &device_fn))
+ { /* Begin found XR */
+ if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1,
+ &base_addr2, &base_addr3,
+ &base_addr4, &base_addr5))
+ { /* Store a PCI/XR into the boards structure */
+
+
+ boards[boards_found + pci_count].status = ENABLED;
+ boards[boards_found + pci_count].type = PCIXR;
+
+ boards[boards_found + pci_count].numports = 0x0;
+
+ boards[boards_found + pci_count].port = (unsigned char *)((char *)base_addr0 + PCI_IO_OFFSET);
+ /* Most cards use base_addr0, but some use base_addr2 */
+ boards[boards_found + pci_count].membase = (unsigned char *)base_addr0;
+
+ if (base_addr0 >= 0x100000)
+ {
+ /* ------------------------------------------------------------
+ Standard physical addresses are valid to the kernel as long
+ as they aren't above RAM. Higher addresses (Such as are
+ typical of a PCI system) need to be mapped in with the
+ ioremap command. For boards using such high addresses the
+ driver will store both addresses. One address (The physical)
+ will be held for the apps use (And mmap) and the other (The
+ ioremapped address) will be used in the kernel.
+
+ ---------------------------------------------------------------- */
+ boards[boards_found + pci_count].re_map_port = ioremap((base_addr0 + PCI_IO_OFFSET),0x200000);
+ boards[boards_found + pci_count].re_map_membase = ioremap(base_addr0, 0x200000);
+ }
+
+ pci_count++;
+
+ /* --------------------------------------------------------------
+ I don't know what the below does, but the hardware guys say
+ its required on everything except PLX (In this case XRJ).
+ ---------------------------------------------------------------- */
+ pcibios_write_config_byte(bus, device_fn, 0x40, 0);
+ pcibios_write_config_byte(bus, device_fn, 0x46, 0);
+
+ } /* End store a PCI/XR into the board structure */
+
+ } /* End found XR */
+
+ if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_XEM,
+ i, &bus, &device_fn))
+ { /* Begin found XEM */
+
+ if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1,
+ &base_addr2, &base_addr3,
+ &base_addr4, &base_addr5))
+ { /* Begin store a PCI/XEM into the boards structure */
+
+ boards[boards_found + pci_count].status = ENABLED;
+ boards[boards_found + pci_count].type = PCIXEM;
+
+ boards[boards_found + pci_count].numports = 0x0;
+ boards[boards_found + pci_count].port = (char *)((char *)base_addr0 + PCI_IO_OFFSET);
+ /* Most cards use base_addr0, but some use base_addr2 */
+ boards[boards_found + pci_count].membase = (unsigned char *)base_addr0;
+
+ if (base_addr0 >= 0x100000)
+ {
+ /* ------------------------------------------------------------
+ Standard physical addresses are valid to the kernel as long
+ as they aren't above RAM. Higher addresses (Such as are
+ typical of a PCI system) need to be mapped in with the
+ ioremap command. For boards using such high addresses the
+ driver will store both addresses. One address (The physical)
+ will be held for the apps use (And mmap) and the other (The
+ vremapped address) will be used in the kernel.
+
+ ---------------------------------------------------------------- */
+ boards[boards_found + pci_count].re_map_port = ioremap((base_addr0 + PCI_IO_OFFSET),0x200000);
+ boards[boards_found + pci_count].re_map_membase = ioremap(base_addr0, 0x200000);
+ }
+
+ pci_count++;
+ /* --------------------------------------------------------------
+ I don't know what the below does, but the hardware guys say
+ its required on everything except PLX (In this case XRJ).
+ ---------------------------------------------------------------- */
+ pcibios_write_config_byte(bus, device_fn, 0x40, 0);
+ pcibios_write_config_byte(bus, device_fn, 0x46, 0);
+
+ } /* End store a PCI/XEM into the boards structure */
+
+ } /* End found XEM */
+
+
+ if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_CX,
+ i, &bus, &device_fn))
+ { /* Begin found CX */
+
+ if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1,
+ &base_addr2, &base_addr3,
+ &base_addr4, &base_addr5))
+ { /* Begin store a PCI/CX into the boards structure */
+
+ boards[boards_found + pci_count].status = ENABLED;
+ boards[boards_found + pci_count].type = PCICX;
+
+ boards[boards_found + pci_count].numports = 0x0;
+ boards[boards_found + pci_count].port = (char *)((char *)base_addr0 + PCI_IO_OFFSET);
+ /* Most cards use base_addr0, but some use base_addr2 */
+ boards[boards_found + pci_count].membase = (unsigned char *)base_addr0;
+
+ if (base_addr0 >= 0x100000)
+ {
+ /* ------------------------------------------------------------
+ Standard physical addresses are valid to the kernel as long
+ as they aren't above RAM. Higher addresses (Such as are
+ typical of a PCI system) need to be mapped in with the
+ ioremap command. For boards using such high addresses the
+ driver will store both addresses. One address (The physical)
+ will be held for the apps use (And mmap) and the other (The
+ vremapped address) will be used in the kernel.
+
+ ---------------------------------------------------------------- */
+ boards[boards_found + pci_count].re_map_port = ioremap((base_addr0 + PCI_IO_OFFSET),0x200000);
+ boards[boards_found + pci_count].re_map_membase = ioremap(base_addr0, 0x200000);
+ }
+
+ pci_count++;
+ /* --------------------------------------------------------------
+ I don't know what the below does, but the hardware guys say
+ its required on everything except PLX (In this case XRJ).
+ ---------------------------------------------------------------- */
+ pcibios_write_config_byte(bus, device_fn, 0x40, 0);
+ pcibios_write_config_byte(bus, device_fn, 0x46, 0);
+
+ } /* End store a PCI/CX into the boards structure */
+
+ } /* End found CX */
+
+ if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_XRJ,
+ i, &bus, &device_fn))
+ { /* Begin found XRJ */
+
+ if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1,
+ &base_addr2, &base_addr3,
+ &base_addr4, &base_addr5))
+ { /* Begin store a PCI/XRJ into the boards structure */
+
+ boards[boards_found + pci_count].status = ENABLED;
+ boards[boards_found + pci_count].type = PCIXRJ;
+
+ boards[boards_found + pci_count].numports = 0x0;
+ boards[boards_found + pci_count].port = (unsigned char *)(base_addr2 + PCI_IO_OFFSET);
+ /* Most cards use base_addr0, but some use base_addr2 */
+ boards[boards_found + pci_count].membase = (unsigned char *)base_addr2;
+
+ if (base_addr2 >= 0x100000)
+ {
+ /* ------------------------------------------------------------
+ Standard physical addresses are valid to the kernel as long
+ as they aren't above RAM. Higher addresses (Such as are
+ typical of a PCI system) need to be mapped in with the
+ ioremap command. For boards using such high addresses the
+ driver will store both addresses. One address (The physical)
+ will be held for the apps use (And mmap) and the other (The
+ vremapped address) will be used in the kernel.
+
+ ---------------------------------------------------------------- */
+ boards[boards_found + pci_count].re_map_port = ioremap((base_addr2 + PCI_IO_OFFSET),0x200000);
+ boards[boards_found + pci_count].re_map_membase = ioremap(base_addr2, 0x200000);
+ }
+
+ pci_count++;
+
+ } /* End store a PCI/XRJ into the boards structure */
+
+ } /* End found XRJ */
+
+ } /* End for each POSSIBLE remaining board */
+
+ return(pci_count);
+
+} /* End init_PCI */
+
+#endif /* ENABLE_PCI */
+
+
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index c1eb47de0..42ed91080 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -689,7 +689,7 @@ static void do_softint(void *private_)
if (!tty)
return;
- if (clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) {
+ if (test_and_clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) {
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
diff --git a/drivers/char/fbmem.c b/drivers/char/fbmem.c
index 1493f4932..b267f84d3 100644
--- a/drivers/char/fbmem.c
+++ b/drivers/char/fbmem.c
@@ -16,6 +16,7 @@
#include <linux/malloc.h>
#include <linux/mman.h>
#include <linux/tty.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
@@ -300,8 +301,8 @@ unregister_framebuffer(int node)
return 0;
}
-void
-fbmem_init(void)
+__initfunc(void
+fbmem_init(void))
{
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);
diff --git a/drivers/char/ftape/kernel-interface.c b/drivers/char/ftape/kernel-interface.c
index 31719a451..9bcb35e46 100644
--- a/drivers/char/ftape/kernel-interface.c
+++ b/drivers/char/ftape/kernel-interface.c
@@ -29,6 +29,7 @@
#include <linux/signal.h>
#include <linux/major.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <linux/ftape.h>
#include <asm/dma.h>
@@ -120,7 +121,7 @@ EXPORT_NO_SYMBOLS;
#define ftape_init init_module
#endif
-int ftape_init(void)
+__initfunc(int ftape_init(void))
{
int n;
int order;
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index a0f2f10c5..f21693bff 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -1005,7 +1005,7 @@ static int stli_initopen(stlibrd_t *brdp, stliport_t *portp)
set_bit(ST_GETSIGS, &portp->state);
if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig, sizeof(asysigs_t), 1)) < 0)
return(rc);
- if (clear_bit(ST_GETSIGS, &portp->state))
+ if (test_and_clear_bit(ST_GETSIGS, &portp->state))
portp->sigs = stli_mktiocm(portp->asig.sigvalue);
stli_mkasysigs(&portp->asig, 1, 1);
if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0)) < 0)
diff --git a/drivers/char/keyb_m68k.c b/drivers/char/keyb_m68k.c
deleted file mode 100644
index 587d61a4b..000000000
--- a/drivers/char/keyb_m68k.c
+++ /dev/null
@@ -1,876 +0,0 @@
-/*
- * linux/drivers/char/keyboard.c
- *
- * Keyboard driver for Linux v0.99 using Latin-1.
- *
- * Written for linux by Johan Myreen as a translation from
- * the assembly version by Linus (with diacriticals added)
- *
- * Some additional features added by Christoph Niemann (ChN), March 1993
- *
- * Loadable keymaps by Risto Kankkunen, May 1993
- *
- * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
- * Added decr/incr_console, dynamic keymaps, Unicode support,
- * dynamic function/string keys, led setting, Sept 1994
- * `Sticky' modifier keys, 951006.
- *
- */
-
-/*
- * modified to provide 'generic' keyboard support by Hamish Macdonald
- */
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/mm.h>
-#include <linux/random.h>
-#include <linux/init.h>
-
-#include <asm/bitops.h>
-#include <asm/machdep.h>
-
-#include "kbd_kern.h"
-#include "diacr.h"
-#include "vt_kern.h"
-
-#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
-
-#define KBD_REPORT_ERR
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
-
-#ifndef KBD_DEFMODE
-#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
-#endif
-
-#ifndef KBD_DEFLEDS
-/*
- * Some laptops take the 789uiojklm,. keys as number pad when NumLock
- * is on. This seems a good reason to start with NumLock off.
- */
-#define KBD_DEFLEDS 0
-#endif
-
-#ifndef KBD_DEFLOCK
-#define KBD_DEFLOCK 0
-#endif
-
-/*
- * The default IO slowdown is doing 'inb()'s from 0x61, which should be
- * safe. But as that is the keyboard controller chip address, we do our
- * slowdowns here by doing short jumps: the keyboard controller should
- * be able to keep up
- */
-#define REALLY_SLOW_IO
-#define SLOW_IO_BY_JUMPING
-#include <asm/io.h>
-#include <asm/system.h>
-
-extern void poke_blanked_console(void);
-extern void ctrl_alt_del(void);
-extern void reset_vc(unsigned int new_console);
-extern void scrollback(int);
-extern void scrollfront(int);
-extern int vc_cons_allocated(unsigned int);
-
-unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
-
-struct wait_queue * keypress_wait = NULL;
-
-void keyboard_wait_for_keypress(void)
-{
- sleep_on(&keypress_wait);
-}
-
-/*
- * global state includes the following, and various static variables
- * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next.
- * (last_console is now a global variable)
- */
-
-/* shift state counters.. */
-static unsigned char k_down[NR_SHIFT] = {0, };
-/* keyboard key bitmap */
-#define BITS_PER_LONG (8*sizeof(unsigned long))
-static unsigned long key_down[256/BITS_PER_LONG] = { 0, };
-
-static int dead_key_next = 0;
-/*
- * In order to retrieve the shift_state (for the mouse server), either
- * the variable must be global, or a new procedure must be created to
- * return the value. I chose the former way.
- */
-/*static*/ int shift_state = 0;
-static int npadch = -1; /* -1 or number assembled on pad */
-static unsigned char diacr = 0;
-static char rep = 0; /* flag telling character repeat */
-struct kbd_struct kbd_table[MAX_NR_CONSOLES];
-static struct tty_struct **ttytab;
-static struct kbd_struct *kbd = kbd_table;
-static struct tty_struct *tty = NULL;
-
-extern void compute_shiftstate(void);
-
-typedef void (*k_hand)(unsigned char value, char up_flag);
-typedef void (k_handfn)(unsigned char value, char up_flag);
-
-static k_handfn
- do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
- do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_ignore;
-
-static k_hand key_handler[16] = {
- do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
- do_meta, do_ascii, do_lock, do_lowercase, do_slock,
- do_ignore, do_ignore, do_ignore
-};
-
-typedef void (*void_fnp)(void);
-typedef void (void_fn)(void);
-
-static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle,
- num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose,
- SAK, decr_console, incr_console, spawn_console, bare_num;
-
-static void_fnp spec_fn_table[] = {
- do_null, enter, show_ptregs, show_mem,
- show_state, send_intr, lastcons, caps_toggle,
- num, hold, scroll_forw, scroll_back,
- boot_it, caps_on, compose, SAK,
- decr_console, incr_console, spawn_console, bare_num
-};
-
-/* maximum values each key_handler can handle */
-const int max_vals[] = {
- 255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
- NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
- 255, NR_ASCII - 1, NR_LOCK - 1, 255,
- NR_LOCK - 1
-};
-
-const int NR_TYPES = SIZE(max_vals);
-
-static void put_queue(int);
-static unsigned char handle_diacr(unsigned char);
-
-/*
- * Many other routines do put_queue, but I think either
- * they produce ASCII, or they produce some user-assigned
- * string, and in both cases we might assume that it is
- * in utf-8 already.
- */
-void to_utf8(ushort c) {
- if (c < 0x80)
- put_queue(c); /* 0******* */
- else if (c < 0x800) {
- put_queue(0xc0 | (c >> 6)); /* 110***** 10****** */
- put_queue(0x80 | (c & 0x3f));
- } else {
- put_queue(0xe0 | (c >> 12)); /* 1110**** 10****** 10****** */
- put_queue(0x80 | ((c >> 6) & 0x3f));
- put_queue(0x80 | (c & 0x3f));
- }
- /* UTF-8 is defined for words of up to 31 bits,
- but we need only 16 bits here */
-}
-
-void process_keycode (int keycode)
-{
- char up_flag; /* 0 or 0200 */
- char raw_mode;
-
- do_poke_blanked_console = 1;
- mark_bh(KEYBOARD_BH);
- add_keyboard_randomness(keycode);
-
- tty = ttytab[fg_console];
- kbd = kbd_table + fg_console;
- if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
- put_queue(keycode);
- /* we do not return yet, because we want to maintain
- the key_down array, so that we have the correct
- values when finishing RAW mode or when changing VT's */
- }
-
- /*
- * At this point the variable `keycode' contains the keycode.
- * Note: the keycode must not be 0.
- * We keep track of the up/down status of the key, and
- * return the keycode if in MEDIUMRAW mode.
- */
-
- up_flag = (keycode & 0200);
- keycode &= 0x7f;
- if (up_flag) {
- rep = 0;
- if(!clear_bit(keycode, key_down)) {
- /* unexpected, but this can happen:
- maybe this was a key release for a FOCUS 9000
- PF key; if we want to see it, we have to clear
- up_flag */
-#ifndef __mc68000__
- if (keycode >= SC_LIM || keycode == 85)
- up_flag = 0;
-#endif
- }
- } else
- rep = set_bit(keycode, key_down);
-
- if (raw_mode)
- return;
-
- if (kbd->kbdmode == VC_MEDIUMRAW) {
- /* soon keycodes will require more than one byte */
- put_queue(keycode + up_flag);
- return;
- }
-
- /*
- * Small change in philosophy: earlier we defined repetition by
- * rep = keycode == prev_keycode;
- * prev_keycode = keycode;
- * but now by the fact that the depressed key was down already.
- * Does this ever make a difference? Yes.
- */
-
- /*
- * Repeat a key only if the input buffers are empty or the
- * characters get echoed locally. This makes key repeat usable
- * with slow applications and under heavy loads.
- */
- if (!rep ||
- (vc_kbd_mode(kbd,VC_REPEAT) && tty &&
- (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) {
- u_short keysym;
- u_char type;
-
- /* the XOR below used to be an OR */
- int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate;
- ushort *key_map = key_maps[shift_final];
-
- if (key_map != NULL) {
- keysym = key_map[keycode];
- type = KTYP(keysym);
-
- if (type >= 0xf0) {
- type -= 0xf0;
- if (type == KT_LETTER) {
- type = KT_LATIN;
- if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
- key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
- if (key_map)
- keysym = key_map[keycode];
- }
- }
- (*key_handler[type])(keysym & 0xff, up_flag);
- if (type != KT_SLOCK)
- kbd->slockstate = 0;
- } else {
- /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */
- if (!up_flag)
- to_utf8(keysym);
- }
- } else {
- /* maybe beep? */
- /* we have at least to update shift_state */
-#if 1 /* how? two almost equivalent choices follow */
- compute_shiftstate();
-#else
- keysym = U(plain_map[keycode]);
- type = KTYP(keysym);
- if (type == KT_SHIFT)
- (*key_handler[type])(keysym & 0xff, up_flag);
-#endif
- }
- }
-}
-
-static void put_queue(int ch)
-{
- wake_up(&keypress_wait);
- if (tty) {
- tty_insert_flip_char(tty, ch, 0);
- tty_schedule_flip(tty);
- }
-}
-
-static void puts_queue(char *cp)
-{
- wake_up(&keypress_wait);
- if (!tty)
- return;
-
- while (*cp) {
- tty_insert_flip_char(tty, *cp, 0);
- cp++;
- }
- tty_schedule_flip(tty);
-}
-
-static void applkey(int key, char mode)
-{
- static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
-
- buf[1] = (mode ? 'O' : '[');
- buf[2] = key;
- puts_queue(buf);
-}
-
-static void enter(void)
-{
- put_queue(13);
- if (vc_kbd_mode(kbd,VC_CRLF))
- put_queue(10);
-}
-
-static void caps_toggle(void)
-{
- if (rep)
- return;
- chg_vc_kbd_led(kbd, VC_CAPSLOCK);
-}
-
-static void caps_on(void)
-{
- if (rep)
- return;
- set_vc_kbd_led(kbd, VC_CAPSLOCK);
-}
-
-struct pt_regs *pt_regs;
-
-static void show_ptregs(void)
-{
- if (pt_regs)
- show_regs(pt_regs);
- return;
-}
-
-static void hold(void)
-{
- if (rep || !tty)
- return;
-
- /*
- * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
- * these routines are also activated by ^S/^Q.
- * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
- */
- if (tty->stopped)
- start_tty(tty);
- else
- stop_tty(tty);
-}
-
-static void num(void)
-{
- if (vc_kbd_mode(kbd,VC_APPLIC))
- applkey('P', 1);
- else
- bare_num();
-}
-
-/*
- * Bind this to Shift-NumLock if you work in application keypad mode
- * but want to be able to change the NumLock flag.
- * Bind this to NumLock if you prefer that the NumLock key always
- * changes the NumLock flag.
- */
-static void bare_num(void)
-{
- if (!rep)
- chg_vc_kbd_led(kbd,VC_NUMLOCK);
-}
-
-static void lastcons(void)
-{
- /* switch to the last used console, ChN */
- set_console(last_console);
-}
-
-static void decr_console(void)
-{
- int i;
-
- for (i = fg_console-1; i != fg_console; i--) {
- if (i == -1)
- i = MAX_NR_CONSOLES-1;
- if (vc_cons_allocated(i))
- break;
- }
- set_console(i);
-}
-
-static void incr_console(void)
-{
- int i;
-
- for (i = fg_console+1; i != fg_console; i++) {
- if (i == MAX_NR_CONSOLES)
- i = 0;
- if (vc_cons_allocated(i))
- break;
- }
- set_console(i);
-}
-
-static void send_intr(void)
-{
- if (!tty)
- return;
- tty_insert_flip_char(tty, 0, TTY_BREAK);
- tty_schedule_flip(tty);
-}
-
-static void scroll_forw(void)
-{
- scrollfront(0);
-}
-
-static void scroll_back(void)
-{
- scrollback(0);
-}
-
-static void boot_it(void)
-{
- ctrl_alt_del();
-}
-
-static void compose(void)
-{
- dead_key_next = 1;
-}
-
-int spawnpid, spawnsig;
-
-static void spawn_console(void)
-{
- if (spawnpid)
- if(kill_proc(spawnpid, spawnsig, 1))
- spawnpid = 0;
-}
-
-static void SAK(void)
-{
- do_SAK(tty);
-#if 0
- /*
- * Need to fix SAK handling to fix up RAW/MEDIUM_RAW and
- * vt_cons modes before we can enable RAW/MEDIUM_RAW SAK
- * handling.
- *
- * We should do this some day --- the whole point of a secure
- * attention key is that it should be guaranteed to always
- * work.
- */
- reset_vc(fg_console);
- do_unblank_screen(); /* not in interrupt routine? */
-#endif
-}
-
-static void do_ignore(unsigned char value, char up_flag)
-{
-}
-
-static void do_null()
-{
- compute_shiftstate();
-}
-
-static void do_spec(unsigned char value, char up_flag)
-{
- if (up_flag)
- return;
- if (value >= SIZE(spec_fn_table))
- return;
- spec_fn_table[value]();
-}
-
-static void do_lowercase(unsigned char value, char up_flag)
-{
- printk("keyboard.c: do_lowercase was called - impossible\n");
-}
-
-static void do_self(unsigned char value, char up_flag)
-{
- if (up_flag)
- return; /* no action, if this is a key release */
-
- if (diacr)
- value = handle_diacr(value);
-
- if (dead_key_next) {
- dead_key_next = 0;
- diacr = value;
- return;
- }
-
- put_queue(value);
-}
-
-#define A_GRAVE '`'
-#define A_ACUTE '\''
-#define A_CFLEX '^'
-#define A_TILDE '~'
-#define A_DIAER '"'
-#define A_CEDIL ','
-static unsigned char ret_diacr[NR_DEAD] =
- {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL };
-
-/* If a dead key pressed twice, output a character corresponding to it, */
-/* otherwise just remember the dead key. */
-
-static void do_dead(unsigned char value, char up_flag)
-{
- if (up_flag)
- return;
-
- value = ret_diacr[value];
- if (diacr == value) { /* pressed twice */
- diacr = 0;
- put_queue(value);
- return;
- }
- diacr = value;
-}
-
-
-/* If space is pressed, return the character corresponding the pending */
-/* dead key, otherwise try to combine the two. */
-
-unsigned char handle_diacr(unsigned char ch)
-{
- int d = diacr;
- int i;
-
- diacr = 0;
- if (ch == ' ')
- return d;
-
- for (i = 0; i < accent_table_size; i++) {
- if (accent_table[i].diacr == d && accent_table[i].base == ch)
- return accent_table[i].result;
- }
-
- put_queue(d);
- return ch;
-}
-
-static void do_cons(unsigned char value, char up_flag)
-{
- if (up_flag)
- return;
- set_console(value);
-}
-
-static void do_fn(unsigned char value, char up_flag)
-{
- if (up_flag)
- return;
- if (value < SIZE(func_table)) {
- if (func_table[value])
- puts_queue(func_table[value]);
- } else
- printk("do_fn called with value=%d\n", value);
-}
-
-static void do_pad(unsigned char value, char up_flag)
-{
- static const char *pad_chars = "0123456789+-*/\015,.?";
- static const char *app_map = "pqrstuvwxylSRQMnn?";
-
- if (up_flag)
- return; /* no action, if this is a key release */
-
- /* kludge... shift forces cursor/number keys */
- if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) {
- applkey(app_map[value], 1);
- return;
- }
-
- if (!vc_kbd_led(kbd,VC_NUMLOCK))
- switch (value) {
- case KVAL(K_PCOMMA):
- case KVAL(K_PDOT):
- do_fn(KVAL(K_REMOVE), 0);
- return;
- case KVAL(K_P0):
- do_fn(KVAL(K_INSERT), 0);
- return;
- case KVAL(K_P1):
- do_fn(KVAL(K_SELECT), 0);
- return;
- case KVAL(K_P2):
- do_cur(KVAL(K_DOWN), 0);
- return;
- case KVAL(K_P3):
- do_fn(KVAL(K_PGDN), 0);
- return;
- case KVAL(K_P4):
- do_cur(KVAL(K_LEFT), 0);
- return;
- case KVAL(K_P6):
- do_cur(KVAL(K_RIGHT), 0);
- return;
- case KVAL(K_P7):
- do_fn(KVAL(K_FIND), 0);
- return;
- case KVAL(K_P8):
- do_cur(KVAL(K_UP), 0);
- return;
- case KVAL(K_P9):
- do_fn(KVAL(K_PGUP), 0);
- return;
- case KVAL(K_P5):
- applkey('G', vc_kbd_mode(kbd, VC_APPLIC));
- return;
- }
-
- put_queue(pad_chars[value]);
- if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
- put_queue(10);
-}
-
-static void do_cur(unsigned char value, char up_flag)
-{
- static const char *cur_chars = "BDCA";
- if (up_flag)
- return;
-
- applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE));
-}
-
-static void do_shift(unsigned char value, char up_flag)
-{
- int old_state = shift_state;
-
- if (rep)
- return;
-
- /* Mimic typewriter:
- a CapsShift key acts like Shift but undoes CapsLock */
- if (value == KVAL(K_CAPSSHIFT)) {
- value = KVAL(K_SHIFT);
- if (!up_flag)
- clr_vc_kbd_led(kbd, VC_CAPSLOCK);
- }
-
- if (up_flag) {
- /* handle the case that two shift or control
- keys are depressed simultaneously */
- if (k_down[value])
- k_down[value]--;
- } else
- k_down[value]++;
-
- if (k_down[value])
- shift_state |= (1 << value);
- else
- shift_state &= ~ (1 << value);
-
- /* kludge */
- if (up_flag && shift_state != old_state && npadch != -1) {
- if (kbd->kbdmode == VC_UNICODE)
- to_utf8(npadch & 0xffff);
- else
- put_queue(npadch & 0xff);
- npadch = -1;
- }
-}
-
-/* called after returning from RAW mode or when changing consoles -
- recompute k_down[] and shift_state from key_down[] */
-/* maybe called when keymap is undefined, so that shiftkey release is seen */
-void compute_shiftstate(void)
-{
- int i, j, k, sym, val;
-
- shift_state = 0;
- for(i=0; i < SIZE(k_down); i++)
- k_down[i] = 0;
-
- for(i=0; i < SIZE(key_down); i++)
- if(key_down[i]) { /* skip this word if not a single bit on */
- k = i*BITS_PER_LONG;
- for(j=0; j<BITS_PER_LONG; j++,k++)
- if(test_bit(k, key_down)) {
- sym = U(plain_map[k]);
- if(KTYP(sym) == KT_SHIFT) {
- val = KVAL(sym);
- if (val == KVAL(K_CAPSSHIFT))
- val = KVAL(K_SHIFT);
- k_down[val]++;
- shift_state |= (1<<val);
- }
- }
- }
-}
-
-static void do_meta(unsigned char value, char up_flag)
-{
- if (up_flag)
- return;
-
- if (vc_kbd_mode(kbd, VC_META)) {
- put_queue('\033');
- put_queue(value);
- } else
- put_queue(value | 0x80);
-}
-
-static void do_ascii(unsigned char value, char up_flag)
-{
- int base;
-
- if (up_flag)
- return;
-
- if (value < 10) /* decimal input of code, while Alt depressed */
- base = 10;
- else { /* hexadecimal input of code, while AltGr depressed */
- value -= 10;
- base = 16;
- }
-
- if (npadch == -1)
- npadch = value;
- else
- npadch = npadch * base + value;
-}
-
-static void do_lock(unsigned char value, char up_flag)
-{
- if (up_flag || rep)
- return;
- chg_vc_kbd_lock(kbd, value);
-}
-
-static void do_slock(unsigned char value, char up_flag)
-{
- if (up_flag || rep)
- return;
- chg_vc_kbd_slock(kbd, value);
-}
-
-/*
- * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
- * or (ii) whatever pattern of lights people want to show using KDSETLED,
- * or (iii) specified bits of specified words in kernel memory.
- */
-
-static unsigned char ledstate = 0xff; /* undefined */
-static unsigned char ledioctl;
-
-unsigned char getledstate(void) {
- return ledstate;
-}
-
-void setledstate(struct kbd_struct *kbd, unsigned int led) {
- if (!(led & ~7)) {
- ledioctl = led;
- kbd->ledmode = LED_SHOW_IOCTL;
- } else
- kbd->ledmode = LED_SHOW_FLAGS;
- set_leds();
-}
-
-static struct ledptr {
- unsigned int *addr;
- unsigned int mask;
- unsigned char valid:1;
-} ledptrs[3];
-
-void register_leds(int console, unsigned int led,
- unsigned int *addr, unsigned int mask) {
- struct kbd_struct *kbd = kbd_table + console;
- if (led < 3) {
- ledptrs[led].addr = addr;
- ledptrs[led].mask = mask;
- ledptrs[led].valid = 1;
- kbd->ledmode = LED_SHOW_MEM;
- } else
- kbd->ledmode = LED_SHOW_FLAGS;
-}
-
-static inline unsigned char getleds(void){
- struct kbd_struct *kbd = kbd_table + fg_console;
- unsigned char leds;
-
- if (kbd->ledmode == LED_SHOW_IOCTL)
- return ledioctl;
- leds = kbd->ledflagstate;
- if (kbd->ledmode == LED_SHOW_MEM) {
- if (ledptrs[0].valid) {
- if (*ledptrs[0].addr & ledptrs[0].mask)
- leds |= 1;
- else
- leds &= ~1;
- }
- if (ledptrs[1].valid) {
- if (*ledptrs[1].addr & ledptrs[1].mask)
- leds |= 2;
- else
- leds &= ~2;
- }
- if (ledptrs[2].valid) {
- if (*ledptrs[2].addr & ledptrs[2].mask)
- leds |= 4;
- else
- leds &= ~4;
- }
- }
- return leds;
-}
-
-/*
- * This routine is the bottom half of the keyboard interrupt
- * routine, and runs with all interrupts enabled. It does
- * console changing, led setting and copy_to_cooked, which can
- * take a reasonably long time.
- *
- * Aside from timing (which isn't really that important for
- * keyboard interrupts as they happen often), using the software
- * interrupt routines for this thing allows us to easily mask
- * this when we don't want any of the above to happen. Not yet
- * used, but this allows for easy and efficient race-condition
- * prevention later on.
- */
-static void kbd_bh(void)
-{
- unsigned char leds = getleds();
-
- if (leds != ledstate) {
- ledstate = leds;
- if (mach_kbd_leds)
- mach_kbd_leds(leds);
- }
-}
-
-__initfunc(int kbd_init(void))
-{
- int i;
- struct kbd_struct kbd0;
- extern struct tty_driver console_driver;
-
- kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
- kbd0.ledmode = LED_SHOW_FLAGS;
- kbd0.lockstate = KBD_DEFLOCK;
- kbd0.slockstate = 0;
- kbd0.modeflags = KBD_DEFMODE;
- kbd0.kbdmode = VC_XLATE;
-
- for (i = 0 ; i < MAX_NR_CONSOLES ; i++)
- kbd_table[i] = kbd0;
-
- ttytab = console_driver.table;
-
- init_bh(KEYBOARD_BH, kbd_bh);
- mark_bh(KEYBOARD_BH);
-
- mach_keyb_init ();
-
- return 0;
-}
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index d63aa20df..0185c2bda 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -1,4 +1,3 @@
-
/*
* linux/drivers/char/keyboard.c
*
@@ -14,41 +13,29 @@
* dynamic function/string keys, led setting, Sept 1994
* `Sticky' modifier keys, 951006.
* 11-11-96: SAK should now work in the raw mode (Martin Mares)
+ *
+ * Modified to provide 'generic' keyboard support by Hamish Macdonald
+ * Merge with the m68k keyboard driver and split-off of the PC low-level
+ * parts by Geert Uytterhoeven, May 1997
*/
-#include <linux/config.h>
-#include <linux/kbdcntrlr.h>
#include <linux/sched.h>
-#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/mm.h>
-#include <linux/ptrace.h>
-#include <linux/signal.h>
#include <linux/string.h>
-#include <linux/ioport.h>
#include <linux/random.h>
#include <linux/init.h>
+#include <asm/keyboard.h>
#include <asm/bitops.h>
-/*
- * Declare functions used in machine dependand parts of the kbd driver.
- */
-static inline void kb_wait(void);
-static int send_data(unsigned char data);
-
-#include <asm/keyboard.h>
-
#include "kbd_kern.h"
#include "diacr.h"
#include "vt_kern.h"
#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
-
#ifndef KBD_DEFMODE
#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
#endif
@@ -65,15 +52,11 @@ static int send_data(unsigned char data);
#define KBD_DEFLOCK 0
#endif
-#include <asm/system.h>
-
extern void ctrl_alt_del(void);
extern void reset_vc(unsigned int new_console);
extern void scrollback(int);
extern void scrollfront(int);
-unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
-
struct wait_queue * keypress_wait = NULL;
void keyboard_wait_for_keypress(void)
@@ -108,12 +91,7 @@ static struct tty_struct **ttytab;
static struct kbd_struct * kbd = kbd_table;
static struct tty_struct * tty = NULL;
-/* used only by send_data - set by keyboard_interrupt */
-static volatile unsigned char reply_expected = 0;
-static volatile unsigned char acknowledge = 0;
-static volatile unsigned char resend = 0;
-
-extern void compute_shiftstate(void);
+void compute_shiftstate(void);
typedef void (*k_hand)(unsigned char value, char up_flag);
typedef void (k_handfn)(unsigned char value, char up_flag);
@@ -163,23 +141,7 @@ static void put_queue(int);
static unsigned char handle_diacr(unsigned char);
/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
-static struct pt_regs * pt_regs;
-
-static inline void kb_wait(void)
-{
- int i;
-
- for (i=0; i<0x100000; i++)
- if ((kbd_inb_p(0x64) & 0x02) == 0)
- return;
- printk(KERN_WARNING "Keyboard timed out\n");
-}
-
-static inline void send_cmd(unsigned char c)
-{
- kb_wait();
- kbd_outb(c,0x64);
-}
+struct pt_regs * pt_regs;
/*
* Many other routines do put_queue, but I think either
@@ -204,182 +166,25 @@ void to_utf8(ushort c) {
/*
* Translation of escaped scancodes to keycodes.
- * This is now user-settable.
- * The keycodes 1-88,96-111,119 are fairly standard, and
- * should probably not be changed - changing might confuse X.
- * X also interprets scancode 0x5d (KEY_Begin).
- *
- * For 1-88 keycode equals scancode.
+ * This is now user-settable (for machines were it makes sense).
*/
-#define E0_KPENTER 96
-#define E0_RCTRL 97
-#define E0_KPSLASH 98
-#define E0_PRSCR 99
-#define E0_RALT 100
-#define E0_BREAK 101 /* (control-pause) */
-#define E0_HOME 102
-#define E0_UP 103
-#define E0_PGUP 104
-#define E0_LEFT 105
-#define E0_RIGHT 106
-#define E0_END 107
-#define E0_DOWN 108
-#define E0_PGDN 109
-#define E0_INS 110
-#define E0_DEL 111
-
-#define E1_PAUSE 119
-
-/*
- * The keycodes below are randomly located in 89-95,112-118,120-127.
- * They could be thrown away (and all occurrences below replaced by 0),
- * but that would force many users to use the `setkeycodes' utility, where
- * they needed not before. It does not matter that there are duplicates, as
- * long as no duplication occurs for any single keyboard.
- */
-#define SC_LIM 89
-
-#define FOCUS_PF1 85 /* actual code! */
-#define FOCUS_PF2 89
-#define FOCUS_PF3 90
-#define FOCUS_PF4 91
-#define FOCUS_PF5 92
-#define FOCUS_PF6 93
-#define FOCUS_PF7 94
-#define FOCUS_PF8 95
-#define FOCUS_PF9 120
-#define FOCUS_PF10 121
-#define FOCUS_PF11 122
-#define FOCUS_PF12 123
-
-#define JAP_86 124
-/* tfj@olivia.ping.dk:
- * The four keys are located over the numeric keypad, and are
- * labelled A1-A4. It's an rc930 keyboard, from
- * Regnecentralen/RC International, Now ICL.
- * Scancodes: 59, 5a, 5b, 5c.
- */
-#define RGN1 124
-#define RGN2 125
-#define RGN3 126
-#define RGN4 127
-
-static unsigned char high_keys[128 - SC_LIM] = {
- RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
- 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */
- 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */
- FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */
- FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */
-};
-
-/* BTC */
-#define E0_MACRO 112
-/* LK450 */
-#define E0_F13 113
-#define E0_F14 114
-#define E0_HELP 115
-#define E0_DO 116
-#define E0_F17 117
-#define E0_KPMINPLUS 118
-/*
- * My OmniKey generates e0 4c for the "OMNI" key and the
- * right alt key does nada. [kkoller@nyx10.cs.du.edu]
- */
-#define E0_OK 124
-/*
- * New microsoft keyboard is rumoured to have
- * e0 5b (left window button), e0 5c (right window button),
- * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
- * [or: Windows_L, Windows_R, TaskMan]
- */
-#define E0_MSLW 125
-#define E0_MSRW 126
-#define E0_MSTM 127
-
-static unsigned char e0_keys[128] = {
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */
- 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */
- 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */
- E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */
- E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */
- E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
- E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */
- 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
- 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */
- 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
-};
-
int setkeycode(unsigned int scancode, unsigned int keycode)
{
- if (scancode < SC_LIM || scancode > 255 || keycode > 127)
- return -EINVAL;
- if (scancode < 128)
- high_keys[scancode - SC_LIM] = keycode;
- else
- e0_keys[scancode - 128] = keycode;
- return 0;
+ return kbd_setkeycode(scancode, keycode);
}
int getkeycode(unsigned int scancode)
{
- return
- (scancode < SC_LIM || scancode > 255) ? -EINVAL :
- (scancode < 128) ? high_keys[scancode - SC_LIM] :
- e0_keys[scancode - 128];
+ return kbd_getkeycode(scancode);
}
-#if defined(CONFIG_SGI) && defined(CONFIG_PSMOUSE)
-extern void aux_interrupt(unsigned char status, unsigned char data);
-#endif
-
-#if DISABLE_KBD_DURING_INTERRUPTS
-#define disable_keyboard() do { send_cmd(0xAD); kb_wait(); } while (0)
-#define enable_keyboard() send_cmd(0xAE)
-#else
-#define disable_keyboard() /* nothing */
-#define enable_keyboard() /* nothing */
-#endif
-
-static void handle_scancode(unsigned char scancode)
+void handle_scancode(unsigned char scancode)
{
unsigned char keycode;
- static unsigned int prev_scancode = 0; /* remember E0, E1 */
char up_flag; /* 0 or 0200 */
char raw_mode;
- if (reply_expected) {
- /* 0xfa, 0xfe only mean "acknowledge", "resend" for most keyboards */
- /* but they are the key-up scancodes for PF6, PF10 on a FOCUS 9000 */
- reply_expected = 0;
- if (scancode == 0xfa) {
- acknowledge = 1;
- return;
- } else if (scancode == 0xfe) {
- resend = 1;
- return;
- }
- /* strange ... */
- reply_expected = 1;
-#if 0
- printk(KERN_DEBUG "keyboard reply expected - got %02x\n",
- scancode);
-#endif
- }
- if (scancode == 0) {
-#ifdef KBD_REPORT_ERR
- printk(KERN_INFO "keyboard buffer overflow\n");
-#endif
- prev_scancode = 0;
- return;
- }
do_poke_blanked_console = 1;
mark_bh(CONSOLE_BH);
add_keyboard_randomness(scancode);
@@ -393,123 +198,30 @@ static void handle_scancode(unsigned char scancode)
values when finishing RAW mode or when changing VT's */
}
- if (scancode == 0xff) {
- /* in scancode mode 1, my ESC key generates 0xff */
- /* the calculator keys on a FOCUS 9000 generate 0xff */
-#ifndef KBD_IS_FOCUS_9000
-#ifdef KBD_REPORT_ERR
- if (!raw_mode)
- printk(KERN_DEBUG "keyboard error\n");
-#endif
-#endif
- prev_scancode = 0;
- return;
- }
-
- if (scancode == 0xe0 || scancode == 0xe1) {
- prev_scancode = scancode;
- return;
- }
-
+ if (!kbd_pretranslate(scancode, raw_mode))
+ return;
/*
- * Convert scancode to keycode, using prev_scancode.
+ * Convert scancode to keycode
*/
up_flag = (scancode & 0200);
scancode &= 0x7f;
- if (prev_scancode) {
- /*
- * usually it will be 0xe0, but a Pause key generates
- * e1 1d 45 e1 9d c5 when pressed, and nothing when released
- */
- if (prev_scancode != 0xe0) {
- if (prev_scancode == 0xe1 && scancode == 0x1d) {
- prev_scancode = 0x100;
- return;
- } else if (prev_scancode == 0x100 && scancode == 0x45) {
- keycode = E1_PAUSE;
- prev_scancode = 0;
- } else {
-#ifdef KBD_REPORT_UNKN
- if (!raw_mode)
- printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
-#endif
- prev_scancode = 0;
- return;
- }
- } else {
- prev_scancode = 0;
- /*
- * The keyboard maintains its own internal caps lock and
- * num lock statuses. In caps lock mode E0 AA precedes make
- * code and E0 2A follows break code. In num lock mode,
- * E0 2A precedes make code and E0 AA follows break code.
- * We do our own book-keeping, so we will just ignore these.
- */
- /*
- * For my keyboard there is no caps lock mode, but there are
- * both Shift-L and Shift-R modes. The former mode generates
- * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
- * So, we should also ignore the latter. - aeb@cwi.nl
- */
- if (scancode == 0x2a || scancode == 0x36)
- return;
-
- if (e0_keys[scancode])
- keycode = e0_keys[scancode];
- else {
-#ifdef KBD_REPORT_UNKN
- if (!raw_mode)
- printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
- scancode);
-#endif
- return;
- }
- }
- } else if (scancode >= SC_LIM) {
- /* This happens with the FOCUS 9000 keyboard
- Its keys PF1..PF12 are reported to generate
- 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
- Moreover, unless repeated, they do not generate
- key-down events, so we have to zero up_flag below */
- /* Also, Japanese 86/106 keyboards are reported to
- generate 0x73 and 0x7d for \ - and \ | respectively. */
- /* Also, some Brazilian keyboard is reported to produce
- 0x73 and 0x7e for \ ? and KP-dot, respectively. */
-
- keycode = high_keys[scancode - SC_LIM];
-
- if (!keycode) {
- if (!raw_mode) {
-#ifdef KBD_REPORT_UNKN
- printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
- " - ignored\n", scancode);
-#endif
- }
- return;
- }
- } else
- keycode = scancode;
+ if (!kbd_translate(scancode, &keycode, raw_mode))
+ return;
/*
* At this point the variable `keycode' contains the keycode.
- * Note: the keycode must not be 0.
+ * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid).
* We keep track of the up/down status of the key, and
* return the keycode if in MEDIUMRAW mode.
*/
if (up_flag) {
rep = 0;
- if(!clear_bit(keycode, key_down)) {
- /* unexpected, but this can happen:
- maybe this was a key release for a FOCUS 9000
- PF key; if we want to see it, we have to clear
- up_flag */
- if (keycode >= SC_LIM || keycode == 85)
- up_flag = 0;
- }
+ if(!test_and_clear_bit(keycode, key_down))
+ up_flag = kbd_unexpected_up(keycode);
} else
- rep = set_bit(keycode, key_down);
+ rep = test_and_set_bit(keycode, key_down);
if (kbd->kbdmode == VC_MEDIUMRAW) {
/* soon keycodes will require more than one byte */
@@ -579,36 +291,6 @@ static void handle_scancode(unsigned char scancode)
}
}
-static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- unsigned char status;
-
- pt_regs = regs;
- disable_keyboard();
-
- status = kbd_inb_p(0x64);
- do {
- unsigned char scancode;
-
- /* mouse data? */
- if (status & kbd_read_mask & 0x20) {
-#if defined(CONFIG_SGI) && defined(CONFIG_PSMOUSE)
- scancode = kbd_inb(0x60);
- aux_interrupt(status, scancode);
-#endif
- break;
- }
-
- scancode = kbd_inb(0x60);
- if (status & 0x01)
- handle_scancode(scancode);
-
- status = kbd_inb(0x64);
- } while (status & 0x01);
-
- mark_bh(KEYBOARD_BH);
- enable_keyboard();
-}
static void put_queue(int ch)
{
@@ -898,8 +580,8 @@ static void do_fn(unsigned char value, char up_flag)
static void do_pad(unsigned char value, char up_flag)
{
- static const char *pad_chars = "0123456789+-*/\015,.?";
- static const char *app_map = "pqrstuvwxylSRQMnn?";
+ static const char *pad_chars = "0123456789+-*/\015,.?()";
+ static const char *app_map = "pqrstuvwxylSRQMnn?PQ";
if (up_flag)
return; /* no action, if this is a key release */
@@ -1075,35 +757,6 @@ static void do_slock(unsigned char value, char up_flag)
}
/*
- * send_data sends a character to the keyboard and waits
- * for an acknowledge, possibly retrying if asked to. Returns
- * the success status.
- */
-static int send_data(unsigned char data)
-{
- int retries = 3;
- int i;
-
- do {
- kb_wait();
- acknowledge = 0;
- resend = 0;
- reply_expected = 1;
- kbd_outb_p(data, 0x60);
- for(i=0; i<0x200000; i++) {
- kbd_inb_p(0x64); /* just as a delay */
- if (acknowledge)
- return 1;
- if (resend)
- break;
- }
- if (!resend)
- return 0;
- } while (retries-- > 0);
- return 0;
-}
-
-/*
* The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
* or (ii) whatever pattern of lights people want to show using KDSETLED,
* or (iii) specified bits of specified words in kernel memory.
@@ -1192,8 +845,7 @@ static void kbd_bh(void)
if (leds != ledstate) {
ledstate = leds;
- if (!send_data(0xed) || !send_data(leds))
- send_data(0xf4); /* re-enable kbd if any errors */
+ kbd_leds(leds);
}
}
@@ -1215,8 +867,7 @@ __initfunc(int kbd_init(void))
ttytab = console_driver.table;
- request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
- keyboard_setup();
+ kbd_init_hw();
init_bh(KEYBOARD_BH, kbd_bh);
mark_bh(KEYBOARD_BH);
return 0;
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 7fd2f9b35..599ae87fc 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -631,7 +631,7 @@ MODULE_PARM(parport, "1-" __MODULE_STRING(LP_NO) "i");
static int parport_ptr = 0;
-void lp_setup(char *str, int *ints)
+__initfunc(void lp_setup(char *str, int *ints))
{
/* Ugh. */
if (!strncmp(str, "parport", 7)) {
diff --git a/drivers/char/lp_intern.c b/drivers/char/lp_intern.c
index 9d676f927..7bb4ec634 100644
--- a/drivers/char/lp_intern.c
+++ b/drivers/char/lp_intern.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/sched.h>
+#include <linux/init.h>
#include <asm/irq.h>
#include <asm/setup.h>
#ifdef CONFIG_AMIGA
@@ -33,7 +34,6 @@
#endif
#include <linux/lp_intern.h>
-static int my_inter = 0;
static int minor = -1;
static void lp_int_out(int, int);
@@ -126,24 +126,18 @@ lp_int_online (int dev)
}
}
-static int lp_int_my_interrupt(int dev)
-{
- return my_inter;
-}
-
static void lp_int_interrupt(int irq, void *data, struct pt_regs *fp)
{
- my_inter = 1;
- lp_interrupt(irq, data, fp);
- my_inter = 0;
+ lp_interrupt(minor);
}
-static void lp_int_open(void)
+static int lp_int_open(int dev)
{
MOD_INC_USE_COUNT;
+ return 0;
}
-static void lp_int_release(void)
+static void lp_int_release(int dev)
{
MOD_DEC_USE_COUNT;
}
@@ -155,7 +149,7 @@ static struct lp_struct tab = {
lp_int_busy,
lp_int_pout,
lp_int_online,
- lp_int_my_interrupt,
+ 0,
NULL, /* ioctl */
lp_int_open,
lp_int_release,
@@ -167,7 +161,7 @@ static struct lp_struct tab = {
NULL,
};
-int lp_internal_init(void)
+__initfunc(int lp_internal_init(void))
{
#ifdef CONFIG_AMIGA
if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL))
diff --git a/drivers/char/lp_m68k.c b/drivers/char/lp_m68k.c
index 3cc9458bd..17405c191 100644
--- a/drivers/char/lp_m68k.c
+++ b/drivers/char/lp_m68k.c
@@ -41,6 +41,7 @@
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/string.h>
+#include <linux/init.h>
#include <asm/irq.h>
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
@@ -465,7 +466,7 @@ EXPORT_SYMBOL(lp_init);
EXPORT_SYMBOL(register_parallel);
EXPORT_SYMBOL(unregister_parallel);
-int lp_init(void)
+__initfunc(int lp_init(void))
{
extern char m68k_debug_device[];
@@ -498,7 +499,7 @@ int lp_init(void)
/*
* Currently we do not accept any lp-parameters, but that may change.
*/
-void lp_setup(char *str, int *ints)
+__initfunc(void lp_setup(char *str, int *ints))
{
}
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 3d973d2a8..56d537fb3 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -139,7 +139,8 @@ static long read_kmem(struct inode *inode, struct file *file,
else
tmp = count;
read = tmp;
-#if defined(__sparc__) /* we don't have page 0 mapped on sparc.. */
+#if defined(__sparc__) || defined(__mc68000__)
+ /* we don't have page 0 mapped on sparc and m68k.. */
while (p < PAGE_SIZE && tmp > 0) {
put_user(0,buf);
buf++;
@@ -172,7 +173,8 @@ static long write_kmem(struct inode * inode, struct file * file,
if (count > (unsigned long) high_memory - p)
count = (unsigned long) high_memory - p;
written = 0;
-#if defined(__sparc__) /* we don't have page 0 mapped on sparc.. */
+#if defined(__sparc__) || defined(__mc68000__)
+ /* we don't have page 0 mapped on sparc and m68k.. */
while (p < PAGE_SIZE && count > 0) {
/* Hmm. Do something? */
buf++;
@@ -236,38 +238,38 @@ static long write_null(struct inode * inode, struct file * file,
*/
static inline unsigned long read_zero_pagealigned(char * buf, unsigned long size)
{
- struct vm_area_struct * curr_vma;
+ struct vm_area_struct * vma;
unsigned long addr=(unsigned long)buf;
-/*
- * First we take the most obvious case: when we have one VM area to deal with,
- * and it's privately mapped.
- */
- curr_vma = find_vma(current->mm, addr);
-
- if ( !(curr_vma->vm_flags & VM_SHARED) &&
- (addr + size <= curr_vma->vm_end) ) {
+ /* For private mappings, just map in zero pages. */
+ for (vma = find_vma(current->mm, addr); vma; vma = vma->vm_next) {
+ unsigned long count;
- flush_cache_range(current->mm, addr, addr + size);
- zap_page_range(current->mm, addr, size);
- zeromap_page_range(addr, size, PAGE_COPY);
- flush_tlb_range(current->mm, addr, addr + size);
-
- return 0;
+ if (vma->vm_start > addr || (vma->vm_flags & VM_WRITE) == 0)
+ return size;
+ if (vma->vm_flags & VM_SHARED)
+ break;
+ count = vma->vm_end - addr;
+ if (count > size)
+ count = size;
+
+ flush_cache_range(current->mm, addr, addr + count);
+ zap_page_range(current->mm, addr, count);
+ zeromap_page_range(addr, count, PAGE_COPY);
+ flush_tlb_range(current->mm, addr, addr + count);
+
+ size -= count;
+ buf += count;
+ addr += count;
+ if (size == 0)
+ return 0;
}
-
-/*
- * Ooops, the shared case is hard. Lets do the conventional
- * zeroing.
- *
- * FIXME: same for the multiple-vma case, we dont handle it
- * now for simplicity, although it's much easier than
- * the shared case. Not that it should happen often ...
- */
-
+
+ /* The shared case is hard. Lets do the conventional zeroing. */
do {
- if (clear_user(buf, PAGE_SIZE))
- break;
+ unsigned long unwritten = clear_user(buf, PAGE_SIZE);
+ if (unwritten)
+ return size + unwritten - PAGE_SIZE;
if (need_resched)
schedule();
buf += PAGE_SIZE;
@@ -280,7 +282,10 @@ static inline unsigned long read_zero_pagealigned(char * buf, unsigned long size
static long read_zero(struct inode * node, struct file * file,
char * buf, unsigned long count)
{
- unsigned long left;
+ unsigned long left, unwritten, written = 0;
+
+ if (!count)
+ return 0;
if (!access_ok(VERIFY_WRITE, buf, count))
return -EFAULT;
@@ -289,21 +294,27 @@ static long read_zero(struct inode * node, struct file * file,
/* do we want to be clever? Arbitrary cut-off */
if (count >= PAGE_SIZE*4) {
- unsigned long partial, unwritten;
+ unsigned long partial;
/* How much left of the page? */
partial = (PAGE_SIZE-1) & -(unsigned long) buf;
- clear_user(buf, partial);
+ unwritten = clear_user(buf, partial);
+ written = partial - unwritten;
+ if (unwritten)
+ goto out;
left -= partial;
buf += partial;
unwritten = read_zero_pagealigned(buf, left & PAGE_MASK);
+ written += (left & PAGE_MASK) - unwritten;
+ if (unwritten)
+ goto out;
buf += left & PAGE_MASK;
left &= ~PAGE_MASK;
- if (unwritten)
- return count - left - unwritten;
}
- clear_user(buf, left);
- return count;
+ unwritten = clear_user(buf, left);
+ written += left - unwritten;
+out:
+ return written ? written : -EFAULT;
}
static int mmap_zero(struct inode * inode, struct file * file, struct vm_area_struct * vma)
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index fd72f33d8..d632e4788 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -73,6 +73,7 @@ extern void watchdog_init(void);
extern void wdt_init(void);
extern void pcwatchdog_init(void);
extern int rtc_init(void);
+extern int dsp56k_init(void);
#ifdef CONFIG_PROC_FS
static int misc_read_proc(char *buf, char **start, off_t offset,
@@ -235,6 +236,9 @@ __initfunc(int misc_init(void))
#ifdef CONFIG_RTC
rtc_init();
#endif
+#ifdef CONFIG_ATARI_DSP56K
+ dsp56k_init();
+#endif
#endif /* !MODULE */
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
printk("unable to get major %d for misc devices\n",
diff --git a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c
index b11730f70..8f98231b8 100644
--- a/drivers/char/msbusmouse.c
+++ b/drivers/char/msbusmouse.c
@@ -51,7 +51,7 @@
static struct mouse_status mouse;
static int mouse_irq = MOUSE_IRQ;
-void msmouse_setup(char *str, int *ints)
+__initfunc(void msmouse_setup(char *str, int *ints))
{
if (ints[0] > 0)
mouse_irq=ints[1];
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index cf50a9781..8db4e1443 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -78,7 +78,7 @@ void n_tty_flush_buffer(struct tty_struct * tty)
return;
if (tty->driver.unthrottle &&
- clear_bit(TTY_THROTTLED, &tty->flags))
+ test_and_clear_bit(TTY_THROTTLED, &tty->flags))
tty->driver.unthrottle(tty);
if (tty->link->packet) {
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
@@ -598,7 +598,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
if ((tty->read_cnt >= TTY_THRESHOLD_THROTTLE) &&
tty->driver.throttle &&
- !set_bit(TTY_THROTTLED, &tty->flags))
+ !test_and_set_bit(TTY_THROTTLED, &tty->flags))
tty->driver.throttle(tty);
}
@@ -874,7 +874,7 @@ do_it_again:
if (!tty->read_cnt) {
break;
}
- eol = clear_bit(tty->read_tail,
+ eol = test_and_clear_bit(tty->read_tail,
&tty->read_flags);
c = tty->read_buf[tty->read_tail];
tty->read_tail = ((tty->read_tail+1) &
@@ -904,7 +904,7 @@ do_it_again:
low-level driver know. */
if (tty->driver.unthrottle &&
(tty->read_cnt <= TTY_THRESHOLD_UNTHROTTLE)
- && clear_bit(TTY_THROTTLED, &tty->flags))
+ && test_and_clear_bit(TTY_THROTTLED, &tty->flags))
tty->driver.unthrottle(tty);
if (b - buf >= minimum || !nr)
@@ -923,7 +923,7 @@ do_it_again:
size = b - buf;
if (size && nr)
clear_bit(TTY_PUSH, &tty->flags);
- if (!size && clear_bit(TTY_PUSH, &tty->flags))
+ if (!size && test_and_clear_bit(TTY_PUSH, &tty->flags))
goto do_it_again;
if (!size && !retval)
clear_bit(TTY_PUSH, &tty->flags);
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
new file mode 100644
index 000000000..88dcb1986
--- /dev/null
+++ b/drivers/char/pc_keyb.c
@@ -0,0 +1,647 @@
+/*
+ * linux/drivers/char/pc_keyb.c
+ *
+ * Written for linux by Johan Myreen as a translation from
+ * the assembly version by Linus (with diacriticals added)
+ *
+ * Some additional features added by Christoph Niemann (ChN), March 1993
+ *
+ * Loadable keymaps by Risto Kankkunen, May 1993
+ *
+ * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
+ * Added decr/incr_console, dynamic keymaps, Unicode support,
+ * dynamic function/string keys, led setting, Sept 1994
+ * `Sticky' modifier keys, 951006.
+ * 11-11-96: SAK should now work in the raw mode (Martin Mares)
+ *
+ * Separation of the PC low-level part by Geert Uytterhoeven, May 1997
+ */
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/config.h>
+
+#include <asm/bitops.h>
+
+/*
+ * Define these here, include/asm-mips/keyboard.h depends on them.
+ *
+ * keyboard controller registers
+ */
+#define KBD_STATUS_REG (unsigned int) 0x64
+#define KBD_CNTL_REG (unsigned int) 0x64
+#define KBD_DATA_REG (unsigned int) 0x60
+/*
+ * controller commands
+ */
+#define KBD_READ_MODE (unsigned int) 0x20
+#define KBD_WRITE_MODE (unsigned int) 0x60
+#define KBD_SELF_TEST (unsigned int) 0xAA
+#define KBD_SELF_TEST2 (unsigned int) 0xAB
+#define KBD_CNTL_ENABLE (unsigned int) 0xAE
+/*
+ * keyboard commands
+ */
+#define KBD_ENABLE (unsigned int) 0xF4
+#define KBD_DISABLE (unsigned int) 0xF5
+#define KBD_RESET (unsigned int) 0xFF
+/*
+ * keyboard replies
+ */
+#define KBD_ACK (unsigned int) 0xFA
+#define KBD_POR (unsigned int) 0xAA
+/*
+ * status register bits
+ */
+#define KBD_OBF (unsigned int) 0x01
+#define KBD_IBF (unsigned int) 0x02
+#define KBD_GTO (unsigned int) 0x40
+#define KBD_PERR (unsigned int) 0x80
+/*
+ * keyboard controller mode register bits
+ */
+#define KBD_EKI (unsigned int) 0x01
+#define KBD_SYS (unsigned int) 0x04
+#define KBD_DMS (unsigned int) 0x20
+#define KBD_KCC (unsigned int) 0x40
+
+#include <asm/keyboard.h>
+
+/*
+ * On non-x86 hardware we do a full keyboard controller
+ * initialization, in case the bootup software hasn't done
+ * it. On a x86, the BIOS will already have initialized the
+ * keyboard.
+ */
+#ifdef INIT_KBD
+int initialize_kbd(void);
+#endif
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
+
+/* used only by send_data - set by keyboard_interrupt */
+static volatile unsigned char reply_expected = 0;
+static volatile unsigned char acknowledge = 0;
+static volatile unsigned char resend = 0;
+
+/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
+static inline void kb_wait(void)
+{
+ int i;
+
+ for (i=0; i<0x100000; i++)
+ if ((kbd_inb_p(0x64) & 0x02) == 0)
+ return;
+ printk(KERN_WARNING "Keyboard timed out\n");
+}
+
+extern struct pt_regs *pt_regs;
+
+extern void handle_scancode(unsigned char scancode);
+
+
+/*
+ * Translation of escaped scancodes to keycodes.
+ * This is now user-settable.
+ * The keycodes 1-88,96-111,119 are fairly standard, and
+ * should probably not be changed - changing might confuse X.
+ * X also interprets scancode 0x5d (KEY_Begin).
+ *
+ * For 1-88 keycode equals scancode.
+ */
+
+#define E0_KPENTER 96
+#define E0_RCTRL 97
+#define E0_KPSLASH 98
+#define E0_PRSCR 99
+#define E0_RALT 100
+#define E0_BREAK 101 /* (control-pause) */
+#define E0_HOME 102
+#define E0_UP 103
+#define E0_PGUP 104
+#define E0_LEFT 105
+#define E0_RIGHT 106
+#define E0_END 107
+#define E0_DOWN 108
+#define E0_PGDN 109
+#define E0_INS 110
+#define E0_DEL 111
+
+#define E1_PAUSE 119
+
+/*
+ * The keycodes below are randomly located in 89-95,112-118,120-127.
+ * They could be thrown away (and all occurrences below replaced by 0),
+ * but that would force many users to use the `setkeycodes' utility, where
+ * they needed not before. It does not matter that there are duplicates, as
+ * long as no duplication occurs for any single keyboard.
+ */
+#define SC_LIM 89
+
+#define FOCUS_PF1 85 /* actual code! */
+#define FOCUS_PF2 89
+#define FOCUS_PF3 90
+#define FOCUS_PF4 91
+#define FOCUS_PF5 92
+#define FOCUS_PF6 93
+#define FOCUS_PF7 94
+#define FOCUS_PF8 95
+#define FOCUS_PF9 120
+#define FOCUS_PF10 121
+#define FOCUS_PF11 122
+#define FOCUS_PF12 123
+
+#define JAP_86 124
+/* tfj@olivia.ping.dk:
+ * The four keys are located over the numeric keypad, and are
+ * labelled A1-A4. It's an rc930 keyboard, from
+ * Regnecentralen/RC International, Now ICL.
+ * Scancodes: 59, 5a, 5b, 5c.
+ */
+#define RGN1 124
+#define RGN2 125
+#define RGN3 126
+#define RGN4 127
+
+static unsigned char high_keys[128 - SC_LIM] = {
+ RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
+ 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */
+ 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */
+ FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */
+ FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */
+};
+
+/* BTC */
+#define E0_MACRO 112
+/* LK450 */
+#define E0_F13 113
+#define E0_F14 114
+#define E0_HELP 115
+#define E0_DO 116
+#define E0_F17 117
+#define E0_KPMINPLUS 118
+/*
+ * My OmniKey generates e0 4c for the "OMNI" key and the
+ * right alt key does nada. [kkoller@nyx10.cs.du.edu]
+ */
+#define E0_OK 124
+/*
+ * New microsoft keyboard is rumoured to have
+ * e0 5b (left window button), e0 5c (right window button),
+ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
+ * [or: Windows_L, Windows_R, TaskMan]
+ */
+#define E0_MSLW 125
+#define E0_MSRW 126
+#define E0_MSTM 127
+
+static unsigned char e0_keys[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */
+ 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */
+ 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */
+ E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */
+ E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */
+ E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
+ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */
+ 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
+ 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */
+ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
+};
+
+static unsigned int prev_scancode = 0; /* remember E0, E1 */
+
+int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+ if (scancode < SC_LIM || scancode > 255 || keycode > 127)
+ return -EINVAL;
+ if (scancode < 128)
+ high_keys[scancode - SC_LIM] = keycode;
+ else
+ e0_keys[scancode - 128] = keycode;
+ return 0;
+}
+
+int pckbd_getkeycode(unsigned int scancode)
+{
+ return
+ (scancode < SC_LIM || scancode > 255) ? -EINVAL :
+ (scancode < 128) ? high_keys[scancode - SC_LIM] :
+ e0_keys[scancode - 128];
+}
+
+#if DISABLE_KBD_DURING_INTERRUPTS
+static inline void send_cmd(unsigned char c)
+{
+ kb_wait();
+ kbd_outb(c,0x64);
+}
+
+#define disable_keyboard() do { send_cmd(0xAD); kb_wait(); } while (0)
+#define enable_keyboard() send_cmd(0xAE)
+#else
+#define disable_keyboard() /* nothing */
+#define enable_keyboard() /* nothing */
+#endif
+
+static int do_acknowledge(unsigned char scancode)
+{
+ if (reply_expected) {
+ /* 0xfa, 0xfe only mean "acknowledge", "resend" for most keyboards */
+ /* but they are the key-up scancodes for PF6, PF10 on a FOCUS 9000 */
+ reply_expected = 0;
+ if (scancode == 0xfa) {
+ acknowledge = 1;
+ return 0;
+ } else if (scancode == 0xfe) {
+ resend = 1;
+ return 0;
+ }
+ /* strange ... */
+ reply_expected = 1;
+#if 0
+ printk(KERN_DEBUG "keyboard reply expected - got %02x\n",
+ scancode);
+#endif
+ }
+ if (scancode == 0) {
+#ifdef KBD_REPORT_ERR
+ printk(KERN_INFO "keyboard buffer overflow\n");
+#endif
+ prev_scancode = 0;
+ return 0;
+ }
+ return 1;
+}
+
+int pckbd_pretranslate(unsigned char scancode, char raw_mode)
+{
+ if (scancode == 0xff) {
+ /* in scancode mode 1, my ESC key generates 0xff */
+ /* the calculator keys on a FOCUS 9000 generate 0xff */
+#ifndef KBD_IS_FOCUS_9000
+#ifdef KBD_REPORT_ERR
+ if (!raw_mode)
+ printk(KERN_DEBUG "keyboard error\n");
+#endif
+#endif
+ prev_scancode = 0;
+ return 0;
+ }
+
+ if (scancode == 0xe0 || scancode == 0xe1) {
+ prev_scancode = scancode;
+ return 0;
+ }
+ return 1;
+}
+
+int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode)
+{
+ if (prev_scancode) {
+ /*
+ * usually it will be 0xe0, but a Pause key generates
+ * e1 1d 45 e1 9d c5 when pressed, and nothing when released
+ */
+ if (prev_scancode != 0xe0) {
+ if (prev_scancode == 0xe1 && scancode == 0x1d) {
+ prev_scancode = 0x100;
+ return 0;
+ } else if (prev_scancode == 0x100 && scancode == 0x45) {
+ *keycode = E1_PAUSE;
+ prev_scancode = 0;
+ } else {
+#ifdef KBD_REPORT_UNKN
+ if (!raw_mode)
+ printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
+#endif
+ prev_scancode = 0;
+ return 0;
+ }
+ } else {
+ prev_scancode = 0;
+ /*
+ * The keyboard maintains its own internal caps lock and
+ * num lock statuses. In caps lock mode E0 AA precedes make
+ * code and E0 2A follows break code. In num lock mode,
+ * E0 2A precedes make code and E0 AA follows break code.
+ * We do our own book-keeping, so we will just ignore these.
+ */
+ /*
+ * For my keyboard there is no caps lock mode, but there are
+ * both Shift-L and Shift-R modes. The former mode generates
+ * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
+ * So, we should also ignore the latter. - aeb@cwi.nl
+ */
+ if (scancode == 0x2a || scancode == 0x36)
+ return 0;
+
+ if (e0_keys[scancode])
+ *keycode = e0_keys[scancode];
+ else {
+#ifdef KBD_REPORT_UNKN
+ if (!raw_mode)
+ printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
+ scancode);
+#endif
+ return 0;
+ }
+ }
+ } else if (scancode >= SC_LIM) {
+ /* This happens with the FOCUS 9000 keyboard
+ Its keys PF1..PF12 are reported to generate
+ 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
+ Moreover, unless repeated, they do not generate
+ key-down events, so we have to zero up_flag below */
+ /* Also, Japanese 86/106 keyboards are reported to
+ generate 0x73 and 0x7d for \ - and \ | respectively. */
+ /* Also, some Brazilian keyboard is reported to produce
+ 0x73 and 0x7e for \ ? and KP-dot, respectively. */
+
+ *keycode = high_keys[scancode - SC_LIM];
+
+ if (!*keycode) {
+ if (!raw_mode) {
+#ifdef KBD_REPORT_UNKN
+ printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
+ " - ignored\n", scancode);
+#endif
+ }
+ return 0;
+ }
+ } else
+ *keycode = scancode;
+ return 1;
+}
+
+char pckbd_unexpected_up(unsigned char keycode)
+{
+ /* unexpected, but this can happen: maybe this was a key release for a
+ FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */
+ if (keycode >= SC_LIM || keycode == 85)
+ return 0;
+ else
+ return 0200;
+}
+
+static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned char status;
+
+ pt_regs = regs;
+ disable_keyboard();
+
+ status = kbd_inb_p(0x64);
+ do {
+ unsigned char scancode;
+
+ /* mouse data? */
+ if (status & kbd_read_mask & 0x20)
+ break;
+
+ scancode = kbd_inb(0x60);
+ if ((status & 0x01) && do_acknowledge(scancode))
+ handle_scancode(scancode);
+
+ status = kbd_inb(0x64);
+ } while (status & 0x01);
+
+ mark_bh(KEYBOARD_BH);
+ enable_keyboard();
+}
+
+/*
+ * send_data sends a character to the keyboard and waits
+ * for an acknowledge, possibly retrying if asked to. Returns
+ * the success status.
+ */
+static int send_data(unsigned char data)
+{
+ int retries = 3;
+ int i;
+
+ do {
+ kb_wait();
+ acknowledge = 0;
+ resend = 0;
+ reply_expected = 1;
+ kbd_outb_p(data, 0x60);
+ for(i=0; i<0x200000; i++) {
+ kbd_inb_p(0x64); /* just as a delay */
+ if (acknowledge)
+ return 1;
+ if (resend)
+ break;
+ }
+ if (!resend)
+ return 0;
+ } while (retries-- > 0);
+ return 0;
+}
+
+void pckbd_leds(unsigned char leds)
+{
+ if (!send_data(0xed) || !send_data(leds))
+ send_data(0xf4); /* re-enable kbd if any errors */
+}
+
+__initfunc(void pckbd_init_hw(void))
+{
+ request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
+ keyboard_setup();
+#ifdef INIT_KBD
+ initialize_kbd();
+#endif
+}
+
+#ifdef INIT_KBD
+
+/*
+ * controller commands
+ */
+#define KBD_READ_MODE (unsigned int) 0x20
+#define KBD_WRITE_MODE (unsigned int) 0x60
+#define KBD_SELF_TEST (unsigned int) 0xAA
+#define KBD_SELF_TEST2 (unsigned int) 0xAB
+#define KBD_CNTL_ENABLE (unsigned int) 0xAE
+/*
+ * keyboard commands
+ */
+#define KBD_ENABLE (unsigned int) 0xF4
+#define KBD_DISABLE (unsigned int) 0xF5
+#define KBD_RESET (unsigned int) 0xFF
+/*
+ * keyboard replies
+ */
+#define KBD_ACK (unsigned int) 0xFA
+#define KBD_POR (unsigned int) 0xAA
+/*
+ * status register bits
+ */
+#define KBD_OBF (unsigned int) 0x01
+#define KBD_IBF (unsigned int) 0x02
+#define KBD_GTO (unsigned int) 0x40
+#define KBD_PERR (unsigned int) 0x80
+/*
+ * keyboard controller mode register bits
+ */
+#define KBD_EKI (unsigned int) 0x01
+#define KBD_SYS (unsigned int) 0x04
+#define KBD_DMS (unsigned int) 0x20
+#define KBD_KCC (unsigned int) 0x40
+
+#define TIMEOUT_CONST 500000
+
+static int kbd_wait_for_input(void)
+{
+ int n;
+ int status, data;
+
+ n = TIMEOUT_CONST;
+ do {
+ status = kbd_inb(KBD_STATUS_REG);
+ /*
+ * Wait for input data to become available. This bit will
+ * then be cleared by the following read of the DATA
+ * register.
+ */
+
+ if (!(status & KBD_OBF))
+ continue;
+
+ data = kbd_inb(KBD_DATA_REG);
+
+ /*
+ * Check to see if a timeout error has occurred. This means
+ * that transmission was started but did not complete in the
+ * normal time cycle. PERR is set when a parity error occurred
+ * in the last transmission.
+ */
+ if (status & (KBD_GTO | KBD_PERR)) {
+ continue;
+ }
+ return (data & 0xff);
+ } while (--n);
+ return (-1); /* timed-out if fell through to here... */
+}
+
+static void kbd_write(int address, int data)
+{
+ int status;
+
+ do {
+ status = kbd_inb(KBD_STATUS_REG); /* spin until input buffer empty*/
+ } while (status & KBD_IBF);
+ kbd_outb(data, address); /* write out the data*/
+}
+
+__initfunc(int initialize_kbd(void))
+{
+ unsigned long flags;
+
+ save_flags(flags); cli();
+
+ /* Flush any pending input. */
+ while (kbd_wait_for_input() != -1)
+ continue;
+
+ /*
+ * Test the keyboard interface.
+ * This seems to be the only way to get it going.
+ * If the test is successful a x55 is placed in the input buffer.
+ */
+ kbd_write(KBD_CNTL_REG, KBD_SELF_TEST);
+ if (kbd_wait_for_input() != 0x55) {
+ printk(KERN_WARNING "initialize_kbd: "
+ "keyboard failed self test.\n");
+ restore_flags(flags);
+ return(-1);
+ }
+
+ /*
+ * Perform a keyboard interface test. This causes the controller
+ * to test the keyboard clock and data lines. The results of the
+ * test are placed in the input buffer.
+ */
+ kbd_write(KBD_CNTL_REG, KBD_SELF_TEST2);
+ if (kbd_wait_for_input() != 0x00) {
+ printk(KERN_WARNING "initialize_kbd: "
+ "keyboard failed self test 2.\n");
+ restore_flags(flags);
+ return(-1);
+ }
+
+ /* Enable the keyboard by allowing the keyboard clock to run. */
+ kbd_write(KBD_CNTL_REG, KBD_CNTL_ENABLE);
+
+ /*
+ * Reset keyboard. If the read times out
+ * then the assumption is that no keyboard is
+ * plugged into the machine.
+ * This defaults the keyboard to scan-code set 2.
+ */
+ kbd_write(KBD_DATA_REG, KBD_RESET);
+ if (kbd_wait_for_input() != KBD_ACK) {
+ printk(KERN_WARNING "initialize_kbd: "
+ "reset kbd failed, no ACK.\n");
+ restore_flags(flags);
+ return(-1);
+ }
+
+ if (kbd_wait_for_input() != KBD_POR) {
+ printk(KERN_WARNING "initialize_kbd: "
+ "reset kbd failed, not POR.\n");
+ restore_flags(flags);
+ return(-1);
+ }
+
+ /*
+ * now do a DEFAULTS_DISABLE always
+ */
+ kbd_write(KBD_DATA_REG, KBD_DISABLE);
+ if (kbd_wait_for_input() != KBD_ACK) {
+ printk(KERN_WARNING "initialize_kbd: "
+ "disable kbd failed, no ACK.\n");
+ restore_flags(flags);
+ return(-1);
+ }
+
+ /*
+ * Enable keyboard interrupt, operate in "sys" mode,
+ * enable keyboard (by clearing the disable keyboard bit),
+ * disable mouse, do conversion of keycodes.
+ */
+ kbd_write(KBD_CNTL_REG, KBD_WRITE_MODE);
+ kbd_write(KBD_DATA_REG, KBD_EKI|KBD_SYS|KBD_DMS|KBD_KCC);
+
+ /*
+ * now ENABLE the keyboard to set it scanning...
+ */
+ kbd_write(KBD_DATA_REG, KBD_ENABLE);
+ if (kbd_wait_for_input() != KBD_ACK) {
+ printk(KERN_WARNING "initialize_kbd: "
+ "keyboard enable failed.\n");
+ restore_flags(flags);
+ return(-1);
+ }
+
+ restore_flags(flags);
+
+ return (1);
+}
+#endif /* INIT_KBD */
diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c
index c09c7dbbe..9a68bb472 100644
--- a/drivers/char/pcxx.c
+++ b/drivers/char/pcxx.c
@@ -895,7 +895,7 @@ static void pcxe_flush_chars(struct tty_struct *tty)
* Driver setup function when linked into the kernel to optionally parse multible
* "digi="-lines and initialize the driver at boot time. No probing.
*/
-void pcxx_setup(char *str, int *ints)
+__initfunc(void pcxx_setup(char *str, int *ints))
{
struct board_info board;
@@ -2358,7 +2358,7 @@ static void do_softint(void *private_)
if(info && info->magic == PCXX_MAGIC) {
struct tty_struct *tty = info->tty;
if (tty && tty->driver_data) {
- if(clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
+ if(test_and_clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
tty_hangup(tty);
wake_up_interruptible(&info->open_wait);
info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 3fb64b28d..5f7619391 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1,7 +1,7 @@
/*
* random.c -- A strong random number generator
*
- * Version 1.01, last modified 13-Feb-97
+ * Version 1.02, last modified 15-Apr-97
*
* Copyright Theodore Ts'o, 1994, 1995, 1996, 1997. All rights reserved.
*
@@ -839,6 +839,18 @@ static void SHATransform(__u32 *digest, __u32 *data)
digest[ 4 ] += E;
}
+#undef ROTL
+#undef f1
+#undef f2
+#undef f3
+#undef f4
+#undef K1
+#undef K2
+#undef K3
+#undef K4
+#undef expand
+#undef subRound
+
#else
#define HASH_BUFFER_SIZE 4
#define HASH_TRANSFORM MD5Transform
@@ -1324,22 +1336,90 @@ struct file_operations urandom_fops = {
* attacks which rely on guessing the initial TCP sequence number.
* This algorithm was suggested by Steve Bellovin.
*/
+
+/* F, G and H are basic MD4 functions: selection, majority, parity */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+#define ROTL(n,X) ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) )
+
+/* FF, GG and HH are MD4 transformations for rounds 1, 2 and 3 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s) \
+ {(a) += F ((b), (c), (d)) + (x); \
+ (a) = ROTL ((s), (a));}
+#define GG(a, b, c, d, x, s) \
+ {(a) += G ((b), (c), (d)) + (x) + 013240474631UL; \
+ (a) = ROTL ((s), (a));}
+#define HH(a, b, c, d, x, s) \
+ {(a) += H ((b), (c), (d)) + (x) + 015666365641UL; \
+ (a) = ROTL ((s), (a));}
+
+/*
+ * Basic cut-down MD4 transform
+ */
+static void halfMD4Transform (__u32 buf[4], __u32 in[8])
+{
+ __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+ FF (a, b, c, d, in[ 0], 3);
+ FF (d, a, b, c, in[ 1], 7);
+ FF (c, d, a, b, in[ 2], 11);
+ FF (b, c, d, a, in[ 3], 19);
+ FF (a, b, c, d, in[ 4], 3);
+ FF (d, a, b, c, in[ 5], 7);
+ FF (c, d, a, b, in[ 6], 11);
+ FF (b, c, d, a, in[ 7], 19);
+
+ /* Round 2 */
+ GG (a, b, c, d, in[ 0], 3);
+ GG (d, a, b, c, in[ 4], 5);
+ GG (a, b, c, d, in[ 1], 9);
+ GG (d, a, b, c, in[ 5], 13);
+ GG (a, b, c, d, in[ 2], 3);
+ GG (d, a, b, c, in[ 6], 5);
+ GG (a, b, c, d, in[ 3], 9);
+ GG (d, a, b, c, in[ 7], 13);
+
+ /* Round 3 */
+ HH (a, b, c, d, in[ 0], 3);
+ HH (c, d, a, b, in[ 4], 9);
+ HH (a, b, c, d, in[ 2], 11);
+ HH (c, d, a, b, in[ 6], 15);
+ HH (a, b, c, d, in[ 1], 3);
+ HH (c, d, a, b, in[ 5], 9);
+ HH (a, b, c, d, in[ 3], 11);
+ HH (c, d, a, b, in[ 7], 15);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#define REKEY_INTERVAL 300
+
__u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
__u16 sport, __u16 dport)
{
- static int is_init = 0;
- static __u32 secret[16];
+ static __u32 rekey_time = 0;
+ static __u32 secret[12];
+ static char count = 0;
struct timeval tv;
- __u32 tmp[16];
+ __u32 tmp[12];
__u32 seq;
/*
- * Pick a random secret the first time we open a TCP
- * connection.
+ * Pick a random secret every REKEY_INTERVAL seconds
*/
- if (is_init == 0) {
+ do_gettimeofday(&tv);
+ if (!rekey_time ||
+ (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
get_random_bytes(&secret, sizeof(secret));
- is_init = 1;
+ rekey_time = tv.tv_sec;
+ count++;
}
memcpy(tmp, secret, sizeof(tmp));
@@ -1350,7 +1430,7 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
tmp[8]=saddr;
tmp[9]=daddr;
tmp[10]=(sport << 16) + dport;
- HASH_TRANSFORM(tmp, tmp);
+ halfMD4Transform(tmp, tmp+4);
/*
* As close as possible to RFC 793, which
@@ -1359,8 +1439,8 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
* For 10MB/s ethernet, a 1MHz clock is appropriate.
* That's funny, Linux has one built in! Use it!
*/
- do_gettimeofday(&tv);
- seq = tmp[1] + tv.tv_usec+tv.tv_sec*1000000;
+ seq = (tmp[1]&0xFFFFFF) + (tv.tv_usec+tv.tv_sec*1000000) +
+ (count << 24);
#if 0
printk("init_seq(%lx, %lx, %d, %d) = %d\n",
saddr, daddr, sport, dport, seq);
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 301babf81..dfe150e07 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -1711,7 +1711,7 @@ static void do_softint(void *private_)
if(!(tty = port->tty))
return;
- if (clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
@@ -1821,7 +1821,7 @@ static void rc_release_drivers(void)
* addresses in this case.
*
*/
-void riscom8_setup(char *str, int * ints)
+__initfunc(void riscom8_setup(char *str, int * ints))
{
int i;
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index e1a69a85e..e2a93a0c3 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -992,7 +992,7 @@ static void do_softint(void *private_)
if (!tty)
return;
- if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
diff --git a/drivers/char/tga.c b/drivers/char/tga.c
index 723cbc631..a85f4cba4 100644
--- a/drivers/char/tga.c
+++ b/drivers/char/tga.c
@@ -26,6 +26,7 @@
#include <linux/ioport.h>
#include <linux/bios32.h>
#include <linux/pci.h>
+#include <linux/init.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -140,35 +141,35 @@ unsigned long tga_fb_base;
unsigned long tga_regs_base;
unsigned int tga_bpp, tga_fb_width, tga_fb_height, tga_fb_stride;
-static unsigned int fb_offset_presets[4] = {
+static unsigned int fb_offset_presets[4] __initdata = {
TGA_8PLANE_FB_OFFSET,
TGA_24PLANE_FB_OFFSET,
0xffffffff,
TGA_24PLUSZ_FB_OFFSET
};
-static unsigned int deep_presets[4] = {
+static unsigned int deep_presets[4] __initdata = {
0x00014000,
0x0001440d,
0xffffffff,
0x0001441d
};
-static unsigned int rasterop_presets[4] = {
+static unsigned int rasterop_presets[4] __initdata = {
0x00000003,
0x00000303,
0xffffffff,
0x00000303
};
-static unsigned int mode_presets[4] = {
+static unsigned int mode_presets[4] __initdata = {
0x00002000,
0x00002300,
0xffffffff,
0x00002300
};
-static unsigned int base_addr_presets[4] = {
+static unsigned int base_addr_presets[4] __initdata = {
0x00000000,
0x00000001,
0xffffffff,
@@ -304,8 +305,8 @@ set_cursor(int currcons)
restore_flags(flags);
}
-unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc)
+__initfunc(unsigned long
+con_type_init(unsigned long kmem_start, const char **display_desc))
{
can_do_color = 1;
@@ -323,8 +324,8 @@ con_type_init(unsigned long kmem_start, const char **display_desc)
return kmem_start;
}
-void
-con_type_init_finish(void)
+__initfunc(void
+con_type_init_finish(void))
{
}
@@ -447,8 +448,8 @@ void set_vesa_blanking(const unsigned long arg)
* when TGA console is configured, at the end of the probing code,
* we call here to look for a TGA device, and proceed...
*/
-void
-tga_console_init(void)
+__initfunc(void
+tga_console_init(void))
{
unsigned char pci_bus, pci_devfn;
int status;
@@ -490,9 +491,9 @@ tga_console_init(void)
#endif
}
-unsigned char PLLbits[7] = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
+unsigned char PLLbits[7] __initdata = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
-const unsigned long bt485_cursor_source[64] = {
+const unsigned long bt485_cursor_source[64] __initdata = {
0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
@@ -502,7 +503,7 @@ const unsigned long bt485_cursor_source[64] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
-const unsigned int bt463_cursor_source[256] = {
+const unsigned int bt463_cursor_source[256] __initdata = {
0xffff0000, 0x00000000, 0x00000000, 0x00000000,
0xffff0000, 0x00000000, 0x00000000, 0x00000000,
0xffff0000, 0x00000000, 0x00000000, 0x00000000,
@@ -533,8 +534,8 @@ const unsigned int bt463_cursor_source[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
-void
-tga_init_video()
+__initfunc(void
+tga_init_video(void))
{
int i, j, temp;
unsigned char *cbp;
@@ -750,8 +751,8 @@ tga_init_video()
tga_fb_stride = tga_fb_width / sizeof(int);
}
-void
-tga_clear_screen()
+__initfunc(void
+tga_clear_screen(void))
{
register int i, j;
register unsigned int *dst;
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
index 4f2dbf768..9d4ee2449 100644
--- a/drivers/char/tpqic02.c
+++ b/drivers/char/tpqic02.c
@@ -89,6 +89,7 @@
#include <linux/tpqic02.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/dma.h>
#include <asm/system.h>
@@ -2866,10 +2867,7 @@ static int qic02_get_resources(void)
return 0;
} /* qic02_get_resources */
-#ifdef MODULE
-static
-#endif
-int qic02_tape_init(void)
+__initfunc(static int qic02_tape_init(void))
{
if (TPSTATSIZE != 6)
{
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 0d0f0a4ed..12109e524 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -166,14 +166,11 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
{
#ifdef CHECK_TTY_COUNT
struct file *f;
- int i, count = 0;
+ int count = 0;
- for (f = first_file, i=0; i<nr_files; i++, f = f->f_next) {
- if (!f->f_count)
- continue;
- if (f->private_data == tty) {
+ for(f = inuse_filps; f; f = f->f_next) {
+ if(f->private_data == tty)
count++;
- }
}
if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
tty->driver.subtype == PTY_TYPE_SLAVE &&
@@ -363,16 +360,14 @@ static struct file_operations hung_up_tty_fops = {
void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
{
- int i;
+
struct file * filp;
struct task_struct *p;
if (!tty)
return;
check_tty_count(tty, "do_tty_hangup");
- for (filp = first_file, i=0; i<nr_files; i++, filp = filp->f_next) {
- if (!filp->f_count)
- continue;
+ for (filp = inuse_filps; filp; filp = filp->f_next) {
if (filp->private_data != tty)
continue;
if (!filp->f_inode)
@@ -405,13 +400,14 @@ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
tty->ldisc = ldiscs[N_TTY];
tty->termios->c_line = N_TTY;
if (tty->ldisc.open) {
- i = (tty->ldisc.open)(tty);
+ int i = (tty->ldisc.open)(tty);
if (i < 0)
printk("do_tty_hangup: N_TTY open: error %d\n",
-i);
}
}
+ read_lock(&tasklist_lock);
for_each_task(p) {
if ((tty->session > 0) && (p->session == tty->session) &&
p->leader) {
@@ -423,6 +419,8 @@ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
if (p->tty == tty)
p->tty = NULL;
}
+ read_unlock(&tasklist_lock);
+
tty->flags = 0;
tty->session = 0;
tty->pgrp = -1;
@@ -494,9 +492,11 @@ void disassociate_ctty(int on_exit)
tty->session = 0;
tty->pgrp = -1;
+ read_lock(&tasklist_lock);
for_each_task(p)
if (p->session == current->session)
p->tty = NULL;
+ read_unlock(&tasklist_lock);
}
void wait_for_keypress(void)
@@ -838,7 +838,7 @@ static void release_dev(struct file * filp)
{
struct tty_struct *tty, *o_tty;
struct termios *tp, *o_tp, *ltp, *o_ltp;
- struct task_struct **p;
+ struct task_struct *p;
int idx;
tty = (struct tty_struct *)filp->private_data;
@@ -972,14 +972,14 @@ static void release_dev(struct file * filp)
* Make sure there aren't any processes that still think this
* tty is their controlling tty.
*/
- for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
- if (*p == 0)
- continue;
- if ((*p)->tty == tty)
- (*p)->tty = NULL;
- if (o_tty && (*p)->tty == o_tty)
- (*p)->tty = NULL;
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if (p->tty == tty)
+ p->tty = NULL;
+ if (o_tty && p->tty == o_tty)
+ p->tty = NULL;
}
+ read_unlock(&tasklist_lock);
/*
* Shutdown the current line discipline, and reset it to
@@ -1216,40 +1216,6 @@ static int tty_fasync(struct inode * inode, struct file * filp, int on)
return 0;
}
-#if 0
-/*
- * XXX does anyone use this anymore?!?
- */
-static int do_get_ps_info(unsigned long arg)
-{
- struct tstruct {
- int flag;
- int present[NR_TASKS];
- struct task_struct tasks[NR_TASKS];
- };
- struct tstruct *ts = (struct tstruct *)arg;
- struct task_struct **p;
- char *c, *d;
- int i, n = 0;
-
- i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct));
- if (i)
- return i;
- for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
- if (*p)
- {
- c = (char *)(*p);
- d = (char *)(ts->tasks+n);
- for (i=0 ; i<sizeof(struct task_struct) ; i++)
- put_user(*c++, d++);
- put_user(1, ts->present+n);
- }
- else
- put_user(0, ts->present+n);
- return(0);
-}
-#endif
-
static int tiocsti(struct tty_struct *tty, char * arg)
{
char ch, mbz = 0;
@@ -1338,9 +1304,11 @@ static int tiocsctty(struct tty_struct *tty, int arg)
*/
struct task_struct *p;
+ read_lock(&tasklist_lock);
for_each_task(p)
if (p->tty == tty)
p->tty = NULL;
+ read_unlock(&tasklist_lock);
} else
return -EPERM;
}
@@ -1493,7 +1461,7 @@ void do_SAK( struct tty_struct *tty)
#ifdef TTY_SOFT_SAK
tty_hangup(tty);
#else
- struct task_struct **p;
+ struct task_struct *p;
int session;
int i;
struct file *filp;
@@ -1505,23 +1473,23 @@ void do_SAK( struct tty_struct *tty)
tty->ldisc.flush_buffer(tty);
if (tty->driver.flush_buffer)
tty->driver.flush_buffer(tty);
- for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
- if (!(*p))
- continue;
- if (((*p)->tty == tty) ||
- ((session > 0) && ((*p)->session == session)))
- send_sig(SIGKILL, *p, 1);
- else if ((*p)->files) {
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if ((p->tty == tty) ||
+ ((session > 0) && (p->session == session)))
+ send_sig(SIGKILL, p, 1);
+ else if (p->files) {
for (i=0; i < NR_OPEN; i++) {
- filp = (*p)->files->fd[i];
+ filp = p->files->fd[i];
if (filp && (filp->f_op == &tty_fops) &&
(filp->private_data == tty)) {
- send_sig(SIGKILL, *p, 1);
+ send_sig(SIGKILL, p, 1);
break;
}
}
}
}
+ read_unlock(&tasklist_lock);
#endif
}
@@ -1761,6 +1729,9 @@ __initfunc(int tty_init(void))
#ifdef CONFIG_DIGI
pcxe_init();
#endif
+#ifdef CONFIG_DIGIEPCA
+ pc_init();
+#endif
#ifdef CONFIG_RISCOM8
riscom8_init();
#endif
diff --git a/drivers/char/vga.c b/drivers/char/vga.c
index 7ae406d8e..e82bbc083 100644
--- a/drivers/char/vga.c
+++ b/drivers/char/vga.c
@@ -53,6 +53,7 @@
#include <linux/major.h>
#include <linux/mm.h>
#include <linux/ioport.h>
+#include <linux/init.h>
#ifdef __mips__
#include <asm/bootinfo.h>
@@ -159,8 +160,8 @@ set_cursor(int currcons)
hide_cursor();
}
-unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc)
+__initfunc(unsigned long
+con_type_init(unsigned long kmem_start, const char **display_desc))
{
#ifdef CONFIG_ACER_PICA_61
/*
@@ -328,8 +329,8 @@ con_type_init(unsigned long kmem_start, const char **display_desc)
return kmem_start;
}
-void
-con_type_init_finish(void)
+__initfunc(void
+con_type_init_finish(void))
{
}
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 0f4957971..b3e25c010 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -123,6 +123,7 @@ kd_size_changed(int row, int col)
}
}
+ read_lock(&tasklist_lock);
for_each_task(p)
{
if ( p->tty && MAJOR(p->tty->device) == TTY_MAJOR &&
@@ -131,6 +132,7 @@ kd_size_changed(int row, int col)
send_sig(SIGWINCH, p, 1);
}
}
+ read_unlock(&tasklist_lock);
return 0;
}
diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c
index e32131b63..31837eee2 100644
--- a/drivers/char/wdt.c
+++ b/drivers/char/wdt.c
@@ -61,7 +61,7 @@ static int irq=14;
* Setup options
*/
-void wdt_setup(char *str, int *ints)
+__initfunc(void wdt_setup(char *str, int *ints))
{
if(ints[0]>0)
{
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in
index af07e9bca..f731a096d 100644
--- a/drivers/isdn/Config.in
+++ b/drivers/isdn/Config.in
@@ -11,7 +11,6 @@ fi
bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO
dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
-dep_tristate 'Teles/NICCY1016PC/Creatix support' CONFIG_ISDN_DRV_TELES $CONFIG_ISDN
dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
bool 'HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile
index 8ef5d8e39..e88e81735 100644
--- a/drivers/isdn/Makefile
+++ b/drivers/isdn/Makefile
@@ -1,6 +1,6 @@
SUB_DIRS :=
MOD_SUB_DIRS :=
-ALL_SUB_DIRS := icn teles pcbit hisax
+ALL_SUB_DIRS := icn pcbit hisax
L_OBJS :=
LX_OBJS :=
@@ -36,16 +36,6 @@ else
endif
endif
-ifeq ($(CONFIG_ISDN_DRV_TELES),y)
- L_OBJS += teles/teles.o
- SUB_DIRS += teles
- MOD_SUB_DIRS += teles
-else
- ifeq ($(CONFIG_ISDN_DRV_TELES),m)
- MOD_SUB_DIRS += teles
- endif
-endif
-
ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
L_OBJS += hisax/hisax.o
SUB_DIRS += hisax
diff --git a/drivers/isdn/hisax/.cvsignore b/drivers/isdn/hisax/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/drivers/isdn/hisax/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
index cbc91e9d6..ebf0957b5 100644
--- a/drivers/isdn/hisax/isdnl1.c
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -461,11 +461,11 @@ isac_bh(struct IsdnCardState *sp)
if (!sp)
return;
- if (clear_bit(ISAC_PHCHANGE, &sp->event))
+ if (test_and_clear_bit(ISAC_PHCHANGE, &sp->event))
process_new_ph(sp);
- if (clear_bit(ISAC_RCVBUFREADY, &sp->event))
+ if (test_and_clear_bit(ISAC_RCVBUFREADY, &sp->event))
process_rcv(sp);
- if (clear_bit(ISAC_XMTBUFREADY, &sp->event))
+ if (test_and_clear_bit(ISAC_XMTBUFREADY, &sp->event))
process_xmt(sp);
}
@@ -578,9 +578,9 @@ hscx_bh(struct HscxState *hsp)
if (!hsp)
return;
- if (clear_bit(HSCX_RCVBUFREADY, &hsp->event))
+ if (test_and_clear_bit(HSCX_RCVBUFREADY, &hsp->event))
hscx_process_rcv(hsp);
- if (clear_bit(HSCX_XMTBUFREADY, &hsp->event))
+ if (test_and_clear_bit(HSCX_XMTBUFREADY, &hsp->event))
hscx_process_xmt(hsp);
}
diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c
index 5d3ab899e..b6b076360 100644
--- a/drivers/isdn/isdn_net.c
+++ b/drivers/isdn/isdn_net.c
@@ -934,7 +934,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
return 0;
}
/* Avoid timer-based retransmission conflicts. */
- if (set_bit(0, (void *) &ndev->tbusy) != 0)
+ if (test_and_set_bit(0, (void *) &ndev->tbusy) != 0)
printk(KERN_WARNING
"%s: Transmitter access conflict.\n",
ndev->name);
diff --git a/drivers/isdn/sc/Makefile b/drivers/isdn/sc/Makefile
index 5440cdaff..be0d8b76c 100644
--- a/drivers/isdn/sc/Makefile
+++ b/drivers/isdn/sc/Makefile
@@ -1,5 +1,5 @@
#
-# $Id: Makefile.kernel,v 1.1 1996/11/07 13:07:40 fritz Exp $
+# $Id: Makefile,v 1.2 1997/05/01 08:53:47 davem Exp $
# Copyright (C) 1996 SpellCaster Telecommunications Inc.
#
# This program is free software; you can redistribute it and/or modify
diff --git a/drivers/isdn/teles/Makefile b/drivers/isdn/teles/Makefile
deleted file mode 100644
index a252f46ba..000000000
--- a/drivers/isdn/teles/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-L_OBJS :=
-M_OBJS :=
-O_OBJS := mod.o card.o config.o buffers.o tei.o isdnl2.o isdnl3.o \
-llglue.o q931.o callc.o fsm.o
-
-O_TARGET :=
-ifeq ($(CONFIG_ISDN_DRV_TELES),y)
- O_TARGET += teles.o
-else
- ifeq ($(CONFIG_ISDN_DRV_TELES),m)
- O_TARGET += teles.o
- M_OBJS += teles.o
- endif
-endif
-
-include $(TOPDIR)/Rules.make
-
diff --git a/drivers/isdn/teles/buffers.c b/drivers/isdn/teles/buffers.c
deleted file mode 100644
index 74510a664..000000000
--- a/drivers/isdn/teles/buffers.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/* $Id: buffers.c,v 1.2 1996/07/04 22:46:20 dm Exp $
- *
- * $Log: buffers.c,v $
- * Revision 1.2 1996/07/04 22:46:20 dm
- * Merge to 2.0.1
- *
- * Revision 1.3 1996/05/31 00:56:53 fritz
- * removed cli() from BufPoolAdd, since it is called
- * with interrupts off anyway.
- *
- * Revision 1.2 1996/04/29 22:48:14 fritz
- * Removed compatibility-macros. No longer needed.
- *
- * Revision 1.1 1996/04/13 10:19:28 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-#include <linux/mm.h>
-#include <linux/malloc.h>
-
-
-void
-BufPoolInit(struct BufPool *bp, int order, int bpps,
- int maxpages)
-{
-#ifdef DEBUG_MAGIC
- generateerror
- bp->magic = 010167;
-#endif
-
-#if 0
- printk(KERN_DEBUG "BufPoolInit bp %x\n", bp);
-#endif
-
- bp->freelist = NULL;
- bp->pageslist = NULL;
- bp->pageorder = order;
- bp->pagescount = 0;
- bp->bpps = bpps;
- bp->bufsize = BUFFER_SIZE(order, bpps);
- bp->maxpages = maxpages;
-}
-
-int
-BufPoolAdd(struct BufPool *bp, int priority)
-{
- struct Pages *ptr;
- byte *bptr;
- int i;
- struct BufHeader *bh = NULL, *prev, *first;
-
-#if 0
- printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp);
-#endif
-
- ptr = (struct Pages *) __get_free_pages(priority, bp->pageorder, 0);
- if (!ptr) {
- printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n");
- return (-1);
- }
-#if 0
- printk(KERN_DEBUG "Order %d pages allocated at %x\n", bp->pageorder, ptr);
-#endif
-
- ptr->next = bp->pageslist;
- bp->pageslist = ptr;
- bp->pagescount++;
-
- bptr = (byte *) ptr + sizeof(struct Pages *);
-
- i = bp->bpps;
- first = (struct BufHeader *) bptr;
- prev = NULL;
- while (i--) {
- bh = (struct BufHeader *) bptr;
-#ifdef DEBUG_MAGIC
- bh->magic = 020167;
-#endif
- bh->next = prev;
- prev = bh;
- bh->bp = bp;
- bptr += PART_SIZE(bp->pageorder, bp->bpps);
- }
-
- first->next = bp->freelist;
- bp->freelist = bh;
- return (0);
-}
-
-void
-BufPoolFree(struct BufPool *bp)
-{
- struct Pages *p;
-
-#if 0
- printk(KERN_DEBUG "BufPoolFree bp %x\n", bp);
-#endif
-
- while (bp->pagescount--) {
- p = bp->pageslist->next;
- free_pages((unsigned long) bp->pageslist, bp->pageorder);
-#if 0
- printk(KERN_DEBUG "Free pages %x order %d\n", bp->pageslist, bp->pageorder);
-#endif
- bp->pageslist = p;
- }
-}
-
-int
-BufPoolGet(struct BufHeader **bh,
- struct BufPool *bp, int priority, void *heldby, int where)
-{
- long flags;
- int i;
-
-#ifdef DEBUG_MAGIC
- if (bp->magic != 010167) {
- printk(KERN_DEBUG "BufPoolGet: not a BufHeader\n");
- return (-1);
- }
-#endif
-
- save_flags(flags);
- cli();
- i = 0;
- while (!0) {
- if (bp->freelist) {
- *bh = bp->freelist;
- bp->freelist = bp->freelist->next;
- (*bh)->heldby = heldby;
- (*bh)->where = where;
- restore_flags(flags);
- return (0);
- }
- if ((i == 0) && (bp->pagescount < bp->maxpages)) {
- if (BufPoolAdd(bp, priority)) {
- restore_flags(flags);
- return -1;
- }
- i++;
- } else {
- *bh = NULL;
- restore_flags(flags);
- return (-1);
- }
- }
-
-}
-
-void
-BufPoolRelease(struct BufHeader *bh)
-{
- struct BufPool *bp;
- long flags;
-
-#ifdef DEBUG_MAGIC
- if (bh->magic != 020167) {
- printk(KERN_DEBUG "BufPoolRelease: not a BufHeader\n");
- printk(KERN_DEBUG "called from %x\n", return_address());
- return;
- }
-#endif
-
- bp = bh->bp;
-
-#ifdef DEBUG_MAGIC
- if (bp->magic != 010167) {
- printk(KERN_DEBUG "BufPoolRelease: not a BufPool\n");
- return;
- }
-#endif
-
- save_flags(flags);
- cli();
- bh->next = bp->freelist;
- bp->freelist = bh;
- restore_flags(flags);
-}
-
-void
-BufQueueLink(struct BufQueue *bq,
- struct BufHeader *bh)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (!bq->head)
- bq->head = bh;
- if (bq->tail)
- bq->tail->next = bh;
- bq->tail = bh;
- bh->next = NULL;
- restore_flags(flags);
-}
-
-void
-BufQueueLinkFront(struct BufQueue *bq,
- struct BufHeader *bh)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- bh->next = bq->head;
- bq->head = bh;
- if (!bq->tail)
- bq->tail = bh;
- restore_flags(flags);
-}
-
-int
-BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq)
-{
- long flags;
-
- save_flags(flags);
- cli();
-
- if (bq->head) {
- if (bq->tail == bq->head)
- bq->tail = NULL;
- *bh = bq->head;
- bq->head = (*bh)->next;
- restore_flags(flags);
- return (0);
- } else {
- restore_flags(flags);
- return (-1);
- }
-}
-
-void
-BufQueueInit(struct BufQueue *bq)
-{
-#ifdef DEBUG_MAGIC
- bq->magic = 030167;
-#endif
- bq->head = NULL;
- bq->tail = NULL;
-}
-
-void
-BufQueueRelease(struct BufQueue *bq)
-{
- struct BufHeader *bh;
-
- while (bq->head) {
- BufQueueUnlink(&bh, bq);
- BufPoolRelease(bh);
- }
-}
-
-int
-BufQueueLength(struct BufQueue *bq)
-{
- int i = 0;
- struct BufHeader *bh;
-
- bh = bq->head;
- while (bh) {
- i++;
- bh = bh->next;
- }
- return (i);
-}
-
-void
-BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
- int releasetoo)
-{
- long flags;
- struct BufHeader *sp;
-
- save_flags(flags);
- cli();
-
- while (!0) {
- sp = q->head;
- if (!sp)
- break;
- if ((sp->primitive == pr) && (sp->heldby == heldby)) {
- q->head = sp->next;
- if (q->tail == sp)
- q->tail = NULL;
- if (releasetoo)
- BufPoolRelease(sp);
- } else
- break;
- }
-
- sp = q->head;
- if (sp)
- while (sp->next) {
- if ((sp->next->primitive == pr) && (sp->next->heldby == heldby)) {
- if (q->tail == sp->next)
- q->tail = sp;
- if (releasetoo)
- BufPoolRelease(sp->next);
- sp->next = sp->next->next;
- } else
- sp = sp->next;
- }
- restore_flags(flags);
-}
-
-void
-Sfree(byte * ptr)
-{
-#if 0
- printk(KERN_DEBUG "Sfree %x\n", ptr);
-#endif
- kfree(ptr);
-}
-
-byte *
-Smalloc(int size, int pr, char *why)
-{
- byte *p;
-
- p = (byte *) kmalloc(size, pr);
-#if 0
- printk(KERN_DEBUG "Smalloc %s size %d res %x\n", why, size, p);
-#endif
- return (p);
-}
diff --git a/drivers/isdn/teles/callc.c b/drivers/isdn/teles/callc.c
deleted file mode 100644
index b065d5670..000000000
--- a/drivers/isdn/teles/callc.c
+++ /dev/null
@@ -1,1453 +0,0 @@
-/* $Id: callc.c,v 1.16 1997/02/11 01:39:46 keil Exp $
- *
- * $Log: callc.c,v $
- * Revision 1.16 1997/02/11 01:39:46 keil
- * Changed setup-interface (incoming and outgoing)
- *
- * Revision 1.15 1996/11/23 11:32:20 keil
- * windowsize = 7 X.75 bugfix Thanks to Martin Maurer
- *
- * Revision 1.14 1996/10/22 23:14:14 fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.13 1996/06/24 17:15:55 fritz
- * corrected return code of teles_writebuf()
- *
- * Revision 1.12 1996/06/12 16:15:33 fritz
- * Extended user-configurable debugging flags.
- *
- * Revision 1.11 1996/06/07 12:32:20 fritz
- * More changes to support suspend/resume.
- *
- * Revision 1.10 1996/06/06 21:24:21 fritz
- * Started adding support for suspend/resume.
- *
- * Revision 1.9 1996/05/31 12:23:57 jdenoud
- * Jan: added channel open check to teles_writebuf
- *
- * Revision 1.8 1996/05/31 01:00:38 fritz
- * Changed return code of teles_writebuf, when out of memory.
- *
- * Revision 1.7 1996/05/17 03:40:37 fritz
- * General cleanup.
- *
- * Revision 1.6 1996/05/10 22:42:07 fritz
- * Added entry for EV_RELEASE_CNF in ST_OUT (if no D-Channel avail.)
- *
- * Revision 1.5 1996/05/06 10:16:15 fritz
- * Added voice stuff.
- *
- * Revision 1.4 1996/04/30 22:04:05 isdn4dev
- * improved callback Karsten Keil
- *
- * Revision 1.3 1996/04/30 10:04:19 fritz
- * Started voice support.
- * Added printk() to debug-switcher for easier
- * synchronization between printk()'s and output
- * of /dev/isdnctrl.
- *
- * Revision 1.2 1996/04/20 16:42:29 fritz
- * Changed statemachine to allow reject of incoming calls.
- *
- * Revision 1.1 1996/04/13 10:20:59 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern int nrcards;
-extern int drid;
-extern isdn_if iif;
-extern void teles_mod_dec_use_count(void);
-extern void teles_mod_inc_use_count(void);
-
-static int init_ds(int chan, int incoming);
-static void release_ds(int chan);
-
-static struct Fsm callcfsm =
-{NULL, 0, 0}, lcfsm =
-{NULL, 0, 0};
-
-struct Channel *chanlist;
-static int chancount = 0;
-unsigned int debugflags = 0;
-
-#define TMR_DCHAN_EST 2000
-
-static void
-stat_debug(struct Channel *chanp, char *s)
-{
- char tmp[100], tm[32];
-
- jiftime(tm, jiffies);
- sprintf(tmp, "%s Channel %d HL->LL %s\n", tm, chanp->chan, s);
- teles_putstatus(tmp);
-}
-
-enum {
- ST_NULL, /* 0 inactive */
- ST_OUT, /* 1 outgoing, awaiting SETUP confirm */
- ST_CLEAR, /* 2 call release, awaiting RELEASE confirm */
- ST_OUT_W, /* 3 outgoing, awaiting d-channel establishment */
- ST_REL_W, /* 4 awaiting d-channel release */
- ST_IN_W, /* 5 incoming, awaiting d-channel establishment */
- ST_IN, /* 6 incoming call received */
- ST_IN_SETUP, /* 7 incoming, SETUP response sent */
- ST_IN_DACT, /* 8 incoming connected, no b-channel prot. */
- ST_OUT_ESTB, /* 10 outgoing connected, awaiting b-channel prot. estbl. */
- ST_ACTIVE, /* 11 active, b channel prot. established */
- ST_BC_HANGUP, /* 12 call clear. (initiator), awaiting b channel prot. rel. */
- ST_PRO_W, /* 13 call clear. (initiator), DISCONNECT req. sent */
- ST_ANT_W, /* 14 call clear. (receiver), awaiting DISCONNECT ind. */
- ST_DISC_BC_HANGUP, /* d channel gone, wait for b channel deactivation */
- ST_OUT_W_HANGUP, /* Outgoing waiting for D-Channel hangup received */
- ST_D_ERR, /* d channel released while active */
-};
-
-#define STATE_COUNT (ST_D_ERR+1)
-
-static char *strState[] =
-{
- "ST_NULL",
- "ST_OUT",
- "ST_CLEAR",
- "ST_OUT_W",
- "ST_REL_W",
- "ST_IN_W",
- "ST_IN",
- "ST_IN_SETUP",
- "ST_IN_DACT",
- "ST_OUT_ESTB",
- "ST_ACTIVE",
- "ST_BC_HANGUP",
- "ST_PRO_W",
- "ST_ANT_W",
- "ST_DISC_BC_HANGUP",
- "ST_OUT_W_HANGUP",
- "ST_D_ERR",
-};
-
-enum {
- EV_DIAL, /* 0 */
- EV_SETUP_CNF, /* 1 */
- EV_ACCEPTB, /* 2 */
- EV_DISCONNECT_CNF, /* 5 */
- EV_DISCONNECT_IND, /* 6 */
- EV_RELEASE_CNF, /* 7 */
- EV_DLEST, /* 8 */
- EV_DLRL, /* 9 */
- EV_SETUP_IND, /* 10 */
- EV_RELEASE_IND, /* 11 */
- EV_ACCEPTD, /* 12 */
- EV_SETUP_CMPL_IND, /* 13 */
- EV_BC_EST, /* 14 */
- EV_WRITEBUF, /* 15 */
- EV_DATAIN, /* 16 */
- EV_HANGUP, /* 17 */
- EV_BC_REL, /* 18 */
- EV_CINF, /* 19 */
- EV_SUSPEND, /* 20 */
- EV_RESUME, /* 21 */
-};
-
-#define EVENT_COUNT (EV_CINF+1)
-
-static char *strEvent[] =
-{
- "EV_DIAL",
- "EV_SETUP_CNF",
- "EV_ACCEPTB",
- "EV_DISCONNECT_CNF",
- "EV_DISCONNECT_IND",
- "EV_RELEASE_CNF",
- "EV_DLEST",
- "EV_DLRL",
- "EV_SETUP_IND",
- "EV_RELEASE_IND",
- "EV_ACCEPTD",
- "EV_SETUP_CMPL_IND",
- "EV_BC_EST",
- "EV_WRITEBUF",
- "EV_DATAIN",
- "EV_HANGUP",
- "EV_BC_REL",
- "EV_CINF",
- "EV_SUSPEND",
- "EV_RESUME",
-};
-
-enum {
- ST_LC_NULL,
- ST_LC_ACTIVATE_WAIT,
- ST_LC_DELAY,
- ST_LC_ESTABLISH_WAIT,
- ST_LC_CONNECTED,
- ST_LC_RELEASE_WAIT,
-};
-
-#define LC_STATE_COUNT (ST_LC_RELEASE_WAIT+1)
-
-static char *strLcState[] =
-{
- "ST_LC_NULL",
- "ST_LC_ACTIVATE_WAIT",
- "ST_LC_DELAY",
- "ST_LC_ESTABLISH_WAIT",
- "ST_LC_CONNECTED",
- "ST_LC_RELEASE_WAIT",
-};
-
-enum {
- EV_LC_ESTABLISH,
- EV_LC_PH_ACTIVATE,
- EV_LC_PH_DEACTIVATE,
- EV_LC_DL_ESTABLISH,
- EV_LC_TIMER,
- EV_LC_DL_RELEASE,
- EV_LC_RELEASE,
-};
-
-#define LC_EVENT_COUNT (EV_LC_RELEASE+1)
-
-static char *strLcEvent[] =
-{
- "EV_LC_ESTABLISH",
- "EV_LC_PH_ACTIVATE",
- "EV_LC_PH_DEACTIVATE",
- "EV_LC_DL_ESTABLISH",
- "EV_LC_TIMER",
- "EV_LC_DL_RELEASE",
- "EV_LC_RELEASE",
-};
-
-#define LC_D 0
-#define LC_B 1
-
-/*
- * Dial out
- */
-static void
-r1(struct FsmInst *fi, int event, void *arg)
-{
- isdn_ctrl *ic = arg;
- struct Channel *chanp = fi->userdata;
-
- chanp->para.setup = ic->parm.setup;
- if (!strcmp(chanp->para.setup.eazmsn, "0"))
- chanp->para.setup.eazmsn[0] = '\0';
-
- chanp->l2_active_protocol = chanp->l2_protocol;
- chanp->incoming = 0;
- chanp->lc_b.l2_start = !0;
-
- switch (chanp->l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- chanp->lc_b.l2_establish = !0;
- break;
- case (ISDN_PROTO_L2_HDLC):
- case (ISDN_PROTO_L2_TRANS):
- chanp->lc_b.l2_establish = 0;
- break;
- default:
- printk(KERN_WARNING "r1 unknown protocol\n");
- break;
- }
-
- FsmChangeState(fi, ST_OUT_W);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-ll_hangup(struct Channel *chanp, int bchantoo)
-{
- isdn_ctrl ic;
-
- if (bchantoo) {
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_BHUP");
- ic.driver = drid;
- ic.command = ISDN_STAT_BHUP;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
- }
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_DHUP");
- ic.driver = drid;
- ic.command = ISDN_STAT_DHUP;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
-}
-
-static void
-r2(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
- FsmChangeState(fi, ST_CLEAR);
- ll_hangup(chanp, 0);
-}
-
-
-static void
-r2_1(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-
- FsmChangeState(fi, ST_OUT_W_HANGUP);
-}
-
-
-static void
-r2_2(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_REL_W);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
- ll_hangup(chanp, 0);
-}
-
-
-static void
-r3(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
- FsmChangeState(fi, ST_REL_W);
-}
-
-
-static void
-r3_1(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
-
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
- FsmChangeState(fi, ST_REL_W);
- ll_hangup(chanp, 0);
-}
-
-
-static void
-r4(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp=fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
- FsmChangeState(fi, ST_NULL);
-}
-
-static void
-r5(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->para.callref = chanp->outcallref;
-
- chanp->outcallref++;
- if (chanp->outcallref == 128)
- chanp->outcallref = 64;
-
- chanp->is.l4.l4l3(&chanp->is, CC_SETUP_REQ, NULL);
-
- FsmChangeState(fi, ST_OUT);
-}
-
-static void
-r6(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_IN_W);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-r7(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
- /*
- * Report incoming calls only once to linklevel, use octet 3 of
- * channel identification information element. (it's value
- * is copied to chanp->para.bchannel in l3s12(), file isdnl3.c)
- */
- if (((chanp->chan & 1) + 1) & chanp->para.bchannel) {
- chanp->is.l4.l4l3(&chanp->is, CC_ALERTING_REQ, NULL);
- FsmChangeState(fi, ST_IN);
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_ICALL");
- ic.driver = drid;
- ic.command = ISDN_STAT_ICALL;
- ic.arg = chanp->chan;
- /*
- * No need to return "unknown" for calls without OAD,
- * cause that's handled in linklevel now (replaced by '0')
- */
- ic.parm.setup = chanp->para.setup;
- iif.statcallb(&ic);
- } else {
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
- FsmChangeState(fi, ST_REL_W);
- }
-}
-
-static void
-r8(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_IN_SETUP);
- chanp->is.l4.l4l3(&chanp->is, CC_SETUP_RSP, NULL);
-
-}
-
-static void
-r9(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_IN_DACT);
-
- chanp->l2_active_protocol = chanp->l2_protocol;
- chanp->incoming = !0;
- chanp->lc_b.l2_start = 0;
-
- switch (chanp->l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- chanp->lc_b.l2_establish = !0;
- break;
- case (ISDN_PROTO_L2_HDLC):
- case (ISDN_PROTO_L2_TRANS):
- chanp->lc_b.l2_establish = 0;
- break;
- default:
- printk(KERN_WARNING "r9 unknown protocol\n");
- break;
- }
-
- init_ds(chanp->chan, !0);
-
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-r10(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_OUT_ESTB);
-
- init_ds(chanp->chan, 0);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
-
-}
-
-static void
-r12(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
- FsmChangeState(fi, ST_ACTIVE);
- chanp->data_open = !0;
-
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_DCONN");
- ic.driver = drid;
- ic.command = ISDN_STAT_DCONN;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
-
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_BCONN");
- ic.driver = drid;
- ic.command = ISDN_STAT_BCONN;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
-}
-
-static void
-r15(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- FsmChangeState(fi, ST_BC_HANGUP);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r16(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_PRO_W);
- chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-}
-
-static void
-r17(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_ANT_W);
-}
-
-
-static void
-r17_1(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- release_ds(chanp->chan);
-
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
-
- FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL);
-
- FsmChangeState(fi, ST_NULL);
-
- ll_hangup(chanp,!0);
-}
-
-static void
-r18(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_REL_W);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
-
- ll_hangup(chanp, !0);
-}
-
-static void
-r19(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_CLEAR);
-
- chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
- ll_hangup(chanp, !0);
-}
-
-static void
-r20(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
-
- FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL);
-
- FsmChangeState(fi, ST_NULL);
-
- ll_hangup(chanp, 0);
-}
-
-
-static void
-r21(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- FsmChangeState(fi, ST_DISC_BC_HANGUP);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r22(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_CLEAR);
-
- chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
- ll_hangup(chanp, !0);
-}
-
-static void
-r23(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_PRO_W);
- chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-}
-
-static void
-r23_1(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- chanp->is.l4.l4l3(&chanp->is, CC_DLRL,NULL);
-
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE,NULL);
-
- FsmChangeState(fi, ST_NULL);
-
- ll_hangup(chanp,!0);
-}
-
-static void
-r24(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- FsmChangeState(fi, ST_D_ERR);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r25(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_NULL);
-
- ll_hangup(chanp, !0);
-}
-
-static void
-r26(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
-
- ic.driver = drid;
- ic.command = ISDN_STAT_CINF;
- ic.arg = chanp->chan;
- sprintf(ic.parm.num, "%d", chanp->para.chargeinfo);
- iif.statcallb(&ic);
-}
-
-
-
-static struct FsmNode fnlist[] =
-{
- {ST_NULL, EV_DIAL, r1},
- {ST_OUT_W, EV_DLEST, r5},
- {ST_OUT_W, EV_DLRL, r20},
- {ST_OUT_W, EV_RELEASE_CNF, r2_2 },
- {ST_OUT, EV_DISCONNECT_IND, r2},
- {ST_OUT, EV_SETUP_CNF, r10},
- {ST_OUT, EV_HANGUP, r2_1},
- {ST_OUT, EV_RELEASE_IND, r20},
- {ST_OUT, EV_RELEASE_CNF, r20},
- {ST_OUT, EV_DLRL, r2_2},
- {ST_OUT_W_HANGUP, EV_RELEASE_IND, r2_2},
- {ST_OUT_W_HANGUP, EV_DLRL, r20},
- {ST_CLEAR, EV_RELEASE_CNF, r3},
- {ST_CLEAR, EV_DLRL, r20},
- {ST_REL_W, EV_DLRL, r4},
- {ST_NULL, EV_SETUP_IND, r6},
- {ST_IN_W, EV_DLEST, r7},
- {ST_IN_W, EV_DLRL, r3_1},
- {ST_IN, EV_DLRL, r3_1},
- {ST_IN, EV_HANGUP, r2_1},
- {ST_IN, EV_RELEASE_IND, r2_2},
- {ST_IN, EV_RELEASE_CNF, r2_2},
- {ST_IN, EV_ACCEPTD, r8},
- {ST_IN_SETUP, EV_HANGUP, r2_1},
- {ST_IN_SETUP, EV_SETUP_CMPL_IND, r9},
- {ST_IN_SETUP, EV_RELEASE_IND, r2_2},
- {ST_IN_SETUP, EV_DISCONNECT_IND, r2},
- {ST_IN_SETUP, EV_DLRL, r20},
- {ST_OUT_ESTB, EV_BC_EST, r12},
- {ST_OUT_ESTB, EV_BC_REL, r23},
- {ST_OUT_ESTB, EV_DLRL, r23_1},
- {ST_IN_DACT, EV_BC_EST, r12},
- {ST_IN_DACT, EV_BC_REL, r17},
- {ST_IN_DACT, EV_DLRL, r17_1},
- {ST_ACTIVE, EV_HANGUP, r15},
- {ST_ACTIVE, EV_BC_REL, r17},
- {ST_ACTIVE, EV_DISCONNECT_IND, r21},
- {ST_ACTIVE, EV_DLRL, r24},
- {ST_ACTIVE, EV_CINF, r26},
- {ST_ACTIVE, EV_RELEASE_IND, r17},
- {ST_BC_HANGUP, EV_BC_REL, r16},
- {ST_BC_HANGUP, EV_DISCONNECT_IND, r21},
- {ST_PRO_W, EV_RELEASE_IND, r18},
- {ST_ANT_W, EV_DISCONNECT_IND, r19},
- {ST_DISC_BC_HANGUP, EV_BC_REL, r22},
- {ST_D_ERR, EV_BC_REL, r25},
-};
-
-#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
-
-static void
-lc_r1(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- FsmChangeState(fi, ST_LC_ACTIVATE_WAIT);
- FsmAddTimer(&lf->act_timer, 1000, EV_LC_TIMER, NULL, 50);
- lf->st->ma.manl1(lf->st, PH_ACTIVATE, NULL);
-
-}
-
-static void
-lc_r6(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- FsmDelTimer(&lf->act_timer, 50);
- FsmChangeState(fi, ST_LC_DELAY);
- FsmAddTimer(&lf->act_timer, 40, EV_LC_TIMER, NULL, 51);
-}
-
-static void
-lc_r2(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- if (lf->l2_establish) {
- FsmChangeState(fi, ST_LC_ESTABLISH_WAIT);
- if (lf->l2_start)
- lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL);
- } else {
- FsmChangeState(fi, ST_LC_CONNECTED);
- lf->lccall(lf, LC_ESTABLISH, NULL);
- }
-}
-
-static void
-lc_r3(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- FsmChangeState(fi, ST_LC_CONNECTED);
- lf->lccall(lf, LC_ESTABLISH, NULL);
-}
-
-static void
-lc_r4(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- if (lf->l2_establish) {
- FsmChangeState(fi, ST_LC_RELEASE_WAIT);
- lf->st->ma.manl2(lf->st, DL_RELEASE, NULL);
- } else {
- FsmChangeState(fi, ST_LC_NULL);
- lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
- lf->lccall(lf, LC_RELEASE, NULL);
- }
-}
-
-static void
-lc_r5(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- FsmChangeState(fi, ST_LC_NULL);
- lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
- lf->lccall(lf, LC_RELEASE, NULL);
-}
-
-static struct FsmNode LcFnList[] =
-{
- {ST_LC_NULL, EV_LC_ESTABLISH, lc_r1},
- {ST_LC_ACTIVATE_WAIT, EV_LC_PH_ACTIVATE, lc_r6},
- {ST_LC_DELAY, EV_LC_TIMER, lc_r2},
- {ST_LC_ESTABLISH_WAIT, EV_LC_DL_ESTABLISH, lc_r3},
- {ST_LC_CONNECTED, EV_LC_RELEASE, lc_r4},
- {ST_LC_CONNECTED, EV_LC_DL_RELEASE, lc_r5},
- {ST_LC_RELEASE_WAIT, EV_LC_DL_RELEASE, lc_r5},
- {ST_LC_ACTIVATE_WAIT, EV_LC_TIMER, lc_r5},
- {ST_LC_ESTABLISH_WAIT, EV_LC_DL_RELEASE, lc_r5},
-};
-
-#define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode))
-
-void
-CallcNew(void)
-{
- callcfsm.state_count = STATE_COUNT;
- callcfsm.event_count = EVENT_COUNT;
- callcfsm.strEvent = strEvent;
- callcfsm.strState = strState;
- FsmNew(&callcfsm, fnlist, FNCOUNT);
-
- lcfsm.state_count = LC_STATE_COUNT;
- lcfsm.event_count = LC_EVENT_COUNT;
- lcfsm.strEvent = strLcEvent;
- lcfsm.strState = strLcState;
- FsmNew(&lcfsm, LcFnList, LC_FN_COUNT);
-}
-
-void
-CallcFree(void)
-{
- FsmFree(&lcfsm);
- FsmFree(&callcfsm);
-}
-
-static void
-release_ds(int chan)
-{
- struct PStack *st = &chanlist[chan].ds;
- struct IsdnCardState *sp;
- struct HscxState *hsp;
-
- sp = st->l1.hardware;
- hsp = sp->hs + chanlist[chan].hscx;
-
- close_hscxstate(hsp);
-
- switch (chanlist[chan].l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- releasestack_isdnl2(st);
- break;
- case (ISDN_PROTO_L2_HDLC):
- case (ISDN_PROTO_L2_TRANS):
- releasestack_transl2(st);
- break;
- }
-}
-
-static void
-cc_l1man(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (PH_ACTIVATE):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_ACTIVATE, NULL);
- break;
- case (PH_DEACTIVATE):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_DEACTIVATE, NULL);
- break;
- }
-}
-
-static void
-cc_l2man(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (DL_ESTABLISH):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_ESTABLISH, NULL);
- break;
- case (DL_RELEASE):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_RELEASE, NULL);
- break;
- }
-}
-
-static void
-dcc_l1man(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (PH_ACTIVATE):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_ACTIVATE, NULL);
- break;
- case (PH_DEACTIVATE):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_DEACTIVATE, NULL);
- break;
- }
-}
-
-static void
-dcc_l2man(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (DL_ESTABLISH):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_ESTABLISH, NULL);
- break;
- case (DL_RELEASE):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_RELEASE, NULL);
- break;
- }
-}
-
-static void
-ll_handler(struct PStack *st, int pr,
- struct BufHeader *ibh)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (CC_DISCONNECT_IND):
- FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
- break;
- case (CC_RELEASE_CNF):
- FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
- break;
- case (CC_SETUP_IND):
- FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
- break;
- case (CC_RELEASE_IND):
- FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL);
- break;
- case (CC_SETUP_COMPLETE_IND):
- FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL);
- break;
- case (CC_SETUP_CNF):
- FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
- break;
- case (CC_INFO_CHARGE):
- FsmEvent(&chanp->fi, EV_CINF, NULL);
- break;
- }
-}
-
-static void
-init_is(int chan, unsigned int ces)
-{
- struct PStack *st = &(chanlist[chan].is);
- struct IsdnCardState *sp = chanlist[chan].sp;
- char tmp[128];
-
- setstack_teles(st, sp);
-
- st->l2.sap = 0;
-
- st->l2.tei = 255;
-
- st->l2.ces = ces;
- st->l2.extended = !0;
- st->l2.laptype = LAPD;
- st->l2.window = 1;
- st->l2.orig = !0;
- st->l2.t200 = 1000; /* 1000 milliseconds */
- if (st->protocol == ISDN_PTYPE_1TR6) {
- st->l2.n200 = 3; /* try 3 times */
- st->l2.t203 = 10000; /* 10000 milliseconds */
- } else {
- st->l2.n200 = 4; /* try 4 times */
- st->l2.t203 = 5000; /* 5000 milliseconds */
- }
-
- sprintf(tmp, "Channel %d q.921", chan);
- setstack_isdnl2(st, tmp);
- setstack_isdnl3(st);
- st->l2.debug = 2;
- st->l3.debug = 2;
- st->l2.debug = 0xff;
- st->l3.debug = 0xff;
- st->l4.userdata = chanlist + chan;
- st->l4.l2writewakeup = NULL;
-
- st->l3.l3l4 = ll_handler;
- st->l1.l1man = cc_l1man;
- st->l2.l2man = cc_l2man;
-
- st->pa = &chanlist[chan].para;
- teles_addlist(sp, st);
-}
-
-static void
-callc_debug(struct FsmInst *fi, char *s)
-{
- char str[80], tm[32];
- struct Channel *chanp = fi->userdata;
-
- jiftime(tm, jiffies);
- sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s);
- teles_putstatus(str);
-}
-
-static void
-lc_debug(struct FsmInst *fi, char *s)
-{
- char str[256], tm[32];
- struct LcFsm *lf = fi->userdata;
-
- jiftime(tm, jiffies);
- sprintf(str, "%s Channel %d lc %s\n", tm, lf->ch->chan, s);
- teles_putstatus(str);
-}
-
-static void
-dlc_debug(struct FsmInst *fi, char *s)
-{
- char str[256], tm[32];
- struct LcFsm *lf = fi->userdata;
-
- jiftime(tm, jiffies);
- sprintf(str, "%s Channel %d dlc %s\n", tm, lf->ch->chan, s);
- teles_putstatus(str);
-}
-
-static void
-lccall_d(struct LcFsm *lf, int pr, void *arg)
-{
- struct Channel *chanp = lf->ch;
-
- switch (pr) {
- case (LC_ESTABLISH):
- FsmEvent(&chanp->fi, EV_DLEST, NULL);
- break;
- case (LC_RELEASE):
- FsmEvent(&chanp->fi, EV_DLRL, NULL);
- break;
- }
-}
-
-static void
-lccall_b(struct LcFsm *lf, int pr, void *arg)
-{
- struct Channel *chanp = lf->ch;
-
- switch (pr) {
- case (LC_ESTABLISH):
- FsmEvent(&chanp->fi, EV_BC_EST, NULL);
- break;
- case (LC_RELEASE):
- FsmEvent(&chanp->fi, EV_BC_REL, NULL);
- break;
- }
-}
-
-static void
-init_chan(int chan, int cardnr, int hscx,
- unsigned int ces)
-{
- struct IsdnCard *card = cards + cardnr;
- struct Channel *chanp = chanlist + chan;
-
- chanp->sp = card->sp;
- chanp->hscx = hscx;
- chanp->chan = chan;
- chanp->incoming = 0;
- chanp->debug = 0;
- init_is(chan, ces);
-
- chanp->fi.fsm = &callcfsm;
- chanp->fi.state = ST_NULL;
- chanp->fi.debug = 0;
- chanp->fi.userdata = chanp;
- chanp->fi.printdebug = callc_debug;
-
- chanp->lc_d.lcfi.fsm = &lcfsm;
- chanp->lc_d.lcfi.state = ST_LC_NULL;
- chanp->lc_d.lcfi.debug = 0;
- chanp->lc_d.lcfi.userdata = &chanp->lc_d;
- chanp->lc_d.lcfi.printdebug = lc_debug;
- chanp->lc_d.type = LC_D;
- chanp->lc_d.ch = chanp;
- chanp->lc_d.st = &chanp->is;
- chanp->lc_d.l2_establish = !0;
- chanp->lc_d.l2_start = !0;
- chanp->lc_d.lccall = lccall_d;
- FsmInitTimer(&chanp->lc_d.lcfi, &chanp->lc_d.act_timer);
-
- chanp->lc_b.lcfi.fsm = &lcfsm;
- chanp->lc_b.lcfi.state = ST_LC_NULL;
- chanp->lc_b.lcfi.debug = 0;
- chanp->lc_b.lcfi.userdata = &chanp->lc_b;
- chanp->lc_b.lcfi.printdebug = dlc_debug;
- chanp->lc_b.type = LC_B;
- chanp->lc_b.ch = chanp;
- chanp->lc_b.st = &chanp->ds;
- chanp->lc_b.l2_establish = !0;
- chanp->lc_b.l2_start = !0;
- chanp->lc_b.lccall = lccall_b;
- FsmInitTimer(&chanp->lc_b.lcfi, &chanp->lc_b.act_timer);
-
- chanp->outcallref = 64;
- chanp->data_open = 0;
-}
-
-int
-CallcNewChan(void)
-{
- int i, ces, c;
-
- chancount = 0;
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp)
- chancount += 2;
-
- chanlist = (struct Channel *) Smalloc(sizeof(struct Channel) *
- chancount, GFP_KERNEL, "chanlist");
-
- c = 0;
- ces = randomces();
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp) {
- init_chan(c++, i, 1, ces++);
- ces %= 0xffff;
- init_chan(c++, i, 0, ces++);
- ces %= 0xffff;
- }
- printk(KERN_INFO "channels %d\n", chancount);
- return (chancount);
-
-}
-
-static void
-release_is(int chan)
-{
- struct PStack *st = &chanlist[chan].is;
-
- releasestack_isdnl2(st);
- teles_rmlist(st->l1.hardware, st);
- BufQueueRelease(&st->l2.i_queue);
-}
-
-void
-CallcFreeChan(void)
-{
- int i;
-
- for (i = 0; i < chancount; i++)
- release_is(i);
- Sfree((void *) chanlist);
-}
-
-static void
-lldata_handler(struct PStack *st, int pr,
- void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
- byte *ptr;
- int size;
- struct BufHeader *ibh = arg;
-
- switch (pr) {
- case (DL_DATA):
- if (chanp->data_open) {
- ptr = DATAPTR(ibh);
- ptr += chanp->ds.l2.ihsize;
- size = ibh->datasize - chanp->ds.l2.ihsize;
- iif.rcvcallb(drid, chanp->chan, ptr, size);
- }
- BufPoolRelease(ibh);
- break;
- default:
- printk(KERN_WARNING "lldata_handler unknown primitive\n");
- break;
- }
-}
-
-static void
-lltrans_handler(struct PStack *st, int pr,
- struct BufHeader *ibh)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
- byte *ptr;
-
- switch (pr) {
- case (PH_DATA):
- if (chanp->data_open) {
- ptr = DATAPTR(ibh);
- iif.rcvcallb(drid, chanp->chan, ptr, ibh->datasize);
- }
- BufPoolRelease(ibh);
- break;
- default:
- printk(KERN_WARNING "lltrans_handler unknown primitive\n");
- break;
- }
-}
-
-static void
-ll_writewakeup(struct PStack *st)
-{
- struct Channel *chanp = st->l4.userdata;
- isdn_ctrl ic;
-
- ic.driver = drid;
- ic.command = ISDN_STAT_BSENT;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
-}
-
-static int
-init_ds(int chan, int incoming)
-{
- struct PStack *st = &(chanlist[chan].ds);
- struct IsdnCardState *sp = (struct IsdnCardState *)
- chanlist[chan].is.l1.hardware;
- struct HscxState *hsp = sp->hs + chanlist[chan].hscx;
- char tmp[128];
-
- st->l1.hardware = sp;
-
- hsp->mode = 2;
- hsp->transbufsize = 4000;
-
- if (setstack_hscx(st, hsp))
- return (-1);
-
- st->l2.extended = 0;
- st->l2.laptype = LAPB;
- st->l2.orig = !incoming;
- st->l2.t200 = 1000; /* 1000 milliseconds */
- st->l2.window = 7;
- st->l2.n200 = 4; /* try 4 times */
- st->l2.t203 = 5000; /* 5000 milliseconds */
-
- st->l2.debug = 0xff;
- st->l3.debug = 0xff;
- switch (chanlist[chan].l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- sprintf(tmp, "Channel %d x.75", chan);
- setstack_isdnl2(st, tmp);
- st->l2.l2l3 = lldata_handler;
- st->l1.l1man = dcc_l1man;
- st->l2.l2man = dcc_l2man;
- st->l4.userdata = chanlist + chan;
- st->l4.l1writewakeup = NULL;
- st->l4.l2writewakeup = ll_writewakeup;
- st->l2.l2m.debug = debugflags & 16;
- st->ma.manl2(st, MDL_NOTEIPROC, NULL);
- st->l1.hscxmode = 2; /* Packet-Mode ? */
- st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
- break;
- case (ISDN_PROTO_L2_HDLC):
- st->l1.l1l2 = lltrans_handler;
- st->l1.l1man = dcc_l1man;
- st->l4.userdata = chanlist + chan;
- st->l4.l1writewakeup = ll_writewakeup;
- st->l1.hscxmode = 2;
- st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
- break;
- case (ISDN_PROTO_L2_TRANS):
- st->l1.l1l2 = lltrans_handler;
- st->l1.l1man = dcc_l1man;
- st->l4.userdata = chanlist + chan;
- st->l4.l1writewakeup = ll_writewakeup;
- st->l1.hscxmode = 1;
- st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
- break;
- }
-
- return (0);
-
-}
-
-static void
-channel_report(int i)
-{
-}
-
-static void
-command_debug(struct Channel *chanp, char *s)
-{
- char tmp[64], tm[32];
-
- jiftime(tm, jiffies);
- sprintf(tmp, "%s Channel %d LL->HL %s\n", tm, chanp->chan, s);
- teles_putstatus(tmp);
-}
-
-static void
-distr_debug(void)
-{
- int i;
-
- for (i = 0; i < chancount; i++) {
- chanlist[i].debug = debugflags & 1;
- chanlist[i].fi.debug = debugflags & 2;
- chanlist[i].is.l2.l2m.debug = debugflags & 8;
- chanlist[i].ds.l2.l2m.debug = debugflags & 16;
- }
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp) {
- cards[i].sp->dlogflag = debugflags & 4;
- cards[i].sp->debug = debugflags & 32;
- }
-}
-
-int
-teles_command(isdn_ctrl * ic)
-{
- struct Channel *chanp;
- char tmp[64];
- int i;
- unsigned int num;
-
- switch (ic->command) {
- case (ISDN_CMD_SETEAZ):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1)
- command_debug(chanp, "SETEAZ");
- return (0);
- case (ISDN_CMD_DIAL):
- chanp = chanlist + (ic->arg & 0xff);
- if (chanp->debug & 1) {
- sprintf(tmp, "DIAL %s -> %s (%d,%d)",
- ic->parm.setup.eazmsn, ic->parm.setup.phone,
- ic->parm.setup.si1, ic->parm.setup.si2);
- command_debug(chanp, tmp);
- }
- FsmEvent(&chanp->fi, EV_DIAL, ic);
- return (0);
- case (ISDN_CMD_ACCEPTB):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1)
- command_debug(chanp, "ACCEPTB");
- FsmEvent(&chanp->fi, EV_ACCEPTB, NULL);
- break;
- case (ISDN_CMD_ACCEPTD):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1)
- command_debug(chanp, "ACCEPTD");
- FsmEvent(&chanp->fi, EV_ACCEPTD, NULL);
- break;
- case (ISDN_CMD_HANGUP):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1)
- command_debug(chanp, "HANGUP");
- FsmEvent(&chanp->fi, EV_HANGUP, NULL);
- break;
- case (ISDN_CMD_SUSPEND):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1) {
- sprintf(tmp, "SUSPEND %s", ic->parm.num);
- command_debug(chanp, tmp);
- }
- FsmEvent(&chanp->fi, EV_SUSPEND, ic);
- break;
- case (ISDN_CMD_RESUME):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1) {
- sprintf(tmp, "RESUME %s", ic->parm.num);
- command_debug(chanp, tmp);
- }
- FsmEvent(&chanp->fi, EV_RESUME, ic);
- break;
- case (ISDN_CMD_LOCK):
- teles_mod_inc_use_count();
- break;
- case (ISDN_CMD_UNLOCK):
- teles_mod_dec_use_count();
- break;
- case (ISDN_CMD_IOCTL):
- switch (ic->arg) {
- case (0):
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp)
- teles_reportcard(i);
- for (i = 0; i < chancount; i++)
- channel_report(i);
- break;
- case (1):
- debugflags = *(unsigned int *) ic->parm.num;
- distr_debug();
- sprintf(tmp, "debugging flags set to %x\n", debugflags);
- teles_putstatus(tmp);
- printk(KERN_DEBUG "%s", tmp);
- break;
- case (2):
- num = *(unsigned int *) ic->parm.num;
- i = num >> 8;
- if (i >= chancount)
- break;
- chanp = chanlist + i;
- chanp->impair = num & 0xff;
- if (chanp->debug & 1) {
- sprintf(tmp, "IMPAIR %x", chanp->impair);
- command_debug(chanp, tmp);
- }
- break;
- }
- break;
- case (ISDN_CMD_SETL2):
- chanp = chanlist + (ic->arg & 0xff);
- if (chanp->debug & 1) {
- sprintf(tmp, "SETL2 %ld", ic->arg >> 8);
- command_debug(chanp, tmp);
- }
- chanp->l2_protocol = ic->arg >> 8;
- break;
- default:
- break;
- }
-
- return (0);
-}
-
-int
-teles_writebuf(int id, int chan, const u_char * buf, int count, int user)
-{
- struct Channel *chanp = chanlist + chan;
- struct PStack *st = &chanp->ds;
- struct BufHeader *ibh;
- int err, i;
- byte *ptr;
-
- if (!chanp->data_open) {
- printk(KERN_DEBUG "teles_writebuf: channel not open\n");
- return -EIO;
- }
-
- err = BufPoolGet(&ibh, st->l1.sbufpool, GFP_ATOMIC, st, 21);
- if (err)
- /* Must return 0 here, since this is not an error
- * but a temporary lack of resources.
- */
- return 0;
-
- ptr = DATAPTR(ibh);
- if (chanp->lc_b.l2_establish)
- i = st->l2.ihsize;
- else
- i = 0;
-
- if ((count+i) > BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS)) {
- printk(KERN_WARNING "teles_writebuf: packet too large!\n");
- return (-EINVAL);
- }
-
- ptr += i;
-
- if (user)
- copy_from_user(ptr, buf, count);
- else
- memcpy(ptr, buf, count);
- ibh->datasize = count + i;
-
- if (chanp->data_open) {
- if (chanp->lc_b.l2_establish)
- chanp->ds.l3.l3l2(&chanp->ds, DL_DATA, ibh);
- else
- chanp->ds.l2.l2l1(&chanp->ds, PH_DATA, ibh);
- return (count);
- } else {
- BufPoolRelease(ibh);
- return (0);
- }
-
-}
diff --git a/drivers/isdn/teles/card.c b/drivers/isdn/teles/card.c
deleted file mode 100644
index 2ada8a29d..000000000
--- a/drivers/isdn/teles/card.c
+++ /dev/null
@@ -1,1900 +0,0 @@
-/* $Id: card.c,v 1.16 1996/10/22 23:14:16 fritz Exp $
- *
- * card.c low level stuff for the Teles S0 isdn card
- *
- * Author Jan den Ouden
- *
- * Beat Doebeli log all D channel traffic
- *
- * $Log: card.c,v $
- * Revision 1.16 1996/10/22 23:14:16 fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.15 1996/09/29 19:41:56 fritz
- * Bugfix: ignore unknown frames.
- *
- * Revision 1.14 1996/09/23 01:53:49 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.13 1996/07/18 11:21:24 jdenoud
- * Use small buffers for incoming audio data
- *
- * Revision 1.12 1996/06/24 17:16:52 fritz
- * Added check for misconfigured membase.
- *
- * Revision 1.11 1996/06/14 03:30:37 fritz
- * Added recovery from EXIR 40 interrupt.
- * Some cleanup.
- *
- * Revision 1.10 1996/06/11 14:57:20 hipp
- * minor changes to ensure, that SKBs are sent in the right order
- *
- * Revision 1.9 1996/06/06 14:42:09 fritz
- * Bugfix: forgot hsp-> in last change.
- *
- * Revision 1.7 1996/05/31 01:02:21 fritz
- * Cosmetic changes.
- *
- * Revision 1.6 1996/05/26 14:58:10 fritz
- * Bugfix: Did not show port correctly, when no card found.
- *
- * Revision 1.5 1996/05/17 03:45:02 fritz
- * Made error messages more clearly.
- * Bugfix: Only 31 bytes of 32-byte audio frames
- * have been transfered to upper layers.
- *
- * Revision 1.4 1996/05/06 10:17:57 fritz
- * Added voice-send stuff
- * (Not reporting EXIR when in voice-mode, since it's normal).
- *
- * Revision 1.3 1996/04/30 22:02:40 isdn4dev
- * Bugfixes for 16.3
- * -improved IO allocation
- * -fix second B channel problem
- * -correct ph_command patch
- *
- * Revision 1.2 1996/04/30 10:00:59 fritz
- * Bugfix: Added ph_command(8) for 16.3.
- * Bugfix: Ports did not get registered correctly
- * when using a 16.3.
- * Started voice support.
- * Some experimental changes of waitforXFW().
- *
- * Revision 1.1 1996/04/13 10:22:42 fritz
- * Initial revision
- *
- *
- */
-
-#define __NO_VERSION__
-#include "teles.h"
-#include "proto.h"
-
-#define INCLUDE_INLINE_FUNCS
-#include <linux/tqueue.h>
-#include <linux/interrupt.h>
-
-#undef DCHAN_VERBOSE
-
-extern void tei_handler(struct PStack *st, byte pr,
- struct BufHeader *ibh);
-extern struct IsdnCard cards[];
-extern int nrcards;
-
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
-
-static inline byte
-readisac_0(byte * cardm, byte offset)
-{
- return readb(cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
-}
-
-static inline byte
-readisac_3(int iobase, byte offset)
-{
- return (bytein(iobase - 0x420 + offset));
-}
-
-#define READISAC(mbase,ibase,ofs) \
- ((mbase)?readisac_0(mbase,ofs):readisac_3(ibase,ofs))
-
-static inline void
-writeisac_0(byte * cardm, byte offset, byte value)
-{
- writeb(value, cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
-}
-
-static inline void
-writeisac_3(int iobase, byte offset, byte value)
-{
- byteout(iobase - 0x420 + offset, value);
-}
-
-#define WRITEISAC(mbase,ibase,ofs,val) \
- ((mbase)?writeisac_0(mbase,ofs,val):writeisac_3(ibase,ofs,val))
-
-static inline void
-readisac_s(int iobase, byte offset, byte * dest, int count)
-{
- insb(iobase - 0x420 + offset, dest, count);
-}
-
-static inline void
-writeisac_s(int iobase, byte offset, byte * src, int count)
-{
- outsb(iobase - 0x420 + offset, src, count);
-}
-
-static inline byte
-readhscx_0(byte * base, byte hscx, byte offset)
-{
- return readb(base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
- ((hscx & 1) ? 0x40 : 0) + offset);
-}
-
-static inline byte
-readhscx_3(int iobase, byte hscx, byte offset)
-{
- return (bytein(iobase - (hscx ? 0x820 : 0xc20) + offset));
-}
-
-#define READHSCX(mbase,ibase,hscx,ofs) \
- ((mbase)?readhscx_0(mbase,hscx,ofs):readhscx_3(ibase,hscx,ofs))
-
-static inline void
-writehscx_0(byte * base, byte hscx, byte offset, byte data)
-{
- writeb(data, base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
- ((hscx & 1) ? 0x40 : 0) + offset);
-}
-
-static inline void
-writehscx_3(int iobase, byte hscx, byte offset, byte data)
-{
- byteout(iobase - (hscx ? 0x820 : 0xc20) + offset, data);
-}
-
-static inline void
-readhscx_s(int iobase, byte hscx, byte offset, byte * dest, int count)
-{
- insb(iobase - (hscx ? 0x820 : 0xc20) + offset, dest, count);
-}
-
-static inline void
-writehscx_s(int iobase, byte hscx, byte offset, byte * src, int count)
-{
- outsb(iobase - (hscx ? 0x820 : 0xc20) + offset, src, count);
-}
-
-#define ISAC_MASK 0x20
-#define ISAC_ISTA 0x20
-#define ISAC_STAR 0x21
-#define ISAC_CMDR 0x21
-#define ISAC_EXIR 0x24
-
-#define ISAC_RBCH 0x2a
-
-#define ISAC_ADF2 0x39
-#define ISAC_SPCR 0x30
-#define ISAC_ADF1 0x38
-#define ISAC_CIX0 0x31
-#define ISAC_STCR 0x37
-#define ISAC_MODE 0x22
-#define ISAC_RSTA 0x27
-#define ISAC_RBCL 0x25
-#define ISAC_TIMR 0x23
-#define ISAC_SQXR 0x3b
-
-#define HSCX_ISTA 0x20
-#define HSCX_CCR1 0x2f
-#define HSCX_CCR2 0x2c
-#define HSCX_TSAR 0x31
-#define HSCX_TSAX 0x30
-#define HSCX_XCCR 0x32
-#define HSCX_RCCR 0x33
-#define HSCX_MODE 0x22
-#define HSCX_CMDR 0x21
-#define HSCX_EXIR 0x24
-#define HSCX_XAD1 0x24
-#define HSCX_XAD2 0x25
-#define HSCX_RAH2 0x27
-#define HSCX_RSTA 0x27
-#define HSCX_TIMR 0x23
-#define HSCX_STAR 0x21
-#define HSCX_RBCL 0x25
-#define HSCX_XBCH 0x2d
-#define HSCX_VSTR 0x2e
-#define HSCX_RLCR 0x2e
-#define HSCX_MASK 0x20
-
-static inline void
-waitforCEC_0(byte * base, byte hscx)
-{
- long to = 10;
-
- while ((readhscx_0(base, hscx, HSCX_STAR) & 0x04) && to) {
- udelay(5);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "waitforCEC timeout\n");
-}
-
-static inline void
-waitforCEC_3(int iobase, byte hscx)
-{
- long to = 10;
-
- while ((readhscx_3(iobase, hscx, HSCX_STAR) & 0x04) && to) {
- udelay(5);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "waitforCEC timeout\n");
-}
-
-static inline void
-waitforXFW_0(byte * base, byte hscx)
-{
- long to = 20;
-
- while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
- udelay(5);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "waitforXFW timeout\n");
-}
-
-static inline void
-waitforXFW_3(int iobase, byte hscx)
-{
- long to = 20;
-
- while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
- udelay(5);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "waitforXFW timeout\n");
-}
-
-static inline void
-writehscxCMDR_0(byte * base, byte hscx, byte data)
-{
- long flags;
-
- save_flags(flags);
- cli();
- waitforCEC_0(base, hscx);
- writehscx_0(base, hscx, HSCX_CMDR, data);
- restore_flags(flags);
-}
-
-static inline void
-writehscxCMDR_3(int iobase, byte hscx, byte data)
-{
- long flags;
-
- save_flags(flags);
- cli();
- waitforCEC_3(iobase, hscx);
- writehscx_3(iobase, hscx, HSCX_CMDR, data);
- restore_flags(flags);
-}
-
-#define WRITEHSCX_CMDR(mbase,ibase,hscx,data) \
- ((mbase)?writehscxCMDR_0(mbase,hscx,data):writehscxCMDR_3(ibase,hscx,data))
-
-/*
- * fast interrupt here
- */
-
-#define ISAC_RCVBUFREADY 0
-#define ISAC_XMTBUFREADY 1
-#define ISAC_PHCHANGE 2
-
-#define HSCX_RCVBUFREADY 0
-#define HSCX_XMTBUFREADY 1
-
-void
-teles_hscxreport(struct IsdnCardState *sp, int hscx)
-{
- printk(KERN_DEBUG "HSCX %d\n", hscx);
- if (sp->membase) {
- printk(KERN_DEBUG " ISTA %x\n", readhscx_0(sp->membase,
- hscx, HSCX_ISTA));
- printk(KERN_DEBUG " STAR %x\n", readhscx_0(sp->membase,
- hscx, HSCX_STAR));
- printk(KERN_DEBUG " EXIR %x\n", readhscx_0(sp->membase,
- hscx, HSCX_EXIR));
- } else {
- printk(KERN_DEBUG " ISTA %x\n", readhscx_3(sp->iobase,
- hscx, HSCX_ISTA));
- printk(KERN_DEBUG " STAR %x\n", readhscx_3(sp->iobase,
- hscx, HSCX_STAR));
- printk(KERN_DEBUG " EXIR %x\n", readhscx_3(sp->iobase,
- hscx, HSCX_EXIR));
- }
-}
-
-void
-teles_report(struct IsdnCardState *sp)
-{
- printk(KERN_DEBUG "ISAC\n");
- if (sp->membase) {
- printk(KERN_DEBUG " ISTA %x\n", readisac_0(sp->membase,
- ISAC_ISTA));
- printk(KERN_DEBUG " STAR %x\n", readisac_0(sp->membase,
- ISAC_STAR));
- printk(KERN_DEBUG " EXIR %x\n", readisac_0(sp->membase,
- ISAC_EXIR));
- } else {
- printk(KERN_DEBUG " ISTA %x\n", readisac_3(sp->iobase,
- ISAC_ISTA));
- printk(KERN_DEBUG " STAR %x\n", readisac_3(sp->iobase,
- ISAC_STAR));
- printk(KERN_DEBUG " EXIR %x\n", readisac_3(sp->iobase,
- ISAC_EXIR));
- }
- teles_hscxreport(sp, 0);
- teles_hscxreport(sp, 1);
-}
-
-/*
- * HSCX stuff goes here
- */
-
-static void
-hscx_sched_event(struct HscxState *hsp, int event)
-{
- hsp->event |= 1 << event;
- queue_task_irq_off(&hsp->tqueue, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-}
-
-static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
-{
- byte *ptr;
- struct BufHeader *ibh = hsp->rcvibh;
-
- if (hsp->sp->debug)
- printk(KERN_DEBUG "hscx_empty_fifo\n");
-
- if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER,
- HSCX_RBUF_BPPS)) {
- printk(KERN_WARNING
- "hscx_empty_fifo: incoming packet too large\n");
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx, 0x80);
- return;
- }
- ptr = DATAPTR(ibh);
- ptr += hsp->rcvptr;
-
- hsp->rcvptr += count;
- if (hsp->membase) {
- while (count--)
- *ptr++ = readhscx_0(hsp->membase, hsp->hscx, 0x0);
- writehscxCMDR_0(hsp->membase, hsp->hscx, 0x80);
- } else {
- readhscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count);
- writehscxCMDR_3(hsp->iobase, hsp->hscx, 0x80);
- }
-}
-
-static void
-hscx_fill_fifo(struct HscxState *hsp)
-{
- struct BufHeader *ibh;
- int more, count;
- byte *ptr;
-
- if (hsp->sp->debug)
- printk(KERN_DEBUG "hscx_fill_fifo\n");
-
- ibh = hsp->xmtibh;
- if (!ibh)
- return;
-
- count = ibh->datasize - hsp->sendptr;
- if (count <= 0)
- return;
-
- more = (hsp->mode == 1)?1:0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- ptr = DATAPTR(ibh);
- ptr += hsp->sendptr;
- hsp->sendptr += count;
-
-#ifdef BCHAN_VERBOSE
- {
- int i;
- printk(KERN_DEBUG "hscx_fill_fifo ");
- for (i = 0; i < count; i++)
- printk(" %2x", ptr[i]);
- printk("\n");
- }
-#endif
- if (hsp->membase) {
- waitforXFW_0(hsp->membase, hsp->hscx);
- while (count--)
- writehscx_0(hsp->membase, hsp->hscx, 0x0, *ptr++);
- writehscxCMDR_0(hsp->membase, hsp->hscx, more ? 0x8 : 0xa);
- } else {
- waitforXFW_3(hsp->iobase, hsp->hscx);
- writehscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count);
- writehscxCMDR_3(hsp->iobase, hsp->hscx, more ? 0x8 : 0xa);
- }
-}
-
-static inline void
-hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
-{
- byte r;
- struct HscxState *hsp = sp->hs + hscx;
- int count, err;
-
- if (!hsp->init)
- return;
-
- if (val & 0x80) { /* RME */
-
- r = READHSCX(hsp->membase, sp->iobase, hsp->hscx, HSCX_RSTA);
- if ((r & 0xf0) != 0xa0) {
- if (!r & 0x80)
- printk(KERN_WARNING
- "Teles: HSCX invalid frame\n");
- if ((r & 0x40) && hsp->mode)
- printk(KERN_WARNING "Teles: HSCX RDO mode=%d\n",hsp->mode);
- if (!r & 0x20)
- printk(KERN_WARNING "Teles: HSCX CRC error\n");
- if (hsp->rcvibh)
- BufPoolRelease(hsp->rcvibh);
- hsp->rcvibh = NULL;
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx,
- 0x80);
- goto afterRME;
- }
- if (!hsp->rcvibh)
- if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
- GFP_ATOMIC, (void *) 1, 1)) {
- printk(KERN_WARNING
- "HSCX RME out of buffers at %ld\n",
- jiffies);
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
- hsp->hscx, 0x80);
- goto afterRME;
- } else
- hsp->rcvptr = 0;
-
- count = READHSCX(hsp->membase, sp->iobase, hsp->hscx,
- HSCX_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- hscx_empty_fifo(hsp, count);
- hsp->rcvibh->datasize = hsp->rcvptr - 1;
- BufQueueLink(&hsp->rq, hsp->rcvibh);
- hsp->rcvibh = NULL;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- afterRME:
- if (val & 0x40) { /* RPF */
- if (!hsp->rcvibh) {
- if (hsp->mode == 1)
- err=BufPoolGet(&hsp->rcvibh, &hsp->smallpool,
- GFP_ATOMIC, (void *)1, 2);
- else
- err=BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
- GFP_ATOMIC, (void *)1, 2);
-
- if (err) {
- printk(KERN_WARNING
- "HSCX RPF out of buffers at %ld\n",
- jiffies);
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
- hsp->hscx, 0x80);
- goto afterRPF;
- } else
- hsp->rcvptr = 0;
- }
-
- hscx_empty_fifo(hsp, 32);
- if (hsp->mode == 1) {
- /* receive audio data */
- hsp->rcvibh->datasize = hsp->rcvptr;
- BufQueueLink(&hsp->rq, hsp->rcvibh);
- hsp->rcvibh = NULL;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
-
- }
- afterRPF:
- if (val & 0x10) { /* XPR */
- if (hsp->xmtibh)
- if (hsp->xmtibh->datasize > hsp->sendptr) {
- hscx_fill_fifo(hsp);
- goto afterXPR;
- } else {
- if (hsp->releasebuf)
- BufPoolRelease(hsp->xmtibh);
- hsp->sendptr = 0;
- if (hsp->st->l4.l1writewakeup)
- hsp->st->l4.l1writewakeup(hsp->st);
- hsp->xmtibh = NULL;
- }
- if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) {
- hsp->releasebuf = !0;
- hscx_fill_fifo(hsp);
- } else
- hscx_sched_event(hsp, HSCX_XMTBUFREADY);
- }
- afterXPR:
-}
-
-/*
- * ISAC stuff goes here
- */
-
-static void
-isac_sched_event(struct IsdnCardState *sp, int event)
-{
- sp->event |= 1 << event;
- queue_task_irq_off(&sp->tqueue, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-}
-
-static void
-empty_fifo(struct IsdnCardState *sp, int count)
-{
- byte *ptr;
- struct BufHeader *ibh = sp->rcvibh;
-
- if (sp->debug)
- printk(KERN_DEBUG "empty_fifo\n");
-
- if (sp->rcvptr >= 3072) {
- printk(KERN_WARNING "empty_fifo rcvptr %d\n", sp->rcvptr);
- return;
- }
- ptr = DATAPTR(ibh);
- ptr += sp->rcvptr;
- sp->rcvptr += count;
-
- if (sp->membase) {
-#ifdef DCHAN_VERBOSE
- printk(KERN_DEBUG "empty_fifo ");
- while (count--) {
- *ptr = readisac_0(sp->membase, 0x0);
- printk("%2x ", *ptr);
- ptr++;
- }
- printk("\n");
-#else
- while (count--)
- *ptr++ = readisac_0(sp->membase, 0x0);
-#endif
- writeisac_0(sp->membase, ISAC_CMDR, 0x80);
- } else {
-#ifdef DCHAN_VERBOSE
- int i;
- printk(KERN_DEBUG "empty_fifo ");
- readisac_s(sp->iobase, 0x3e, ptr, count);
- for (i = 0; i < count; i++)
- printk("%2x ", ptr[i]);
- printk("\n");
-#else
- readisac_s(sp->iobase, 0x3e, ptr, count);
-#endif
- writeisac_3(sp->iobase, ISAC_CMDR, 0x80);
- }
-}
-
-static void
-fill_fifo(struct IsdnCardState *sp)
-{
- struct BufHeader *ibh;
- int count, more;
- byte *ptr;
-
- if (sp->debug)
- printk(KERN_DEBUG "fill_fifo\n");
-
- ibh = sp->xmtibh;
- if (!ibh)
- return;
-
- count = ibh->datasize - sp->sendptr;
- if (count <= 0)
- return;
- if (count >= 3072)
- return;
-
- more = 0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- ptr = DATAPTR(ibh);
- ptr += sp->sendptr;
- sp->sendptr += count;
-
- if (sp->membase) {
-#ifdef DCHAN_VERBOSE
- printk(KERN_DEBUG "fill_fifo ");
- while (count--) {
- writeisac_0(sp->membase, 0x0, *ptr);
- printk("%2x ", *ptr);
- ptr++;
- }
- printk("\n");
-#else
- while (count--)
- writeisac_0(sp->membase, 0x0, *ptr++);
-#endif
- writeisac_0(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa);
- } else {
-#ifdef DCHAN_VERBOSE
- int i;
- writeisac_s(sp->iobase, 0x3e, ptr, count);
- printk(KERN_DEBUG "fill_fifo ");
- for (i = 0; i < count; i++)
- printk("%2x ", ptr[i]);
- printk("\n");
-#else
- writeisac_s(sp->iobase, 0x3e, ptr, count);
-#endif
- writeisac_3(sp->iobase, ISAC_CMDR, more ? 0x8 : 0xa);
- }
-}
-
-static int
-act_wanted(struct IsdnCardState *sp)
-{
- struct PStack *st;
-
- st = sp->stlist;
- while (st)
- if (st->l1.act_state)
- return (!0);
- else
- st = st->next;
- return (0);
-}
-
-static void
-ph_command(struct IsdnCardState *sp, unsigned int command)
-{
- printk(KERN_DEBUG "ph_command %d\n", command);
- WRITEISAC(sp->membase, sp->iobase, ISAC_CIX0, (command << 2) | 3);
-}
-
-static void
-isac_new_ph(struct IsdnCardState *sp)
-{
- int enq;
-
- enq = act_wanted(sp);
-
- switch (sp->ph_state) {
- case (0):
- case (6):
- if (enq)
- ph_command(sp, 0);
- else
- ph_command(sp, 15);
- break;
- case (7):
- if (enq)
- ph_command(sp, 9);
- break;
- case (12):
- ph_command(sp, 8);
- sp->ph_active = 5;
- isac_sched_event(sp, ISAC_PHCHANGE);
- if (!sp->xmtibh)
- if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
- sp->sendptr = 0;
- if (sp->xmtibh)
- fill_fifo(sp);
- break;
- case (13):
- ph_command(sp, 9);
- sp->ph_active = 5;
- isac_sched_event(sp, ISAC_PHCHANGE);
- if (!sp->xmtibh)
- if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
- sp->sendptr = 0;
- if (sp->xmtibh)
- fill_fifo(sp);
- break;
- case (4):
- case (8):
- break;
- default:
- sp->ph_active = 0;
- break;
- }
-}
-
-static void
-teles_interrupt(int intno, void *dev_id, struct pt_regs *regs)
-{
- byte val, r, exval;
- struct IsdnCardState *sp;
- unsigned int count;
- struct HscxState *hsp;
-
- sp = (struct IsdnCardState *) irq2dev_map[intno];
-
- if (!sp) {
- printk(KERN_WARNING "Teles: Spurious interrupt!\n");
- return;
- }
- val = READHSCX(sp->membase, sp->iobase, 1, HSCX_ISTA);
-
- if (val & 0x01) {
- hsp = sp->hs + 1;
- exval = READHSCX(sp->membase, sp->iobase, 1, HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- hsp->sendptr = 0;
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
- hsp->hscx, 0x01);
- printk(KERN_DEBUG "HSCX B EXIR %x\n", exval);
- }
- } else
- printk(KERN_WARNING "HSCX B EXIR %x\n", exval);
- }
- if (val & 0xf8) {
- if (sp->debug)
- printk(KERN_DEBUG "HSCX B interrupt %x\n", val);
- hscx_interrupt(sp, val, 1);
- }
- if (val & 0x02) {
- hsp = sp->hs;
- exval = READHSCX(sp->membase, sp->iobase, 0, HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- hsp->sendptr = 0;
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
- hsp->hscx, 0x01);
- printk(KERN_DEBUG "HSCX A EXIR %x\n", exval);
- }
- } else
- printk(KERN_WARNING "HSCX A EXIR %x\n", exval);
- }
- if (val & 0x04) {
- val = READHSCX(sp->membase, sp->iobase, 0, HSCX_ISTA);
- if (sp->debug)
- printk(KERN_DEBUG "HSCX A interrupt %x\n",
- val);
- hscx_interrupt(sp, val, 0);
- }
-
- val = READISAC(sp->membase, sp->iobase, ISAC_ISTA);
-
- if (sp->debug)
- printk(KERN_DEBUG "ISAC interrupt %x\n", val);
-
- if (val & 0x80) { /* RME */
-
- r = READISAC(sp->membase, sp->iobase, ISAC_RSTA);
- if ((r & 0x70) != 0x20) {
- if (r & 0x40)
- printk(KERN_WARNING "Teles: ISAC RDO\n");
- if (!r & 0x20)
- printk(KERN_WARNING "Teles: ISAC CRC error\n");
- if (sp->rcvibh)
- BufPoolRelease(sp->rcvibh);
- sp->rcvibh = NULL;
- WRITEISAC(sp->membase, sp->iobase, ISAC_CMDR, 0x80);
- goto afterRME;
- }
- if (!sp->rcvibh)
- if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
- GFP_ATOMIC,
- (void *) 1, 3)) {
- printk(KERN_WARNING
- "ISAC RME out of buffers!\n");
- WRITEISAC(sp->membase, sp->iobase,
- ISAC_CMDR, 0x80);
- goto afterRME;
- } else
- sp->rcvptr = 0;
-
- count = READISAC(sp->membase, sp->iobase, ISAC_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- empty_fifo(sp, count);
- sp->rcvibh->datasize = sp->rcvptr;
- BufQueueLink(&(sp->rq), sp->rcvibh);
- sp->rcvibh = NULL;
- isac_sched_event(sp, ISAC_RCVBUFREADY);
- }
- afterRME:
- if (val & 0x40) { /* RPF */
- if (!sp->rcvibh)
- if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
- GFP_ATOMIC,
- (void *) 1, 4)) {
- printk(KERN_WARNING
- "ISAC RME out of buffers!\n");
- WRITEISAC(sp->membase, sp->iobase,
- ISAC_CMDR, 0x80);
- goto afterRPF;
- } else
- sp->rcvptr = 0;
- empty_fifo(sp, 32);
- }
- afterRPF:
- if (val & 0x20) {
- }
- if (val & 0x10) { /* XPR */
- if (sp->xmtibh)
- if (sp->xmtibh->datasize > sp->sendptr) {
- fill_fifo(sp);
- goto afterXPR;
- } else {
- if (sp->releasebuf)
- BufPoolRelease(sp->xmtibh);
- sp->xmtibh = NULL;
- sp->sendptr = 0;
- }
- if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) {
- sp->releasebuf = !0;
- fill_fifo(sp);
- } else
- isac_sched_event(sp, ISAC_XMTBUFREADY);
- }
- afterXPR:
- if (val & 0x04) { /* CISQ */
- sp->ph_state = (READISAC(sp->membase, sp->iobase, ISAC_CIX0)
- >> 2) & 0xf;
- printk(KERN_DEBUG "l1state %d\n", sp->ph_state);
- isac_new_ph(sp);
- }
- if (sp->membase) {
- writeisac_0(sp->membase, ISAC_MASK, 0xFF);
- writehscx_0(sp->membase, 0, HSCX_MASK, 0xFF);
- writehscx_0(sp->membase, 1, HSCX_MASK, 0xFF);
- writeisac_0(sp->membase, ISAC_MASK, 0x0);
- writehscx_0(sp->membase, 0, HSCX_MASK, 0x0);
- writehscx_0(sp->membase, 1, HSCX_MASK, 0x0);
- } else {
- writeisac_3(sp->iobase, ISAC_MASK, 0xFF);
- writehscx_3(sp->iobase, 0, HSCX_MASK, 0xFF);
- writehscx_3(sp->iobase, 1, HSCX_MASK, 0xFF);
- writeisac_3(sp->iobase, ISAC_MASK, 0x0);
- writehscx_3(sp->iobase, 0, HSCX_MASK, 0x0);
- writehscx_3(sp->iobase, 1, HSCX_MASK, 0x0);
- }
-}
-
-/*
- * soft interrupt
- */
-
-static void
-act_ivated(struct IsdnCardState *sp)
-{
- struct PStack *st;
-
- st = sp->stlist;
- while (st) {
- if (st->l1.act_state == 1) {
- st->l1.act_state = 2;
- st->l1.l1man(st, PH_ACTIVATE, NULL);
- }
- st = st->next;
- }
-}
-
-static void
-process_new_ph(struct IsdnCardState *sp)
-{
- if (sp->ph_active == 5)
- act_ivated(sp);
-}
-
-static void
-process_xmt(struct IsdnCardState *sp)
-{
- struct PStack *stptr;
-
- if (sp->xmtibh)
- return;
-
- stptr = sp->stlist;
- while (stptr != NULL)
- if (stptr->l1.requestpull) {
- stptr->l1.requestpull = 0;
- stptr->l1.l1l2(stptr, PH_PULL_ACK, NULL);
- break;
- } else
- stptr = stptr->next;
-}
-
-static void
-process_rcv(struct IsdnCardState *sp)
-{
- struct BufHeader *ibh, *cibh;
- struct PStack *stptr;
- byte *ptr;
- int found, broadc;
- char tmp[64];
-
- while (!BufQueueUnlink(&ibh, &sp->rq)) {
- stptr = sp->stlist;
- ptr = DATAPTR(ibh);
- broadc = (ptr[1] >> 1) == 127;
-
- if (broadc && sp->dlogflag && (!(ptr[0] >> 2)))
- dlogframe(sp, ptr + 3, ibh->datasize - 3,
- "Q.931 frame network->user broadcast");
-
- if (broadc) {
- while (stptr != NULL) {
- if ((ptr[0] >> 2) == stptr->l2.sap)
- if (!BufPoolGet(&cibh, &sp->rbufpool, GFP_ATOMIC,
- (void *) 1, 5)) {
- memcpy(DATAPTR(cibh), DATAPTR(ibh), ibh->datasize);
- cibh->datasize = ibh->datasize;
- stptr->l1.l1l2(stptr, PH_DATA, cibh);
- } else
- printk(KERN_WARNING "isdn broadcast buffer shortage\n");
- stptr = stptr->next;
- }
- BufPoolRelease(ibh);
- } else {
- found = 0;
- while (stptr != NULL)
- if (((ptr[0] >> 2) == stptr->l2.sap) &&
- ((ptr[1] >> 1) == stptr->l2.tei)) {
- stptr->l1.l1l2(stptr, PH_DATA, ibh);
- found = !0;
- break;
- } else
- stptr = stptr->next;
- if (!found) {
- /* BD 10.10.95
- * Print out D-Channel msg not processed
- * by isdn4linux
- */
-
- if ((!(ptr[0] >> 2)) && (!(ptr[2] & 0x01))) {
- sprintf(tmp, "Q.931 frame network->user with tei %d (not for us)", ptr[1] >> 1);
- dlogframe(sp, ptr + 4, ibh->datasize - 4, tmp);
- }
- BufPoolRelease(ibh);
- }
- }
-
- }
-
-}
-
-static void
-isac_bh(struct IsdnCardState *sp)
-{
- if (!sp)
- return;
-
- if (clear_bit(ISAC_PHCHANGE, &sp->event))
- process_new_ph(sp);
- if (clear_bit(ISAC_RCVBUFREADY, &sp->event))
- process_rcv(sp);
- if (clear_bit(ISAC_XMTBUFREADY, &sp->event))
- process_xmt(sp);
-}
-
-
-static void
-hscx_process_xmt(struct HscxState *hsp)
-{
- struct PStack *st = hsp->st;
-
- if (hsp->xmtibh)
- return;
-
- if (st->l1.requestpull) {
- st->l1.requestpull = 0;
- st->l1.l1l2(st, PH_PULL_ACK, NULL);
- }
- if (!hsp->active)
- if ((!hsp->xmtibh) && (!hsp->sq.head))
- modehscx(hsp, 0, 0);
-}
-
-static void
-hscx_process_rcv(struct HscxState *hsp)
-{
- struct BufHeader *ibh;
-
-#ifdef DEBUG_MAGIC
- if (hsp->magic != 301270) {
- printk(KERN_DEBUG "hscx_process_rcv magic not 301270\n");
- return;
- }
-#endif
- while (!BufQueueUnlink(&ibh, &hsp->rq)) {
- hsp->st->l1.l1l2(hsp->st, PH_DATA, ibh);
- }
-}
-
-static void
-hscx_bh(struct HscxState *hsp)
-{
-
- if (!hsp)
- return;
-
- if (clear_bit(HSCX_RCVBUFREADY, &hsp->event))
- hscx_process_rcv(hsp);
- if (clear_bit(HSCX_XMTBUFREADY, &hsp->event))
- hscx_process_xmt(hsp);
-
-}
-
-/*
- * interrupt stuff ends here
- */
-
-static void
-restart_ph(struct IsdnCardState *sp)
-{
- switch (sp->ph_active) {
- case (0):
- if (sp->ph_state == 6)
- ph_command(sp, 0);
- else
- ph_command(sp, 1);
- sp->ph_active = 1;
- break;
- }
-}
-
-static void
-initisac(byte * cardmem, int iobase)
-{
- if (cardmem) {
- writeisac_0(cardmem, ISAC_MASK, 0xff);
- writeisac_0(cardmem, ISAC_ADF2, 0x0);
- writeisac_0(cardmem, ISAC_SPCR, 0xa);
- writeisac_0(cardmem, ISAC_ADF1, 0x2);
- writeisac_0(cardmem, ISAC_STCR, 0x70);
- writeisac_0(cardmem, ISAC_MODE, 0xc9);
- writeisac_0(cardmem, ISAC_CMDR, 0x41);
- writeisac_0(cardmem, ISAC_CIX0, (1 << 2) | 3);
- } else {
- writeisac_3(iobase, ISAC_MASK, 0xff);
- writeisac_3(iobase, ISAC_ADF2, 0x80);
- writeisac_3(iobase, ISAC_SQXR, 0x2f);
- writeisac_3(iobase, ISAC_SPCR, 0x00);
- writeisac_3(iobase, ISAC_ADF1, 0x02);
- writeisac_3(iobase, ISAC_STCR, 0x70);
- writeisac_3(iobase, ISAC_MODE, 0xc9);
- writeisac_3(iobase, ISAC_TIMR, 0x00);
- writeisac_3(iobase, ISAC_ADF1, 0x00);
- writeisac_3(iobase, ISAC_CMDR, 0x41);
- writeisac_3(iobase, ISAC_CIX0, (1 << 2) | 3);
- }
-}
-
-static int
-checkcard(int cardnr)
-{
- int timout;
- byte cfval, val;
- struct IsdnCard *card = cards + cardnr;
-
- if (card->membase)
- if ((unsigned long)card->membase < 0x10000) {
- (unsigned long)card->membase <<= 4;
- printk(KERN_INFO
- "Teles membase configured DOSish, assuming 0x%lx\n",
- (unsigned long)card->membase);
- }
- if (!card->iobase) {
- if (card->membase) {
- printk(KERN_NOTICE
- "Teles 8 assumed, mem: %lx irq: %d proto: %s\n",
- (long) card->membase, card->interrupt,
- (card->protocol == ISDN_PTYPE_1TR6) ?
- "1TR6" : "EDSS1");
- printk(KERN_INFO "HSCX version A:%x B:%x\n",
- readhscx_0(card->membase, 0, HSCX_VSTR) & 0xf,
- readhscx_0(card->membase, 1, HSCX_VSTR) & 0xf);
- }
- } else {
- switch (card->iobase) {
- case 0x180:
- case 0x280:
- case 0x380:
- card->iobase |= 0xc00;
- break;
- }
- if (card->membase) { /* 16.0 */
- if (check_region(card->iobase, 8)) {
- printk(KERN_WARNING
- "teles: ports %x-%x already in use\n",
- card->iobase,
- card->iobase + 8 );
- return -1;
- }
- } else { /* 16.3 */
- if (check_region(card->iobase, 16)) {
- printk(KERN_WARNING
- "teles: 16.3 ports %x-%x already in use\n",
- card->iobase,
- card->iobase + 16 );
- return -1;
- }
- if (check_region((card->iobase - 0xc00) , 32)) {
- printk(KERN_WARNING
- "teles: 16.3 ports %x-%x already in use\n",
- card->iobase - 0xc00,
- card->iobase - 0xc00 + 32);
- return -1;
- }
- if (check_region((card->iobase - 0x800) , 32)) {
- printk(KERN_WARNING
- "teles: 16.3 ports %x-%x already in use\n",
- card->iobase - 0x800,
- card->iobase - 0x800 + 32);
- return -1;
- }
- if (check_region((card->iobase - 0x400) , 32)) {
- printk(KERN_WARNING
- "teles: 16.3 ports %x-%x already in use\n",
- card->iobase - 0x400,
- card->iobase - 0x400 + 32);
- return -1;
- }
- }
- switch (card->interrupt) {
- case 2:
- cfval = 0x00;
- break;
- case 3:
- cfval = 0x02;
- break;
- case 4:
- cfval = 0x04;
- break;
- case 5:
- cfval = 0x06;
- break;
- case 10:
- cfval = 0x08;
- break;
- case 11:
- cfval = 0x0A;
- break;
- case 12:
- cfval = 0x0C;
- break;
- case 15:
- cfval = 0x0E;
- break;
- default:
- cfval = 0x00;
- break;
- }
- if (card->membase) {
- cfval |= (((unsigned int) card->membase >> 9) & 0xF0);
- }
- if (bytein(card->iobase + 0) != 0x51) {
- printk(KERN_INFO "XXX Byte at %x is %x\n",
- card->iobase + 0,
- bytein(card->iobase + 0));
- return -2;
- }
- if (bytein(card->iobase + 1) != 0x93) {
- printk(KERN_INFO "XXX Byte at %x is %x\n",
- card->iobase + 1,
- bytein(card->iobase + 1));
- return -2;
- }
- val = bytein(card->iobase + 2); /* 0x1e=without AB
- * 0x1f=with AB
- * 0x1c 16.3 ???
- */
- if (val != 0x1c && val != 0x1e && val != 0x1f) {
- printk(KERN_INFO "XXX Byte at %x is %x\n",
- card->iobase + 2,
- bytein(card->iobase + 2));
- return -2;
- }
- if (card->membase) { /* 16.0 */
- request_region(card->iobase, 8, "teles 16.0");
- } else {
- request_region(card->iobase, 16, "teles 16.3");
- request_region(card->iobase - 0xC00, 32, "teles HSCX0");
- request_region(card->iobase - 0x800, 32, "teles HSCX1");
- request_region(card->iobase - 0x400, 32, "teles ISAC");
- }
- cli();
- timout = jiffies + (HZ / 10) + 1;
- byteout(card->iobase + 4, cfval);
- sti();
- while (jiffies <= timout);
-
- cli();
- timout = jiffies + (HZ / 10) + 1;
- byteout(card->iobase + 4, cfval | 1);
- sti();
- while (jiffies <= timout);
-
- if (card->membase)
- printk(KERN_NOTICE
- "Teles 16.0 found, io: %x mem: %lx irq: %d proto: %s\n",
- card->iobase, (long) card->membase,
- card->interrupt,
- (card->protocol == ISDN_PTYPE_1TR6) ?
- "1TR6" : "EDSS1");
- else
- printk(KERN_NOTICE
- "Teles 16.3 found, io: %x irq: %d proto: %s\n",
- card->iobase, card->interrupt,
- (card->protocol == ISDN_PTYPE_1TR6) ?
- "1TR6" : "EDSS1");
- printk(KERN_INFO "HSCX version A:%x B:%x\n",
- READHSCX(card->membase, card->iobase, 0,
- HSCX_VSTR) & 0xf,
- READHSCX(card->membase, card->iobase, 1,
- HSCX_VSTR) & 0xf);
-
- }
- if (card->membase) {
- cli();
- timout = jiffies + (HZ / 5) + 1;
- writeb(0, card->membase + 0x80);
- sti();
- while (jiffies <= timout);
-
- cli();
- writeb(1, card->membase + 0x80);
- timout = jiffies + (HZ / 5) + 1;
- sti();
- while (jiffies <= timout);
- }
- return (0);
-}
-
-void
-modehscx(struct HscxState *hs, int mode,
- int ichan)
-{
- struct IsdnCardState *sp = hs->sp;
- int hscx = hs->hscx;
-
- printk(KERN_DEBUG "modehscx hscx %d mode %d ichan %d\n",
- hscx, mode, ichan);
-
- hs->mode = mode;
- if (sp->membase) {
- /* What's that ??? KKeil */
- if (hscx == 0)
- ichan = 1 - ichan; /* raar maar waar... */
- writehscx_0(sp->membase, hscx, HSCX_CCR1, 0x85);
- writehscx_0(sp->membase, hscx, HSCX_XAD1, 0xFF);
- writehscx_0(sp->membase, hscx, HSCX_XAD2, 0xFF);
- writehscx_0(sp->membase, hscx, HSCX_RAH2, 0xFF);
- writehscx_0(sp->membase, hscx, HSCX_XBCH, 0x0);
-
- switch (mode) {
- case (0):
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0xff);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0xff);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_MODE, 0x84);
- break;
- case (1):
- if (ichan == 0) {
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x7);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x7);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- } else {
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x3);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x3);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- }
- writehscx_0(sp->membase, hscx, HSCX_MODE, 0xe4);
- writehscx_0(sp->membase, hscx, HSCX_CMDR, 0x41);
- break;
- case (2):
- if (ichan == 0) {
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x7);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x7);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- } else {
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x3);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x3);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- }
- writehscx_0(sp->membase, hscx, HSCX_MODE, 0x8c);
- writehscx_0(sp->membase, hscx, HSCX_CMDR, 0x41);
- break;
- }
- writehscx_0(sp->membase, hscx, HSCX_ISTA, 0x00);
- } else {
- writehscx_3(sp->iobase, hscx, HSCX_CCR1, 0x85);
- writehscx_3(sp->iobase, hscx, HSCX_XAD1, 0xFF);
- writehscx_3(sp->iobase, hscx, HSCX_XAD2, 0xFF);
- writehscx_3(sp->iobase, hscx, HSCX_RAH2, 0xFF);
- writehscx_3(sp->iobase, hscx, HSCX_XBCH, 0x00);
- writehscx_3(sp->iobase, hscx, HSCX_RLCR, 0x00);
-
- switch (mode) {
- case (0):
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0xff);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0xff);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_MODE, 0x84);
- break;
- case (1):
- if (ichan == 0) {
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x2f);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x2f);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- } else {
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x3);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x3);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- }
- writehscx_3(sp->iobase, hscx, HSCX_MODE, 0xe4);
- writehscx_3(sp->iobase, hscx, HSCX_CMDR, 0x41);
- break;
- case (2):
- if (ichan == 0) {
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x2f);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x2f);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- } else {
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x3);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x3);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- }
- writehscx_3(sp->iobase, hscx, HSCX_MODE, 0x8c);
- writehscx_3(sp->iobase, hscx, HSCX_CMDR, 0x41);
- break;
- }
- writehscx_3(sp->iobase, hscx, HSCX_ISTA, 0x00);
- }
-}
-
-void
-teles_addlist(struct IsdnCardState *sp,
- struct PStack *st)
-{
- st->next = sp->stlist;
- sp->stlist = st;
-}
-
-void
-teles_rmlist(struct IsdnCardState *sp,
- struct PStack *st)
-{
- struct PStack *p;
-
- if (sp->stlist == st)
- sp->stlist = st->next;
- else {
- p = sp->stlist;
- while (p)
- if (p->next == st) {
- p->next = st->next;
- return;
- } else
- p = p->next;
- }
-}
-
-
-static void
-teles_l2l1(struct PStack *st, int pr,
- struct BufHeader *ibh)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
-
-
- switch (pr) {
- case (PH_DATA):
- if (sp->xmtibh)
- BufQueueLink(&sp->sq, ibh);
- else {
- sp->xmtibh = ibh;
- sp->sendptr = 0;
- sp->releasebuf = !0;
- fill_fifo(sp);
- }
- break;
- case (PH_DATA_PULLED):
- if (sp->xmtibh) {
- printk(KERN_DEBUG "teles_l2l1: this shouldn't happen\n");
- break;
- }
- sp->xmtibh = ibh;
- sp->sendptr = 0;
- sp->releasebuf = 0;
- fill_fifo(sp);
- break;
- case (PH_REQUEST_PULL):
- if (!sp->xmtibh) {
- st->l1.requestpull = 0;
- st->l1.l1l2(st, PH_PULL_ACK, NULL);
- } else
- st->l1.requestpull = !0;
- break;
- }
-}
-
-static void
-check_ph_act(struct IsdnCardState *sp)
-{
- struct PStack *st = sp->stlist;
-
- while (st) {
- if (st->l1.act_state)
- return;
- st = st->next;
- }
- sp->ph_active = 0;
-}
-
-static void
-teles_manl1(struct PStack *st, int pr,
- void *arg)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
- long flags;
-
- switch (pr) {
- case (PH_ACTIVATE):
- save_flags(flags);
- cli();
- if (sp->ph_active == 5) {
- st->l1.act_state = 2;
- restore_flags(flags);
- st->l1.l1man(st, PH_ACTIVATE, NULL);
- } else {
- st->l1.act_state = 1;
- if (sp->ph_active == 0)
- restart_ph(sp);
- restore_flags(flags);
- }
- break;
- case (PH_DEACTIVATE):
- st->l1.act_state = 0;
- check_ph_act(sp);
- break;
- }
-}
-
-static void
-teles_l2l1discardq(struct PStack *st, int pr,
- void *heldby, int releasetoo)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
-
-#ifdef DEBUG_MAGIC
- if (sp->magic != 301271) {
- printk(KERN_DEBUG "isac_discardq magic not 301271\n");
- return;
- }
-#endif
-
- BufQueueDiscard(&sp->sq, pr, heldby, releasetoo);
-}
-
-void
-setstack_teles(struct PStack *st, struct IsdnCardState *sp)
-{
- st->l1.hardware = sp;
- st->l1.sbufpool = &(sp->sbufpool);
- st->l1.rbufpool = &(sp->rbufpool);
- st->l1.smallpool = &(sp->smallpool);
- st->protocol = sp->teistack->protocol;
-
- setstack_tei(st);
-
- st->l1.stlistp = &(sp->stlist);
- st->l1.act_state = 0;
- st->l2.l2l1 = teles_l2l1;
- st->l2.l2l1discardq = teles_l2l1discardq;
- st->ma.manl1 = teles_manl1;
- st->l1.requestpull = 0;
-}
-
-void
-init_hscxstate(struct IsdnCardState *sp,
- int hscx)
-{
- struct HscxState *hsp = sp->hs + hscx;
-
- hsp->sp = sp;
- hsp->hscx = hscx;
- hsp->membase = sp->membase;
- hsp->iobase = sp->iobase;
-
- hsp->tqueue.next = 0;
- hsp->tqueue.sync = 0;
- hsp->tqueue.routine = (void *) (void *) hscx_bh;
- hsp->tqueue.data = hsp;
-
- hsp->inuse = 0;
- hsp->init = 0;
- hsp->active = 0;
-
-#ifdef DEBUG_MAGIC
- hsp->magic = 301270;
-#endif
-}
-
-void
-initcard(int cardnr)
-{
- struct IsdnCardState *sp;
- struct IsdnCard *card = cards + cardnr;
-
- sp = (struct IsdnCardState *)
- Smalloc(sizeof(struct IsdnCardState), GFP_KERNEL,
- "struct IsdnCardState");
-
- sp->membase = card->membase;
- sp->iobase = card->iobase;
- sp->cardnr = cardnr;
-
- BufPoolInit(&sp->sbufpool, ISAC_SBUF_ORDER, ISAC_SBUF_BPPS,
- ISAC_SBUF_MAXPAGES);
- BufPoolInit(&sp->rbufpool, ISAC_RBUF_ORDER, ISAC_RBUF_BPPS,
- ISAC_RBUF_MAXPAGES);
- BufPoolInit(&sp->smallpool, ISAC_SMALLBUF_ORDER, ISAC_SMALLBUF_BPPS,
- ISAC_SMALLBUF_MAXPAGES);
-
- sp->dlogspace = Smalloc(4096, GFP_KERNEL, "dlogspace");
-
- initisac(card->membase, card->iobase);
-
- sp->rcvibh = NULL;
- sp->rcvptr = 0;
- sp->xmtibh = NULL;
- sp->sendptr = 0;
- sp->event = 0;
- sp->tqueue.next = 0;
- sp->tqueue.sync = 0;
- sp->tqueue.routine = (void *) (void *) isac_bh;
- sp->tqueue.data = sp;
-
- BufQueueInit(&sp->rq);
- BufQueueInit(&sp->sq);
-
- sp->stlist = NULL;
-
- sp->ph_active = 0;
-
- sp->dlogflag = 0;
- sp->debug = 0;
-
- sp->releasebuf = 0;
-#ifdef DEBUG_MAGIC
- sp->magic = 301271;
-#endif
-
- cards[sp->cardnr].sp = sp;
-
- init_hscxstate(sp, 0);
- init_hscxstate(sp, 1);
-
- modehscx(sp->hs, 0, 0);
- modehscx(sp->hs + 1, 0, 0);
-
- WRITEISAC(sp->membase, sp->iobase, ISAC_MASK, 0x0);
-}
-
-static int
-get_irq(int cardnr)
-{
- struct IsdnCard *card = cards + cardnr;
- long flags;
-
- save_flags(flags);
- cli();
- if (request_irq(card->interrupt, &teles_interrupt,
- SA_INTERRUPT, "teles", NULL)) {
- printk(KERN_WARNING "Teles couldn't get interrupt %d\n",
- card->interrupt);
- restore_flags(flags);
- return (!0);
- }
- irq2dev_map[card->interrupt] = (void *) card->sp;
- restore_flags(flags);
- return (0);
-}
-
-static void
-release_irq(int cardnr)
-{
- struct IsdnCard *card = cards + cardnr;
-
- irq2dev_map[card->interrupt] = NULL;
- free_irq(card->interrupt, NULL);
-}
-
-void
-close_hscxstate(struct HscxState *hs)
-{
- modehscx(hs, 0, 0);
- hs->inuse = 0;
-
- if (hs->init) {
- BufPoolFree(&hs->smallpool);
- BufPoolFree(&hs->rbufpool);
- BufPoolFree(&hs->sbufpool);
- }
- hs->init = 0;
-}
-
-void
-closecard(int cardnr)
-{
- struct IsdnCardState *sp = cards[cardnr].sp;
-
- cards[cardnr].sp = NULL;
-
- Sfree(sp->dlogspace);
-
- BufPoolFree(&sp->smallpool);
- BufPoolFree(&sp->rbufpool);
- BufPoolFree(&sp->sbufpool);
-
- close_hscxstate(sp->hs + 1);
- close_hscxstate(sp->hs);
-
- if (cards[cardnr].iobase)
- if (cards[cardnr].membase) { /* 16.0 */
- release_region(cards[cardnr].iobase, 8);
- } else {
- release_region(cards[cardnr].iobase, 16);
- release_region(cards[cardnr].iobase - 0xC00, 32);
- release_region(cards[cardnr].iobase - 0x800, 32);
- release_region(cards[cardnr].iobase - 0x400, 32);
- }
-
- Sfree((void *) sp);
-}
-
-void
-teles_shiftcards(int idx)
-{
- int i;
-
- for (i = idx; i < 15; i++)
- memcpy(&cards[i],&cards[i+1],sizeof(cards[i]));
-}
-
-int
-teles_inithardware(void)
-{
- int foundcards = 0;
- int i = 0;
-
- while (i < nrcards) {
- if (!cards[i].protocol)
- break;
- switch (checkcard(i)) {
- case (0):
- initcard(i);
- if (get_irq(i)) {
- closecard(i);
- teles_shiftcards(i);
- } else {
- foundcards++;
- i++;
- }
- break;
- case (-1):
- teles_shiftcards(i);
- break;
- case (-2):
- release_region(cards[i].iobase, 8);
- printk(KERN_WARNING "NO Teles card found at 0x%x!\n", cards[i].iobase);
- teles_shiftcards(i);
- break;
- }
- }
- return foundcards;
-}
-
-void
-teles_closehardware(void)
-{
- int i;
-
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp) {
- release_irq(i);
- closecard(i);
- }
-}
-
-static void
-hscx_l2l1(struct PStack *st, int pr,
- struct BufHeader *ibh)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
- struct HscxState *hsp = sp->hs + st->l1.hscx;
- long flags;
-
- switch (pr) {
- case (PH_DATA):
- save_flags(flags);
- cli();
- if (hsp->xmtibh) {
- BufQueueLink(&hsp->sq, ibh);
- restore_flags(flags);
- }
- else {
- restore_flags(flags);
- hsp->xmtibh = ibh;
- hsp->sendptr = 0;
- hsp->releasebuf = !0;
- hscx_fill_fifo(hsp);
- }
- break;
- case (PH_DATA_PULLED):
- if (hsp->xmtibh) {
- printk(KERN_DEBUG "hscx_l2l1: this shouldn't happen\n");
- break;
- }
- hsp->xmtibh = ibh;
- hsp->sendptr = 0;
- hsp->releasebuf = 0;
- hscx_fill_fifo(hsp);
- break;
- case (PH_REQUEST_PULL):
- if (!hsp->xmtibh) {
- st->l1.requestpull = 0;
- st->l1.l1l2(st, PH_PULL_ACK, NULL);
- } else
- st->l1.requestpull = !0;
- break;
- }
-
-}
-
-extern struct IsdnBuffers *tracebuf;
-
-static void
-hscx_l2l1discardq(struct PStack *st, int pr, void *heldby,
- int releasetoo)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
- struct HscxState *hsp = sp->hs + st->l1.hscx;
-
-#ifdef DEBUG_MAGIC
- if (hsp->magic != 301270) {
- printk(KERN_DEBUG "hscx_discardq magic not 301270\n");
- return;
- }
-#endif
-
- BufQueueDiscard(&hsp->sq, pr, heldby, releasetoo);
-}
-
-static int
-open_hscxstate(struct IsdnCardState *sp,
- int hscx)
-{
- struct HscxState *hsp = sp->hs + hscx;
-
- if (!hsp->init) {
- BufPoolInit(&hsp->sbufpool, HSCX_SBUF_ORDER, HSCX_SBUF_BPPS,
- HSCX_SBUF_MAXPAGES);
- BufPoolInit(&hsp->rbufpool, HSCX_RBUF_ORDER, HSCX_RBUF_BPPS,
- HSCX_RBUF_MAXPAGES);
- BufPoolInit(&hsp->smallpool, HSCX_SMALLBUF_ORDER, HSCX_SMALLBUF_BPPS,
- HSCX_SMALLBUF_MAXPAGES);
- }
- hsp->init = !0;
-
- BufQueueInit(&hsp->rq);
- BufQueueInit(&hsp->sq);
-
- hsp->releasebuf = 0;
- hsp->rcvibh = NULL;
- hsp->xmtibh = NULL;
- hsp->rcvptr = 0;
- hsp->sendptr = 0;
- hsp->event = 0;
- return (0);
-}
-
-static void
-hscx_manl1(struct PStack *st, int pr,
- void *arg)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
- struct HscxState *hsp = sp->hs + st->l1.hscx;
-
- switch (pr) {
- case (PH_ACTIVATE):
- hsp->active = !0;
- modehscx(hsp, st->l1.hscxmode, st->l1.hscxchannel);
- st->l1.l1man(st, PH_ACTIVATE, NULL);
- break;
- case (PH_DEACTIVATE):
- if (!hsp->xmtibh)
- modehscx(hsp, 0, 0);
-
- hsp->active = 0;
- break;
- }
-}
-
-int
-setstack_hscx(struct PStack *st, struct HscxState *hs)
-{
- if (open_hscxstate(st->l1.hardware, hs->hscx))
- return (-1);
-
- st->l1.hscx = hs->hscx;
- st->l2.l2l1 = hscx_l2l1;
- st->ma.manl1 = hscx_manl1;
- st->l2.l2l1discardq = hscx_l2l1discardq;
-
- st->l1.sbufpool = &hs->sbufpool;
- st->l1.rbufpool = &hs->rbufpool;
- st->l1.smallpool = &hs->smallpool;
- st->l1.act_state = 0;
- st->l1.requestpull = 0;
-
- hs->st = st;
- return (0);
-}
-
-void
-teles_reportcard(int cardnr)
-{
- printk(KERN_DEBUG "teles_reportcard\n");
-}
diff --git a/drivers/isdn/teles/config.c b/drivers/isdn/teles/config.c
deleted file mode 100644
index 1a9d2d873..000000000
--- a/drivers/isdn/teles/config.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/* $Id: config.c,v 1.1 1996/04/13 10:23:11 fritz Exp $
- *
- * $Log: config.c,v $
- * Revision 1.1 1996/04/13 10:23:11 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/timer.h>
-#include "teles.h"
-
-/*
- * This structure array contains one entry per card. An entry looks
- * like this:
- *
- * { membase,irq,portbase,protocol,NULL }
- *
- * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6
- *
- * Cards which don't have an io port (Teles 8 bit cards for
- * example) can be entered with io port 0x0
- *
- * For the Teles 16.3, membase has to be set to 0.
- *
- */
-
-struct IsdnCard cards[] =
-{
- {(byte *) 0xd0000, 15, 0xd80, ISDN_PTYPE_EURO, NULL}, /* example */
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
-};
diff --git a/drivers/isdn/teles/fsm.c b/drivers/isdn/teles/fsm.c
deleted file mode 100644
index 4d651e73e..000000000
--- a/drivers/isdn/teles/fsm.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/* $Id: fsm.c,v 1.3 1997/02/16 01:04:12 fritz Exp $
- *
- * $Log: fsm.c,v $
- * Revision 1.3 1997/02/16 01:04:12 fritz
- * Bugfix: Changed timer handling caused hang with 2.1.X
- *
- * Revision 1.2 1996/04/29 22:49:57 fritz
- * Removed compatibility-macros.
- *
- * Revision 1.1 1996/04/13 10:23:41 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-void
-FsmNew(struct Fsm *fsm,
- struct FsmNode *fnlist, int fncount)
-{
- int i;
-
- fsm->jumpmatrix = (int *) Smalloc(4L * fsm->state_count * fsm->event_count,
- GFP_KERNEL, "Fsm jumpmatrix");
- memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count);
-
- for (i = 0; i < fncount; i++)
- fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
- fnlist[i].state] = (int) fnlist[i].routine;
-}
-
-void
-FsmFree(struct Fsm *fsm)
-{
- Sfree((void *) fsm->jumpmatrix);
-}
-
-int
-FsmEvent(struct FsmInst *fi, int event, void *arg)
-{
- void (*r) (struct FsmInst *, int, void *);
- char str[80];
-
- r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
- if (r) {
- if (fi->debug) {
- sprintf(str, "State %s Event %s",
- fi->fsm->strState[fi->state],
- fi->fsm->strEvent[event]);
- fi->printdebug(fi, str);
- }
- r(fi, event, arg);
- return (0);
- } else {
- if (fi->debug) {
- sprintf(str, "State %s Event %s no routine",
- fi->fsm->strState[fi->state],
- fi->fsm->strEvent[event]);
- fi->printdebug(fi, str);
- }
- return (!0);
- }
-}
-
-void
-FsmChangeState(struct FsmInst *fi, int newstate)
-{
- char str[80];
-
- fi->state = newstate;
- if (fi->debug) {
- sprintf(str, "ChangeState %s",
- fi->fsm->strState[newstate]);
- fi->printdebug(fi, str);
- }
-}
-
-static void
-FsmExpireTimer(struct FsmTimer *ft)
-{
- FsmEvent(ft->fi, ft->event, ft->arg);
-}
-
-void
-FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
-{
- ft->fi = fi;
- ft->tl.function = (void *) FsmExpireTimer;
- ft->tl.data = (long) ft;
- init_timer(&ft->tl);
-}
-
-void
-FsmDelTimer(struct FsmTimer *ft, int where)
-{
-#if 0
- if (ft->fi->debug) {
- sprintf(str, "FsmDelTimer %lx %d", ft, where);
- ft->fi->printdebug(ft->fi, str);
- }
-#endif
-
- del_timer(&ft->tl);
-}
-
-int
-FsmAddTimer(struct FsmTimer *ft,
- int millisec, int event, void *arg, int where)
-{
-
-#if 0
- if (ft->fi->debug) {
- sprintf(str, "FsmAddTimer %lx %d %d", ft, millisec, where);
- ft->fi->printdebug(ft->fi, str);
- }
-#endif
-
- if (ft->tl.next || ft->tl.prev) {
- printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
- return -1;
- }
- init_timer(&ft->tl);
- ft->event = event;
- ft->arg = arg;
- ft->tl.expires = jiffies + (millisec * HZ) / 1000;
- add_timer(&ft->tl);
- return 0;
-}
-
-int
-FsmTimerRunning(struct FsmTimer *ft)
-{
- return (ft->tl.next != NULL);
-}
-
-void
-jiftime(char *s, long mark)
-{
- s += 8;
-
- *s-- = '\0';
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = '.';
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = mark % 6 + '0';
- mark /= 6;
- *s-- = ':';
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = mark % 10 + '0';
-}
diff --git a/drivers/isdn/teles/isdnl2.c b/drivers/isdn/teles/isdnl2.c
deleted file mode 100644
index 98171aa7d..000000000
--- a/drivers/isdn/teles/isdnl2.c
+++ /dev/null
@@ -1,1320 +0,0 @@
-/* $Id: isdnl2.c,v 1.3 1996/11/23 11:32:57 keil Exp $
- *
- * $Log: isdnl2.c,v $
- * Revision 1.3 1996/11/23 11:32:57 keil
- * X.75 bugfixies; Thanks to Martin Maurer
- *
- * Revision 1.2 1996/05/17 03:46:15 fritz
- * General cleanup.
- *
- * Revision 1.1 1996/04/13 10:24:16 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-#define TIMER_1 2000
-
-static void l2m_debug(struct FsmInst *fi, char *s);
-
-struct Fsm l2fsm =
-{NULL, 0, 0};
-
-enum {
- ST_L2_1,
- ST_L2_3,
- ST_L2_4,
- ST_L2_5,
- ST_L2_6,
- ST_L2_7,
- ST_L2_8,
-};
-
-#define L2_STATE_COUNT (ST_L2_8+1)
-
-static char *strL2State[] =
-{
- "ST_L2_1",
- "ST_L2_3",
- "ST_L2_4",
- "ST_L2_5",
- "ST_L2_6",
- "ST_L2_7",
- "ST_L2_8",
-};
-
-enum {
- EV_L2_UI,
- EV_L2_SABMX,
- EV_L2_UA,
- EV_L2_DISC,
- EV_L2_I,
- EV_L2_RR,
- EV_L2_REJ,
- EV_L2_FRMR,
- EV_L2_DL_DATA,
- EV_L2_DL_ESTABLISH,
- EV_L2_MDL_ASSIGN,
- EV_L2_DL_UNIT_DATA,
- EV_L2_DL_RELEASE,
- EV_L2_MDL_NOTEIPROC,
- EV_L2_T200,
- EV_L2_ACK_PULL,
- EV_L2_T203,
- EV_L2_RNR,
-};
-
-#define L2_EVENT_COUNT (EV_L2_RNR+1)
-
-static char *strL2Event[] =
-{
- "EV_L2_UI",
- "EV_L2_SABMX",
- "EV_L2_UA",
- "EV_L2_DISC",
- "EV_L2_I",
- "EV_L2_RR",
- "EV_L2_REJ",
- "EV_L2_FRMR",
- "EV_L2_DL_DATA",
- "EV_L2_DL_ESTABLISH",
- "EV_L2_MDL_ASSIGN",
- "EV_L2_DL_UNIT_DATA",
- "EV_L2_DL_RELEASE",
- "EV_L2_MDL_NOTEIPROC",
- "EV_L2_T200",
- "EV_L2_ACK_PULL",
- "EV_L2_T203",
- "EV_L2_RNR",
-};
-
-int errcount = 0;
-
-static int l2addrsize(struct Layer2 *tsp);
-
-static int
-cansend(struct PStack *st)
-{
- int p1;
-
- p1 = (st->l2.va + st->l2.window) % (st->l2.extended ? 128 : 8);
- return (st->l2.vs != p1);
-}
-
-static void
-discard_i_queue(struct PStack *st)
-{
- struct BufHeader *ibh;
-
- while (!BufQueueUnlink(&ibh, &st->l2.i_queue))
- BufPoolRelease(ibh);
-}
-
-int
-l2headersize(struct Layer2 *tsp, int UI)
-{
- return ((tsp->extended && (!UI) ? 2 : 1) + (tsp->laptype == LAPD ? 2 : 1));
-}
-
-int
-l2addrsize(struct Layer2 *tsp)
-{
- return (tsp->laptype == LAPD ? 2 : 1);
-}
-
-static int
-sethdraddr(struct Layer2 *tsp,
- struct BufHeader *ibh, int rsp)
-{
- byte *ptr = DATAPTR(ibh);
- int crbit;
-
- if (tsp->laptype == LAPD) {
- crbit = rsp;
- if (!tsp->orig)
- crbit = !crbit;
- *ptr++ = (tsp->sap << 2) | (crbit ? 2 : 0);
- *ptr++ = (tsp->tei << 1) | 1;
- return (2);
- } else {
- crbit = rsp;
- if (tsp->orig)
- crbit = !crbit;
- if (crbit)
- *ptr++ = 1;
- else
- *ptr++ = 3;
- return (1);
- }
-}
-
-static void
-enqueue_ui(struct PStack *st,
- struct BufHeader *ibh)
-{
- st->l2.l2l1(st, PH_DATA, ibh);
-}
-
-static void
-enqueue_super(struct PStack *st,
- struct BufHeader *ibh)
-{
- st->l2.l2l1(st, PH_DATA, ibh);
-}
-
-static int
-legalnr(struct PStack *st, int nr)
-{
- struct Layer2 *l2 = &st->l2;
- int lnr, lvs;
-
- lvs = (l2->vs >= l2->va) ? l2->vs : (l2->vs + l2->extended ? 128 : 8);
- lnr = (nr >= l2->va) ? nr : (nr + l2->extended ? 128 : 8);
- return (lnr <= lvs);
-}
-
-static void
-setva(struct PStack *st, int nr)
-{
- struct Layer2 *l2 = &st->l2;
-
- if (l2->va != nr) {
- while (l2->va != nr) {
- l2->va = (l2->va + 1) % (l2->extended ? 128 : 8);
- BufPoolRelease(l2->windowar[l2->sow]);
- l2->sow = (l2->sow + 1) % l2->window;
- }
- if (st->l4.l2writewakeup)
- st->l4.l2writewakeup(st);
- }
-}
-
-static void
-l2s1(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.l2tei(st, MDL_ASSIGN, (void *)st->l2.ces);
- FsmChangeState(fi, ST_L2_3);
-}
-
-static void
-l2s2(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
-
- byte *ptr;
- int i;
-
- i = sethdraddr(&(st->l2), ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x3;
-
- enqueue_ui(st, ibh);
-}
-
-static void
-l2s3(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
-
- st->l2.l2l3(st, DL_UNIT_DATA, ibh);
-}
-
-static void
-establishlink(struct FsmInst *fi)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh;
- int i;
- byte *ptr;
-
- FsmChangeState(fi, ST_L2_5);
- st->l2.rc = 0;
-
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 1))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 1");
-
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
- return;
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- if (st->l2.extended)
- *ptr = 0x7f;
- else
- *ptr = 0x3f;
- ibh->datasize = i + 1;
-
- enqueue_super(st, ibh);
-}
-
-static void
-l2s11(struct FsmInst *fi, int event, void *arg)
-{
- establishlink(fi);
-}
-
-static void
-l2s13(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
- byte *ptr;
- struct BufHeader *ibh;
- int i;
-
- FsmChangeState(fi, ST_L2_6);
-
- FsmDelTimer(&st->l2.t203_timer, 1);
- if (st->l2.t200_running) {
- FsmDelTimer(&st->l2.t200_timer, 2);
- st->l2.t200_running = 0;
- }
- st->l2.rc = 0;
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 2))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 2");
-
-
- if ((chanp->impair == 2) && (st->l2.laptype == LAPB))
- goto nodisc;
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 9))
- return;
- i = sethdraddr(&(st->l2), ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x53;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
-
- nodisc:
- discard_i_queue(st);
-}
-
-static void
-l2s12(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- byte *ptr;
- int i;
-
- BufPoolRelease(ibh);
- st->l2.vs = 0;
- st->l2.va = 0;
- st->l2.vr = 0;
- st->l2.sow = 0;
- FsmChangeState(fi, ST_L2_7);
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 3");
-
- st->l2.l2man(st, DL_ESTABLISH, NULL);
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10))
- return;
- i = sethdraddr(&(st->l2), ibh, !0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x73;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
-
-}
-
-static void
-l2s14(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- struct Channel *chanp = st->l4.userdata;
- byte *ptr;
- int i, p;
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(&(st->l2));
- p = (*ptr) & 0x10;
- BufPoolRelease(ibh);
-
- FsmChangeState(fi, ST_L2_4);
-
- FsmDelTimer(&st->l2.t203_timer, 3);
- if (st->l2.t200_running) {
- FsmDelTimer(&st->l2.t200_timer, 4);
- st->l2.t200_running = 0;
- }
- if ((chanp->impair == 1) && (st->l2.laptype == LAPB))
- goto noresponse;
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 11))
- return;
- i = sethdraddr(&(st->l2), ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x63 | (p ? 0x10 : 0x0);
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
-
- noresponse:
- st->l2.l2man(st, DL_RELEASE, NULL);
-
-}
-
-static void
-l2s5(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int f;
- byte *data;
-
- data = DATAPTR(ibh);
- data += l2addrsize(&(st->l2));
-
- f = *data & 0x10;
- BufPoolRelease(ibh);
-
- if (f) {
- st->l2.vs = 0;
- st->l2.va = 0;
- st->l2.vr = 0;
- st->l2.sow = 0;
- FsmChangeState(fi, ST_L2_7);
-
- FsmDelTimer(&st->l2.t200_timer, 5);
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 4))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 4");
-
-
- st->l2.l2man(st, DL_ESTABLISH, NULL);
- }
-}
-
-static void
-l2s15(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int f;
- byte *data;
-
- data = DATAPTR(ibh);
- data += l2addrsize(&st->l2);
-
- f = *data & 0x10;
- BufPoolRelease(ibh);
-
- if (f) {
- FsmDelTimer(&st->l2.t200_timer, 6);
- FsmChangeState(fi, ST_L2_4);
- st->l2.l2man(st, DL_RELEASE, NULL);
- }
-}
-
-static void
-l2s6(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
- struct BufHeader *ibh = arg;
- int p, i, seq, rsp;
- byte *ptr;
- struct Layer2 *l2;
-
- l2 = &st->l2;
- ptr = DATAPTR(ibh);
-
- if (l2->laptype == LAPD) {
- rsp = ptr[0] & 0x2;
- if (l2->orig)
- rsp = !rsp;
- } else {
- rsp = ptr[0] == 0x3;
- if (l2->orig)
- rsp = !rsp;
- }
-
- ptr += l2addrsize(l2);
-
- if (l2->extended) {
- p = (ptr[1] & 0x1) == 0x1;
- seq = ptr[1] >> 1;
- } else {
- p = (ptr[0] & 0x10);
- seq = (ptr[0] >> 5) & 0x7;
- }
- BufPoolRelease(ibh);
-
- if ((chanp->impair == 4) && (st->l2.laptype == LAPB))
- goto noresp;
-
- if ((!rsp) && p) {
- if (!BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 12)) {
- i = sethdraddr(l2, ibh, !0);
- ptr = DATAPTR(ibh);
- ptr += i;
-
- if (l2->extended) {
- *ptr++ = 0x1;
- *ptr++ = (l2->vr << 1) | (p ? 1 : 0);
- i += 2;
- } else {
- *ptr++ = (l2->vr << 5) | 0x1 | (p ? 0x10 : 0x0);
- i += 1;
- }
- ibh->datasize = i;
- enqueue_super(st, ibh);
- }
- }
- noresp:
- if (legalnr(st, seq))
- if (seq == st->l2.vs) {
- setva(st, seq);
- FsmDelTimer(&st->l2.t200_timer, 7);
- st->l2.t200_running = 0;
- FsmDelTimer(&st->l2.t203_timer, 8);
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 5))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 5");
-
- if (st->l2.i_queue.head)
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- } else if (st->l2.va != seq) {
- setva(st, seq);
- FsmDelTimer(&st->l2.t200_timer, 9);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 6))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 6");
-
- if (st->l2.i_queue.head)
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- }
-}
-
-static void
-l2s7(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int i;
- byte *ptr;
- struct IsdnCardState *sp = st->l1.hardware;
- char str[64];
-
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
-
- if (st->l2.laptype == LAPD)
- if (sp->dlogflag) {
- sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
- dlogframe(sp, ptr + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- str);
- }
- BufQueueLink(&st->l2.i_queue, ibh);
-
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-}
-
-static void
-l2s8(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
- struct BufHeader *ibh = arg;
- byte *ptr;
- struct BufHeader *ibh2;
- struct IsdnCardState *sp = st->l1.hardware;
- struct Layer2 *l2 = &(st->l2);
- int i, p, seq, nr, wasok;
- char str[64];
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(l2);
- if (l2->extended) {
- p = (ptr[1] & 0x1) == 0x1;
- seq = ptr[0] >> 1;
- nr = (ptr[1] >> 1) & 0x7f;
- } else {
- p = (ptr[0] & 0x10);
- seq = (ptr[0] >> 1) & 0x7;
- nr = (ptr[0] >> 5) & 0x7;
- }
-
- if (l2->vr == seq) {
- wasok = !0;
-
- l2->vr = (l2->vr + 1) % (l2->extended ? 128 : 8);
- l2->rejexp = 0;
-
- ptr = DATAPTR(ibh);
- if (st->l2.laptype == LAPD)
- if (sp->dlogflag) {
- sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei);
- dlogframe(st->l1.hardware, ptr + l2->ihsize,
- ibh->datasize - l2->ihsize, str);
- }
- label8_1:
- if ((chanp->impair == 3) && (st->l2.laptype == LAPB))
- goto noRR;
-
- if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 13)) {
- i = sethdraddr(&(st->l2), ibh2, !0);
- ptr = DATAPTR(ibh2);
- ptr += i;
-
- if (l2->extended) {
- *ptr++ = 0x1;
- *ptr++ = (l2->vr << 1) | (p ? 1 : 0);
- i += 2;
- } else {
- *ptr++ = (l2->vr << 5) | 0x1 | (p ? 0x10 : 0x0);
- i += 1;
- }
- ibh2->datasize = i;
- enqueue_super(st, ibh2);
- noRR:
- }
- } else {
- /* n(s)!=v(r) */
- wasok = 0;
- BufPoolRelease(ibh);
- if (st->l2.rejexp) {
- if (p)
- goto label8_1;
- } else {
- st->l2.rejexp = !0;
- if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 14)) {
- i = sethdraddr(&(st->l2), ibh2, p);
- ptr = DATAPTR(ibh2);
- ptr += i;
-
- if (l2->extended) {
- *ptr++ = 0x9;
- *ptr++ = (l2->vr << 1) | (p ? 1 : 0);
- i += 2;
- } else {
- *ptr++ = (l2->vr << 5) | 0x9 | (p ? 0x10 : 0x0);
- i += 1;
- }
- ibh2->datasize = i;
- enqueue_super(st, ibh2);
- }
- }
- }
-
- if (legalnr(st, nr))
- if (nr == st->l2.vs) {
- setva(st, nr);
- FsmDelTimer(&st->l2.t200_timer, 10);
- st->l2.t200_running = 0;
- FsmDelTimer(&st->l2.t203_timer, 11);
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 7))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 5");
-
- if (st->l2.i_queue.head)
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- } else if (nr != st->l2.va) {
- setva(st, nr);
- FsmDelTimer(&st->l2.t200_timer, 12);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 8))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 6");
-
- if (st->l2.i_queue.head)
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- }
- if (wasok)
- st->l2.l2l3(st, DL_DATA, ibh);
-
-}
-
-static void
-l2s17(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.tei = (int) arg;
- establishlink(fi);
-}
-
-static void
-enquiry_response(struct PStack *st)
-{
- struct BufHeader *ibh2;
- int i;
- byte *ptr;
- struct Layer2 *l2;
-
- l2 = &st->l2;
- if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 16)) {
- i = sethdraddr(&(st->l2), ibh2, !0);
- ptr = DATAPTR(ibh2);
- ptr += i;
-
- if (l2->extended) {
- *ptr++ = 0x1;
- *ptr++ = (l2->vr << 1) | 0x1;
- i += 2;
- } else {
- *ptr++ = (l2->vr << 5) | 0x1 | 0x10;
- i += 1;
- }
- ibh2->datasize = i;
- enqueue_super(st, ibh2);
- }
-}
-
-static void
-invoke_retransmission(struct PStack *st, int nr)
-{
- struct Layer2 *l2 = &st->l2;
- int p1;
-
- if (l2->vs != nr) {
- while (l2->vs != nr) {
-
- l2->vs = l2->vs - 1;
- if (l2->vs < 0)
- l2->vs += l2->extended ? 128 : 8;
-
- p1 = l2->vs - l2->va;
- if (p1 < 0)
- p1 += l2->extended ? 128 : 8;
- p1 = (p1 + l2->sow) % l2->window;
-
- BufQueueLinkFront(&l2->i_queue, l2->windowar[p1]);
- }
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- }
-}
-
-static void
-l2s16(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int p, seq, rsp;
- byte *ptr;
- struct Layer2 *l2;
-
- l2 = &(st->l2);
- ptr = DATAPTR(ibh);
-
- if (l2->laptype == LAPD) {
- rsp = ptr[0] & 0x2;
- if (l2->orig)
- rsp = !rsp;
- } else {
- rsp = ptr[0] == 0x3;
- if (l2->orig)
- rsp = !rsp;
- }
-
-
- ptr += l2addrsize(l2);
-
- if (l2->extended) {
- p = (ptr[1] & 0x1) == 0x1;
- seq = ptr[1] >> 1;
- } else {
- p = (ptr[0] & 0x10);
- seq = (ptr[0] >> 5) & 0x7;
- }
- BufPoolRelease(ibh);
-
- if ((!rsp) && p)
- enquiry_response(st);
-
- if (!legalnr(st, seq))
- return;
-
- setva(st, seq);
- invoke_retransmission(st, seq);
-
-}
-
-static void
-l2s19(struct FsmInst *fi, int event, void *arg)
-{
- FsmChangeState(fi, ST_L2_4);
-}
-
-static void
-l2s20(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- int i;
- struct BufHeader *ibh;
- byte *ptr;
-
- if (st->l2.rc == st->l2.n200) {
- FsmChangeState(fi, ST_L2_4);
- st->l2.l2man(st, DL_RELEASE, NULL);
- } else {
- st->l2.rc++;
-
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 9))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 7");
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
- return;
-
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- if (st->l2.extended)
- *ptr = 0x7f;
- else
- *ptr = 0x3f;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
- }
-}
-
-static void
-l2s21(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
- int i;
- struct BufHeader *ibh;
- byte *ptr;
-
- if (st->l2.rc == st->l2.n200) {
- FsmChangeState(fi, ST_L2_4);
- st->l2.l2man(st, DL_RELEASE, NULL);
- } else {
- st->l2.rc++;
-
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 10))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 8");
-
-
- if ((chanp->impair == 2) && (st->l2.laptype == LAPB))
- goto nodisc;
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
- return;
-
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x53;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
- nodisc:
-
- }
-}
-
-static void
-l2s22(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh;
- struct Layer2 *l2 = &st->l2;
- byte *ptr;
- int p1;
-
- if (!cansend(st))
- return;
-
- if (BufQueueUnlink(&ibh, &l2->i_queue))
- return;
-
-
- p1 = l2->vs - l2->va;
- if (p1 < 0)
- p1 += l2->extended ? 128 : 8;
- p1 = (p1 + l2->sow) % l2->window;
- l2->windowar[p1] = ibh;
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(l2);
-
- if (l2->extended) {
- *ptr++ = l2->vs << 1;
- *ptr++ = (l2->vr << 1) | 0x1;
- l2->vs = (l2->vs + 1) % 128;
- } else {
- *ptr++ = (l2->vr << 5) | (l2->vs << 1);
- l2->vs = (l2->vs + 1) % 8;
- }
-
- st->l2.l2l1(st, PH_DATA_PULLED, ibh);
-
- if (!st->l2.t200_running) {
- FsmDelTimer(&st->l2.t203_timer, 13);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 11))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 9");
-
- st->l2.t200_running = !0;
- }
- if (l2->i_queue.head && cansend(st))
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-
-}
-
-static void
-transmit_enquiry(struct PStack *st)
-{
- struct BufHeader *ibh;
- byte *ptr;
-
- if (!BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 12)) {
- ptr = DATAPTR(ibh);
- ptr += sethdraddr(&st->l2, ibh, 0);
-
- if (st->l2.extended) {
- *ptr++ = 0x1;
- *ptr++ = (st->l2.vr << 1) | 1;
- } else {
- *ptr++ = (st->l2.vr << 5) | 0x11;
- }
- ibh->datasize = ptr - DATAPTR(ibh);
- enqueue_super(st, ibh);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 12))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 10");
-
- st->l2.t200_running = !0;
- }
-}
-
-static void
-l2s23(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.t200_running = 0;
-
- st->l2.rc = 1;
- FsmChangeState(fi, ST_L2_8);
- transmit_enquiry(st);
-}
-
-static void
-l2s24(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int p, seq, rsp;
- byte *ptr;
- struct Layer2 *l2;
-
- l2 = &st->l2;
- ptr = DATAPTR(ibh);
-
- if (l2->laptype == LAPD) {
- rsp = ptr[0] & 0x2;
- if (l2->orig)
- rsp = !rsp;
- } else {
- rsp = ptr[0] == 0x3;
- if (l2->orig)
- rsp = !rsp;
- }
-
-
- ptr += l2addrsize(l2);
-
- if (l2->extended) {
- p = (ptr[1] & 0x1) == 0x1;
- seq = ptr[1] >> 1;
- } else {
- p = (ptr[0] & 0x10);
- seq = (ptr[0] >> 5) & 0x7;
- }
- BufPoolRelease(ibh);
-
- if (rsp && p) {
- if (legalnr(st, seq)) {
- FsmChangeState(fi, ST_L2_7);
- setva(st, seq);
- if (st->l2.t200_running) {
- FsmDelTimer(&st->l2.t200_timer, 14);
- st->l2.t200_running = 0;
- }
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 13))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 11");
-
- invoke_retransmission(st, seq);
- }
- } else {
- if (!rsp && p)
- enquiry_response(st);
- if (legalnr(st, seq)) {
- setva(st, seq);
- }
- }
-}
-
-static void
-l2s25(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.rc = 0;
- FsmChangeState(fi, ST_L2_8);
- transmit_enquiry(st);
-}
-
-static void
-l2s26(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (st->l2.rc == st->l2.n200) {
- l2s13(fi, event, NULL);
- } else {
- st->l2.rc++;
- transmit_enquiry(st);
- }
-}
-
-static void
-l2s27(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- byte *ptr;
- int i, p, est;
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(&st->l2);
-
- if (st->l2.extended)
- p = ptr[1] & 0x1;
- else
- p = ptr[0] & 0x10;
-
- BufPoolRelease(ibh);
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10))
- return;
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x63 | p;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
-
- if (st->l2.vs != st->l2.va) {
- discard_i_queue(st);
- est = !0;
- } else
- est = 0;
-
- FsmDelTimer(&st->l2.t200_timer, 15);
- st->l2.t200_running = 0;
-
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 12");
-
- st->l2.vs = 0;
- st->l2.va = 0;
- st->l2.vr = 0;
- st->l2.sow = 0;
-
-
- if (est)
- st->l2.l2man(st, DL_ESTABLISH, NULL);
-
-}
-
-static void
-l2s28(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- byte *ptr;
- char tmp[64];
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(&st->l2);
- ptr++;
-
- if (st->l2.l2m.debug) {
- if (st->l2.extended)
- sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x",
- ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
- else
- sprintf(tmp, "FRMR information %2x %2x %2x",
- ptr[0], ptr[1], ptr[2]);
-
- l2m_debug(&st->l2.l2m, tmp);
- }
- BufPoolRelease(ibh);
-}
-
-static int
-IsUI(byte * data, int ext)
-{
- return ((data[0] & 0xef) == 0x3);
-}
-
-static int
-IsUA(byte * data, int ext)
-{
- return ((data[0] & 0xef) == 0x63);
-}
-
-static int
-IsDISC(byte * data, int ext)
-{
- return ((data[0] & 0xef) == 0x43);
-}
-
-static int
-IsRR(byte * data, int ext)
-{
- if (ext)
- return (data[0] == 0x1);
- else
- return ((data[0] & 0xf) == 1);
-}
-
-static int
-IsI(byte * data, int ext)
-{
- return ((data[0] & 0x1) == 0x0);
-}
-
-static int
-IsSABMX(byte * data, int ext)
-{
- return (ext ? data[0] == 0x7f : data[0] == 0x3f);
-}
-
-static int
-IsREJ(byte * data, int ext)
-{
- return (ext ? data[0] == 0x9 : (data[0] & 0xf) == 0x9);
-}
-
-static int
-IsFRMR(byte * data, int ext)
-{
- return ((data[0] & 0xef) == 0x87);
-}
-
-static int
-IsRNR(byte * data, int ext)
-{
- if (ext)
- return (data[0] == 0x5);
- else
- return ((data[0] & 0xf) == 5);
-}
-
-static struct FsmNode L2FnList[] =
-{
- {ST_L2_1, EV_L2_DL_ESTABLISH, l2s1},
- {ST_L2_1, EV_L2_MDL_NOTEIPROC, l2s19},
- {ST_L2_3, EV_L2_MDL_ASSIGN, l2s17},
- {ST_L2_4, EV_L2_DL_UNIT_DATA, l2s2},
- {ST_L2_4, EV_L2_DL_ESTABLISH, l2s11},
- {ST_L2_7, EV_L2_DL_UNIT_DATA, l2s2},
- {ST_L2_7, EV_L2_DL_DATA, l2s7},
- {ST_L2_7, EV_L2_DL_RELEASE, l2s13},
- {ST_L2_7, EV_L2_ACK_PULL, l2s22},
- {ST_L2_8, EV_L2_DL_RELEASE, l2s13},
-
- {ST_L2_1, EV_L2_UI, l2s3},
- {ST_L2_4, EV_L2_UI, l2s3},
- {ST_L2_4, EV_L2_SABMX, l2s12},
- {ST_L2_5, EV_L2_UA, l2s5},
- {ST_L2_6, EV_L2_UA, l2s15},
- {ST_L2_7, EV_L2_UI, l2s3},
- {ST_L2_7, EV_L2_DISC, l2s14},
- {ST_L2_7, EV_L2_I, l2s8},
- {ST_L2_7, EV_L2_RR, l2s6},
- {ST_L2_7, EV_L2_REJ, l2s16},
- {ST_L2_7, EV_L2_SABMX, l2s27},
- {ST_L2_7, EV_L2_FRMR, l2s28},
- {ST_L2_8, EV_L2_RR, l2s24},
- {ST_L2_8, EV_L2_DISC, l2s14},
- {ST_L2_8, EV_L2_FRMR, l2s28},
-
- {ST_L2_5, EV_L2_T200, l2s20},
- {ST_L2_6, EV_L2_T200, l2s21},
- {ST_L2_7, EV_L2_T200, l2s23},
- {ST_L2_7, EV_L2_T203, l2s25},
- {ST_L2_8, EV_L2_T200, l2s26},
-};
-
-#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
-
-static void
-isdnl2_l1l2(struct PStack *st, int pr, struct BufHeader *arg)
-{
- struct BufHeader *ibh;
- byte *datap;
- int ret = !0;
-
- switch (pr) {
- case (PH_DATA):
-
- ibh = arg;
- datap = DATAPTR(ibh);
- datap += l2addrsize(&st->l2);
-
- if (IsI(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_I, ibh);
- else if (IsRR(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_RR, ibh);
- else if (IsUI(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_UI, ibh);
- else if (IsSABMX(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, ibh);
- else if (IsUA(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_UA, ibh);
- else if (IsDISC(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, ibh);
- else if (IsREJ(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_REJ, ibh);
- else if (IsFRMR(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, ibh);
- else if (IsRNR(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_RNR, ibh);
-
- if (ret)
- BufPoolRelease(ibh);
-
- break;
- case (PH_PULL_ACK):
- FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
- break;
- }
-}
-
-static void
-isdnl2_l3l2(struct PStack *st, int pr,
- void *arg)
-{
- switch (pr) {
- case (DL_DATA):
- if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg))
- BufPoolRelease((struct BufHeader *) arg);
- break;
- case (DL_UNIT_DATA):
- if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg))
- BufPoolRelease((struct BufHeader *) arg);
- break;
- }
-}
-
-static void
-isdnl2_manl2(struct PStack *st, int pr,
- void *arg)
-{
- switch (pr) {
- case (DL_ESTABLISH):
- FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
- break;
- case (DL_RELEASE):
- FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE, arg);
- break;
- case (MDL_NOTEIPROC):
- FsmEvent(&st->l2.l2m, EV_L2_MDL_NOTEIPROC, NULL);
- break;
- }
-}
-
-static void
-isdnl2_teil2(struct PStack *st, int pr,
- void *arg)
-{
- switch (pr) {
- case (MDL_ASSIGN):
- FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
- break;
- }
-}
-
-void
-releasestack_isdnl2(struct PStack *st)
-{
- FsmDelTimer(&st->l2.t200_timer, 15);
- FsmDelTimer(&st->l2.t203_timer, 16);
-}
-
-static void
-l2m_debug(struct FsmInst *fi, char *s)
-{
- struct PStack *st = fi->userdata;
- char tm[32], str[256];
-
- jiftime(tm, jiffies);
- sprintf(str, "%s %s %s\n", tm, st->l2.debug_id, s);
- teles_putstatus(str);
-}
-
-
-void
-setstack_isdnl2(struct PStack *st, char *debug_id)
-{
- st->l1.l1l2 = isdnl2_l1l2;
- st->l3.l3l2 = isdnl2_l3l2;
- st->ma.manl2 = isdnl2_manl2;
- st->ma.teil2 = isdnl2_teil2;
-
- st->l2.uihsize = l2headersize(&st->l2, !0);
- st->l2.ihsize = l2headersize(&st->l2, 0);
- BufQueueInit(&(st->l2.i_queue));
- st->l2.rejexp = 0;
- st->l2.debug = 1;
-
- st->l2.l2m.fsm = &l2fsm;
- st->l2.l2m.state = ST_L2_1;
- st->l2.l2m.debug = 0;
- st->l2.l2m.userdata = st;
- st->l2.l2m.printdebug = l2m_debug;
- strcpy(st->l2.debug_id, debug_id);
-
- FsmInitTimer(&st->l2.l2m, &st->l2.t200_timer);
- FsmInitTimer(&st->l2.l2m, &st->l2.t203_timer);
- st->l2.t200_running = 0;
-}
-
-void
-setstack_transl2(struct PStack *st)
-{
-}
-
-void
-releasestack_transl2(struct PStack *st)
-{
-}
-
-void
-Isdnl2New(void)
-{
- l2fsm.state_count = L2_STATE_COUNT;
- l2fsm.event_count = L2_EVENT_COUNT;
- l2fsm.strEvent = strL2Event;
- l2fsm.strState = strL2State;
- FsmNew(&l2fsm, L2FnList, L2_FN_COUNT);
-}
-
-void
-Isdnl2Free(void)
-{
- FsmFree(&l2fsm);
-}
diff --git a/drivers/isdn/teles/isdnl3.c b/drivers/isdn/teles/isdnl3.c
deleted file mode 100644
index 3bfb47255..000000000
--- a/drivers/isdn/teles/isdnl3.c
+++ /dev/null
@@ -1,673 +0,0 @@
-/* $Id: isdnl3.c,v 1.13 1997/02/16 12:12:51 fritz Exp $
- *
- * $Log: isdnl3.c,v $
- * Revision 1.13 1997/02/16 12:12:51 fritz
- * Bugfix: SI2 was nont initialized on incoming calls.
- *
- * Revision 1.12 1997/02/11 01:39:20 keil
- * Changed setup-interface (incoming and outgoing)
- *
- * Revision 1.11 1996/09/29 19:41:58 fritz
- * Bugfix: ignore unknown frames.
- *
- * Revision 1.10 1996/09/25 18:32:43 keil
- * response for STATUS_ENQ message added
- *
- * Revision 1.9 1996/06/06 14:22:27 fritz
- * Changed level of "non-digital call..." message, since
- * with audio support, this is quite normal.
- *
- * Revision 1.8 1996/06/03 20:35:04 fritz
- * Fixed typos.
- *
- * Revision 1.7 1996/06/03 20:03:39 fritz
- * Fixed typos.
- *
- * Revision 1.6 1996/05/21 11:33:50 keil
- * Adding SETUP_ACKNOWLEDGE as answer of a SETUP message.
- *
- * Revision 1.5 1996/05/18 01:37:16 fritz
- * Added spelling corrections and some minor changes
- * to stay in sync with kernel.
- *
- * Revision 1.4 1996/05/17 03:46:16 fritz
- * General cleanup.
- *
- * Revision 1.3 1996/04/30 21:57:53 isdn4dev
- * remove some debugging code, improve callback Karsten Keil
- *
- * Revision 1.2 1996/04/20 16:45:05 fritz
- * Changed to report all incoming calls to Linklevel, not just those
- * with Service 7.
- * Misc. typos
- *
- * Revision 1.1 1996/04/13 10:24:45 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#define P_1TR6
-#include "teles.h"
-#include "l3_1TR6.h"
-#define DEBUG_1TR6 0
-
-static void
-i_down(struct PStack *st,
- struct BufHeader *ibh)
-{
- st->l3.l3l2(st, DL_DATA, ibh);
-}
-
-static void
-newl3state(struct PStack *st, int state)
-{
- st->l3.state = state;
- if (DEBUG_1TR6 > 4)
- printk(KERN_INFO "isdnl3: bc:%d cr:%x new state %d\n",
- st->pa->bchannel, st->pa->callref, state);
-
-}
-
-static void
-l3_message(struct PStack *st, int mt)
-{
- struct BufHeader *dibh;
- byte *p;
- int size;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
- size = st->l2.ihsize;
-
- *p++ = 0x8;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = mt;
- size += 4;
-
- dibh->datasize = size;
- i_down(st, dibh);
-}
-
-static void
-l3s3(struct PStack *st, byte pr, void *arg)
-{
- l3_message(st, MT_RELEASE);
- newl3state(st, 19);
-}
-
-static void
-l3s4(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 0);
- st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3s4_1(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 19);
- l3_message(st, MT_RELEASE);
- st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3s5(struct PStack *st, byte pr,
- void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
- char *teln;
-
- st->l3.callref = st->pa->callref;
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = 0x8;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_SETUP;
- *p++ = 0xa1;
-
- /*
- * Set Bearer Capability, Map info from 1TR6-convention to EDSS1
- */
- switch (st->pa->setup.si1) {
- case 1: /* Telephony */
- *p++ = 0x4; /* BC-IE-code */
- *p++ = 0x3; /* Length */
- *p++ = 0x90; /* Coding Std. national, 3.1 kHz audio */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- *p++ = 0xa3; /* A-Law Audio */
- break;
- case 5: /* Datatransmission 64k, BTX */
- case 7: /* Datatransmission 64k */
- default:
- *p++ = 0x4; /* BC-IE-code */
- *p++ = 0x2; /* Length */
- *p++ = 0x88; /* Coding Std. nat., unrestr. dig. Inform. */
- *p++ = 0x90; /* Packet-Mode 64kbps */
- break;
- }
- /*
- * What about info2? Mapping to High-Layer-Compatibility?
- */
- if (st->pa->setup.eazmsn[0] != '\0') {
- *p++ = 0x6c;
- *p++ = strlen(st->pa->setup.eazmsn) + 1;
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- teln = st->pa->setup.eazmsn;
- while (*teln)
- *p++ = *teln++ & 0x7f;
- }
- *p++ = 0x70;
- *p++ = strlen(st->pa->setup.phone) + 1;
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
-
- teln = st->pa->setup.phone;
- while (*teln)
- *p++ = *teln++ & 0x7f;
-
-
- dibh->datasize = p - DATAPTR(dibh);
-
- newl3state(st, 1);
- i_down(st, dibh);
-
-}
-
-static void
-l3s6(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- 0x18, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- } else
- printk(KERN_WARNING "octect 3 not found\n");
-
- BufPoolRelease(ibh);
- newl3state(st, 3);
- st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
-}
-
-static void
-l3s7(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 12);
- st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
-}
-
-static void
-l3s8(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- st->l3.l3l4(st, CC_SETUP_CNF, NULL);
- newl3state(st, 10);
-}
-
-static void
-l3s11(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 4);
- st->l3.l3l4(st, CC_ALERTING_IND, NULL);
-}
-
-static void
-l3s12(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- int bcfound = 0;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- p += st->l2.uihsize;
- st->pa->callref = getcallref(p);
- st->l3.callref = 0x80 + st->pa->callref;
-
- /*
- * Channel Identification
- */
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- 0x18, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- bcfound++ ;
- } else
- printk(KERN_WARNING "l3s12: Channel ident not found\n");
-
- p = DATAPTR(ibh);
- if (st->protocol == ISDN_PTYPE_1TR6) {
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x01, 6))) {
- st->pa->setup.si1 = p[2];
- st->pa->setup.si2 = p[3];
- } else
- printk(KERN_WARNING "l3s12(1TR6): ServiceIndicator not found\n");
- } else {
- /*
- * Bearer Capabilities
- */
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x04, 0))) {
- st->pa->setup.si2 = 0;
- switch (p[2] & 0x1f) {
- case 0x00:
- /* Speech */
- case 0x10:
- /* 3.1 Khz audio */
- st->pa->setup.si1 = 1;
- break;
- case 0x08:
- /* Unrestricted digital information */
- st->pa->setup.si1 = 7;
- break;
- case 0x09:
- /* Restricted digital information */
- st->pa->setup.si1 = 2;
- break;
- case 0x11:
- /* Unrestr. digital information with tones/announcements */
- st->pa->setup.si1 = 3;
- break;
- case 0x18:
- /* Video */
- st->pa->setup.si1 = 4;
- break;
- default:
- st->pa->setup.si1 = 0;
- }
- } else
- printk(KERN_WARNING "l3s12: Bearer capabilities not found\n");
- }
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- 0x70, 0)))
- iecpy(st->pa->setup.eazmsn, p, 1);
- else
- strcpy(st->pa->setup.eazmsn, "");
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- 0x6c, 0))) {
- st->pa->setup.plan = p[2];
- if (st->protocol == ISDN_PTYPE_1TR6) {
- iecpy(st->pa->setup.phone, p, 1);
- } else {
- st->pa->setup.screen = p[3];
- iecpy(st->pa->setup.phone, p, 2);
- }
- } else
- strcpy(st->pa->setup.phone, "");
- BufPoolRelease(ibh);
-
- if (bcfound) {
- if (st->pa->setup.si1 != 7) {
- printk(KERN_DEBUG "non-digital call: %s -> %s\n",
- st->pa->setup.phone,
- st->pa->setup.eazmsn);
- }
- newl3state(st, 6);
- st->l3.l3l4(st, CC_SETUP_IND, NULL);
- }
-}
-
-static void
-l3s13(struct PStack *st, byte pr, void *arg)
-{
- newl3state(st, 0);
-}
-
-static void
-l3s16(struct PStack *st, byte pr,
- void *arg)
-{
- st->l3.callref = 0x80 + st->pa->callref;
- l3_message(st, MT_CONNECT);
- newl3state(st, 8);
-}
-
-static void
-l3s17(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
- newl3state(st, 10);
-}
-
-static void
-l3s18(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
- int size;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
- size = st->l2.ihsize;
-
- *p++ = 0x8;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_DISCONNECT;
- size += 4;
-
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = 0x90;
- size += 4;
-
- dibh->datasize = size;
- i_down(st, dibh);
-
- newl3state(st, 11);
-}
-
-static void
-l3s19(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 0);
- l3_message(st, MT_RELEASE_COMPLETE);
- st->l3.l3l4(st, CC_RELEASE_IND, NULL);
-}
-
-static void
-l3s20(struct PStack *st, byte pr,
- void *arg)
-{
- l3_message(st, MT_ALERTING);
- newl3state(st, 7);
-}
-
-static void
-l3s21(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *dibh=arg;
- byte *p;
- int size;
-
- BufPoolRelease(dibh);
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
- size = st->l2.ihsize;
-
- *p++ = 0x8;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_STATUS;
- size += 4;
-
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = 0x9E; /* answer status enquire */
- size += 4;
-
- *p++ = 0x14; /* CallState */
- *p++ = 0x1;
- *p++ = st->l3.state & 0x3f; /* ISO L3 CallState */
- size += 3;
-
- dibh->datasize = size;
- i_down(st, dibh);
-
-}
-
-struct stateentry {
- int state;
- byte primitive;
- void (*rout) (struct PStack *, byte, void *);
-};
-
-static struct stateentry downstatelist[] =
-{
- {0,CC_SETUP_REQ,l3s5},
- {1,CC_DISCONNECT_REQ,l3s18},
- {1,CC_RELEASE_REQ,l3s3},
- {1,CC_DLRL,l3s13},
- {3,CC_DISCONNECT_REQ,l3s18},
- {3,CC_RELEASE_REQ,l3s3},
- {3,CC_DLRL,l3s13},
- {4,CC_RELEASE_REQ,l3s3},
- {4,CC_DISCONNECT_REQ,l3s18},
- {4,CC_DLRL,l3s13},
- {6,CC_RELEASE_REQ,l3s3},
- {6,CC_DISCONNECT_REQ,l3s18},
- {6,CC_ALERTING_REQ,l3s20},
- {6,CC_DLRL,l3s13},
- {7,CC_RELEASE_REQ,l3s3},
- {7,CC_SETUP_RSP,l3s16},
- {7,CC_DLRL,l3s13},
- {8,CC_RELEASE_REQ,l3s3},
- {8,CC_DISCONNECT_REQ,l3s18},
- {8,CC_DLRL,l3s13},
- {10,CC_DISCONNECT_REQ,l3s18},
- {10,CC_RELEASE_REQ,l3s3},
- {10,CC_DLRL,l3s13},
- {11,CC_RELEASE_REQ,l3s3},
- {12,CC_RELEASE_REQ,l3s3},
- {19,CC_DLRL,l3s13},
-};
-
-static int downsllen = sizeof(downstatelist) /
-sizeof(struct stateentry);
-
-static struct stateentry datastatelist[] =
-{
- {0,MT_STATUS_ENQUIRY,l3s21},
- {0,MT_SETUP,l3s12},
- {1,MT_STATUS_ENQUIRY,l3s21},
- {1,MT_CALL_PROCEEDING,l3s6},
- {1,MT_SETUP_ACKNOWLEDGE,l3s6},
- {1,MT_RELEASE_COMPLETE,l3s4},
- {1,MT_RELEASE,l3s19},
- {1,MT_DISCONNECT,l3s7},
- {3,MT_STATUS_ENQUIRY,l3s21},
- {3,MT_DISCONNECT,l3s7},
- {3,MT_CONNECT,l3s8},
- {3,MT_ALERTING,l3s11},
- {3,MT_RELEASE,l3s19},
- {3,MT_RELEASE_COMPLETE,l3s4},
- {4,MT_STATUS_ENQUIRY,l3s21},
- {4,MT_CONNECT,l3s8},
- {4,MT_DISCONNECT,l3s7},
- {4,MT_RELEASE,l3s19},
- {4,MT_RELEASE_COMPLETE,l3s4},
- {8,MT_STATUS_ENQUIRY,l3s21},
- {6,MT_SETUP,l3s12},
- {8,MT_STATUS_ENQUIRY,l3s21},
- {7,MT_RELEASE,l3s19},
- {7,MT_RELEASE_COMPLETE,l3s4_1},
- {7,MT_DISCONNECT,l3s7},
- {8,MT_STATUS_ENQUIRY,l3s21},
- {8,MT_RELEASE,l3s19},
- {8,MT_CONNECT_ACKNOWLEDGE,l3s17},
- {8,MT_DISCONNECT,l3s7},
- {8,MT_RELEASE_COMPLETE,l3s4_1},
- {10,MT_STATUS_ENQUIRY,l3s21},
- {10,MT_DISCONNECT,l3s7},
- {10,MT_RELEASE,l3s19},
- {10,MT_RELEASE_COMPLETE,l3s4_1},
- {11,MT_STATUS_ENQUIRY,l3s21},
- {11,MT_RELEASE,l3s19},
- {11,MT_RELEASE_COMPLETE,l3s4},
- {19,MT_STATUS_ENQUIRY,l3s21},
- {19,MT_RELEASE_COMPLETE,l3s4},
-};
-
-static int datasllen = sizeof(datastatelist) /
-sizeof(struct stateentry);
-
-#ifdef P_1TR6
-#include "l3_1TR6.c"
-#endif
-
-static void
-l3up(struct PStack *st,
- int pr, void *arg)
-{
- int i, mt, size;
- byte *ptr;
- struct BufHeader *ibh = arg;
-
- if (pr == DL_DATA) {
- ptr = DATAPTR(ibh);
- ptr += st->l2.ihsize;
- size = ibh->datasize - st->l2.ihsize;
- mt = ptr[3];
- switch (ptr[0]) {
-#ifdef P_1TR6
- case PROTO_DIS_N0:
- BufPoolRelease(ibh);
- break;
- case PROTO_DIS_N1:
- for (i = 0; i < datasl_1tr6t_len; i++)
- if ((st->l3.state == datastatelist_1tr6t[i].state) &&
- (mt == datastatelist_1tr6t[i].primitive))
- break;
- if (i == datasl_1tr6t_len) {
- BufPoolRelease(ibh);
- if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n",
- st->l3.state, mt);
- } else
- datastatelist_1tr6t[i].rout(st, pr, ibh);
- break;
-#endif
- case PROTO_EURO: /* E-DSS1 */
- for (i = 0; i < datasllen; i++)
- if ((st->l3.state == datastatelist[i].state) &&
- (mt == datastatelist[i].primitive))
- break;
- if (i == datasllen) {
- BufPoolRelease(ibh);
- if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n",
- st->l3.state, mt);
- } else
- datastatelist[i].rout(st, pr, ibh);
- break;
- default:
- BufPoolRelease(ibh);
- break;
- }
- } else if (pr == DL_UNIT_DATA) {
- ptr = DATAPTR(ibh);
- ptr += st->l2.uihsize;
- size = ibh->datasize - st->l2.uihsize;
- mt = ptr[3];
- switch (ptr[0]) {
-#ifdef P_1TR6
- case PROTO_DIS_N0:
- BufPoolRelease(ibh);
- break;
- case PROTO_DIS_N1:
- for (i = 0; i < datasl_1tr6t_len; i++)
- if ((st->l3.state == datastatelist_1tr6t[i].state) &&
- (mt == datastatelist_1tr6t[i].primitive))
- break;
- if (i == datasl_1tr6t_len) {
- if (DEBUG_1TR6 > 0) {
- printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n"
- ,st->l3.state, mt);
- }
- BufPoolRelease(ibh);
- } else
- datastatelist_1tr6t[i].rout(st, pr, ibh);
- break;
-#endif
- case PROTO_EURO: /* E-DSS1 */
- for (i = 0; i < datasllen; i++)
- if ((st->l3.state == datastatelist[i].state) &&
- (mt == datastatelist[i].primitive))
- break;
- if (i == datasllen) {
- BufPoolRelease(ibh);
- if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n",
- st->l3.state, mt);
- } else
- datastatelist[i].rout(st, pr, ibh);
- break;
- default:
- BufPoolRelease(ibh);
- break;
- }
- }
-}
-
-static void
-l3down(struct PStack *st,
- int pr, void *arg)
-{
- int i;
- struct BufHeader *ibh = arg;
-
- switch (st->protocol) {
-#ifdef P_1TR6
- case ISDN_PTYPE_1TR6:
- for (i = 0; i < downsl_1tr6t_len; i++)
- if ((st->l3.state == downstatelist_1tr6t[i].state) &&
- (pr == downstatelist_1tr6t[i].primitive))
- break;
- if (i == downsl_1tr6t_len) {
- if (DEBUG_1TR6 > 0) {
- printk(KERN_INFO "isdnl3down unhandled 1tr6 state %d primitive %x\n", st->l3.state, pr);
- }
- } else
- downstatelist_1tr6t[i].rout(st, pr, ibh);
- break;
-#endif
- default:
- for (i = 0; i < downsllen; i++)
- if ((st->l3.state == downstatelist[i].state) &&
- (pr == downstatelist[i].primitive))
- break;
- if (i == downsllen) {
- if (DEBUG_1TR6 > 0) {
- printk(KERN_INFO "isdnl3down unhandled E-DSS1 state %d primitive %x\n", st->l3.state, pr);
- }
- } else
- downstatelist[i].rout(st, pr, ibh);
- }
-}
-
-void
-setstack_isdnl3(struct PStack *st)
-{
- st->l4.l4l3 = l3down;
- st->l2.l2l3 = l3up;
- st->l3.state = 0;
- st->l3.callref = 0;
- st->l3.debug = 0;
-}
diff --git a/drivers/isdn/teles/l3_1TR6.c b/drivers/isdn/teles/l3_1TR6.c
deleted file mode 100644
index 8566a14d4..000000000
--- a/drivers/isdn/teles/l3_1TR6.c
+++ /dev/null
@@ -1,538 +0,0 @@
-/* $Id: l3_1TR6.c,v 1.7 1997/02/11 01:38:55 keil Exp $
- *
- * $Log: l3_1TR6.c,v $
- * Revision 1.7 1997/02/11 01:38:55 keil
- * Changed setup-interface (incoming and outgoing)
- *
- * Revision 1.6 1996/09/25 18:34:57 keil
- * missing states in 1TR6 Statemachine added
- *
- * Revision 1.5 1996/09/23 01:53:51 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.4 1996/06/06 14:22:28 fritz
- * Changed level of "non-digital call..." message, since
- * with audio support, this is quite normal.
- *
- * Revision 1.3 1996/04/30 21:54:42 isdn4dev
- * SPV, callback , remove some debugging code Karsten Keil
- *
- * Revision 1.2 1996/04/20 16:47:23 fritz
- * Changed statemachine to allow reject of an incoming call.
- * Report all incoming calls, not just those with Service = 7.
- * Misc. typos
- *
- * Revision 1.1 1996/04/13 10:25:16 fritz
- * Initial revision
- *
- *
- */
-
-#include "proto.h"
-
-static void
-l3_1TR6_message(struct PStack *st, int mt, int pd)
-{
- struct BufHeader *dibh;
- byte *p;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = pd;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = mt;
-
- dibh->datasize = p - DATAPTR(dibh);
- i_down(st, dibh);
-}
-
-static void
-l3_1tr6_setup(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
- char *teln;
-
- st->l3.callref = st->pa->callref;
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = PROTO_DIS_N1;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_N1_SETUP;
-
- if ('S' == (st->pa->setup.phone[0] & 0x5f)) { /* SPV ??? */
- /* NSF SPV */
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_SPV; /* SPV */
- *p++ = st->pa->setup.si1; /* 0 for all Services */
- *p++ = st->pa->setup.si2; /* 0 for all Services */
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_Activate; /* aktiviere SPV (default) */
- *p++ = st->pa->setup.si1; /* 0 for all Services */
- *p++ = st->pa->setup.si2; /* 0 for all Services */
- }
- if (st->pa->setup.eazmsn[0]) {
- *p++ = WE0_origAddr;
- *p++ = strlen(st->pa->setup.eazmsn) + 1;
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- teln = st->pa->setup.eazmsn;
- while (*teln)
- *p++ = *teln++ & 0x7f;
- }
- *p++ = WE0_destAddr;
- teln = st->pa->setup.phone;
- if ('S' != (st->pa->setup.phone[0] & 0x5f)) { /* Keine SPV ??? */
- *p++ = strlen(st->pa->setup.phone) + 1;
- st->pa->spv = 0;
- } else { /* SPV */
- *p++ = strlen(st->pa->setup.phone);
- teln++; /* skip S */
- st->pa->spv = 1;
- }
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- while (*teln)
- *p++ = *teln++ & 0x7f;
-
- *p++ = WE_Shift_F6;
- /* Codesatz 6 fuer Service */
- *p++ = WE6_serviceInd;
- *p++ = 2; /* len=2 info,info2 */
- *p++ = st->pa->setup.si1;
- *p++ = st->pa->setup.si2;
-
- dibh->datasize = p - DATAPTR(dibh);
-
- newl3state(st, 1);
- i_down(st, dibh);
-
-}
-
-static void
-l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- p += st->l2.uihsize;
- st->pa->callref = getcallref(p);
- st->l3.callref = 0x80 + st->pa->callref;
-
- /* Channel Identification */
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- WE0_chanID, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- } else
- printk(KERN_INFO "l3tu_setup: Channel ident not found\n");
-
- p = DATAPTR(ibh);
-
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, WE6_serviceInd, 6))) {
- st->pa->setup.si1 = p[2];
- st->pa->setup.si2 = p[3];
- } else
- printk(KERN_INFO "l3s12(1TR6): ServiceIndicator not found\n");
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- WE0_destAddr, 0)))
- iecpy(st->pa->setup.eazmsn, p, 1);
- else
- strcpy(st->pa->setup.eazmsn, "");
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- WE0_origAddr, 0))) {
- iecpy(st->pa->setup.phone, p, 1);
- } else
- strcpy(st->pa->setup.phone, "");
-
- p = DATAPTR(ibh);
- st->pa->spv = 0;
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- WE0_netSpecFac, 0))) {
- if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
- st->pa->spv = 1;
- }
- BufPoolRelease(ibh);
-
- /* Signal all services, linklevel takes care of Service-Indicator */
- if (st->pa->setup.si1 != 7) {
- printk(KERN_DEBUG "non-digital call: %s -> %s\n",
- st->pa->setup.phone,
- st->pa->setup.eazmsn);
- }
- newl3state(st, 6);
- st->l3.l3l4(st, CC_SETUP_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_setup_ack(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE0_chanID, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- } else
- printk(KERN_INFO "octect 3 not found\n");
-
-
- BufPoolRelease(ibh);
- newl3state(st, 2);
-}
-
-static void
-l3_1tr6_tu_call_sent(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE0_chanID, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- } else
- printk(KERN_INFO "octect 3 not found\n");
-
- BufPoolRelease(ibh);
- newl3state(st, 3);
- st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_alert(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE6_statusCalled, 6))) {
- if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "status called %x\n", p[2]);
- } else if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "statusCalled not found\n");
-
- BufPoolRelease(ibh);
- newl3state(st, 4);
- st->l3.l3l4(st, CC_ALERTING_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_info(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- int i,tmpcharge=0;
- char a_charge[8];
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE6_chargingInfo, 6))) {
- iecpy(a_charge, p, 1);
- for (i = 0; i < strlen (a_charge); i++) {
- tmpcharge *= 10;
- tmpcharge += a_charge[i] & 0xf;
- }
- if (tmpcharge > st->pa->chargeinfo) {
- st->pa->chargeinfo = tmpcharge;
- st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
- }
- if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo);
- } else if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "chargingInfo not found\n");
-
- BufPoolRelease(ibh);
-}
-
-static void
-l3_1tr6_tu_info_s2(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- int i;
- struct BufHeader *ibh = arg;
-
- if (DEBUG_1TR6 > 4) {
- p = DATAPTR(ibh);
- for (i = 0; i < ibh->datasize; i++) {
- printk(KERN_INFO "Info DATA %x\n", p[i]);
- }
- }
- BufPoolRelease(ibh);
-}
-
-static void
-l3_1tr6_tu_connect(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- st->pa->chargeinfo=0;
- BufPoolRelease(ibh);
- st->l3.l3l4(st, CC_SETUP_CNF, NULL);
- newl3state(st, 10);
-}
-
-static void
-l3_1tr6_tu_rel(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1);
- st->l3.l3l4(st, CC_RELEASE_IND, NULL);
- newl3state(st, 0);
-}
-
-static void
-l3_1tr6_tu_rel_ack(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 0);
- st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3_1tr6_tu_disc(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
- byte *p;
- int i,tmpcharge=0;
- char a_charge[8];
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE6_chargingInfo, 6))) {
- iecpy(a_charge, p, 1);
- for (i = 0; i < strlen (a_charge); i++) {
- tmpcharge *= 10;
- tmpcharge += a_charge[i] & 0xf;
- }
- if (tmpcharge > st->pa->chargeinfo) {
- st->pa->chargeinfo = tmpcharge;
- st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
- }
- if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo);
- } else if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "chargingInfo not found\n");
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE0_cause, 0))) {
- if (p[1] > 0) {
- st->pa->cause = p[2];
- } else {
- st->pa->cause = 0;
- }
- if (DEBUG_1TR6 > 1)
- printk(KERN_INFO "Cause %x\n", st->pa->cause);
- } else if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "Cause not found\n");
-
- BufPoolRelease(ibh);
- newl3state(st, 12);
- st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
-}
-
-
-static void
-l3_1tr6_tu_connect_ack(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- st->pa->chargeinfo = 0;
- st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
- newl3state(st, 10);
-}
-
-static void
-l3_1tr6_alert(struct PStack *st, byte pr,
- void *arg)
-{
- l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1);
- newl3state(st, 7);
-}
-
-static void
-l3_1tr6_conn(struct PStack *st, byte pr,
- void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
-
- st->l3.callref = 0x80 + st->pa->callref;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = PROTO_DIS_N1;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_N1_CONN;
-
- if (st->pa->spv) { /* SPV ??? */
- /* NSF SPV */
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_SPV; /* SPV */
- *p++ = st->pa->setup.si1;
- *p++ = st->pa->setup.si2;
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_Activate; /* aktiviere SPV */
- *p++ = st->pa->setup.si1;
- *p++ = st->pa->setup.si2;
- }
- dibh->datasize = p - DATAPTR(dibh);
-
- i_down(st, dibh);
-
- newl3state(st, 8);
-}
-
-static void
-l3_1tr6_reset(struct PStack *st, byte pr, void *arg)
-{
- newl3state(st, 0);
-}
-
-static void
-l3_1tr6_disconn_req(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
- byte rejflg;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 21);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = PROTO_DIS_N1;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_N1_DISC;
-
- if (st->l3.state == 7) {
- rejflg = 1;
- *p++ = WE0_cause; /* Anruf abweisen */
- *p++ = 0x01; /* Laenge = 1 */
- *p++ = CAUSE_CallRejected;
- } else {
- rejflg = 0;
- *p++ = WE0_cause;
- *p++ = 0x0; /* Laenge = 0 normales Ausloesen */
- }
-
- dibh->datasize = p - DATAPTR(dibh);
-
- i_down(st, dibh);
-
- newl3state(st, 11);
-}
-
-static void
-l3_1tr6_rel_req(struct PStack *st, byte pr, void *arg)
-{
- l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1);
- newl3state(st, 19);
-}
-
-static struct stateentry downstatelist_1tr6t[] =
-{
- {0, CC_SETUP_REQ, l3_1tr6_setup},
- {1, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {1, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {1, CC_DLRL, l3_1tr6_reset},
- {2, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {2, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {2, CC_DLRL, l3_1tr6_reset},
- {3, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {3, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {3, CC_DLRL, l3_1tr6_reset},
- {4, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {4, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {4, CC_DLRL, l3_1tr6_reset},
- {6, CC_REJECT_REQ, l3_1tr6_reset},
- {6, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {6, CC_SETUP_RSP, l3_1tr6_conn},
- {6, CC_ALERTING_REQ, l3_1tr6_alert},
- {6, CC_DLRL, l3_1tr6_reset},
- {7, CC_SETUP_RSP, l3_1tr6_conn},
- {7, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {7, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {7, CC_DLRL, l3_1tr6_reset},
- {8, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {8, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {8, CC_DLRL, l3_1tr6_reset},
- {10, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {10, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {10, CC_DLRL, l3_1tr6_reset},
- {12, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {12, CC_DLRL, l3_1tr6_reset},
- {19, CC_DLRL, l3_1tr6_reset},
-};
-
-static int downsl_1tr6t_len = sizeof(downstatelist_1tr6t) /
-sizeof(struct stateentry);
-
-static struct stateentry datastatelist_1tr6t[] =
-{
- {0, MT_N1_SETUP, l3_1tr6_tu_setup},
- {0, MT_N1_REL, l3_1tr6_tu_rel},
- {1, MT_N1_SETUP_ACK, l3_1tr6_tu_setup_ack},
- {1, MT_N1_CALL_SENT, l3_1tr6_tu_call_sent},
- {1, MT_N1_REL, l3_1tr6_tu_rel},
- {1, MT_N1_DISC, l3_1tr6_tu_disc},
- {2, MT_N1_CALL_SENT, l3_1tr6_tu_call_sent},
- {2, MT_N1_ALERT, l3_1tr6_tu_alert},
- {2, MT_N1_CONN, l3_1tr6_tu_connect},
- {2, MT_N1_REL, l3_1tr6_tu_rel},
- {2, MT_N1_DISC, l3_1tr6_tu_disc},
- {2, MT_N1_INFO, l3_1tr6_tu_info_s2},
- {3, MT_N1_ALERT, l3_1tr6_tu_alert},
- {3, MT_N1_CONN, l3_1tr6_tu_connect},
- {3, MT_N1_REL, l3_1tr6_tu_rel},
- {3, MT_N1_DISC, l3_1tr6_tu_disc},
- {4, MT_N1_ALERT, l3_1tr6_tu_alert},
- {4, MT_N1_CONN, l3_1tr6_tu_connect},
- {4, MT_N1_REL, l3_1tr6_tu_rel},
- {4, MT_N1_DISC, l3_1tr6_tu_disc},
- {7, MT_N1_REL, l3_1tr6_tu_rel},
- {7, MT_N1_DISC, l3_1tr6_tu_disc},
- {8, MT_N1_REL, l3_1tr6_tu_rel},
- {8, MT_N1_DISC, l3_1tr6_tu_disc},
- {8, MT_N1_CONN_ACK, l3_1tr6_tu_connect_ack},
- {10, MT_N1_REL, l3_1tr6_tu_rel},
- {10, MT_N1_DISC, l3_1tr6_tu_disc},
- {10, MT_N1_INFO, l3_1tr6_tu_info},
- {11, MT_N1_REL, l3_1tr6_tu_rel},
- {12, MT_N1_REL, l3_1tr6_tu_rel},
- {19, MT_N1_REL_ACK, l3_1tr6_tu_rel_ack}
-};
-
-static int datasl_1tr6t_len = sizeof(datastatelist_1tr6t) /
-sizeof(struct stateentry);
diff --git a/drivers/isdn/teles/l3_1TR6.h b/drivers/isdn/teles/l3_1TR6.h
deleted file mode 100644
index e3b538e26..000000000
--- a/drivers/isdn/teles/l3_1TR6.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/* $Id: l3_1TR6.h,v 1.4 1996/09/23 01:53:52 fritz Exp $
- *
- * $Log: l3_1TR6.h,v $
- * Revision 1.4 1996/09/23 01:53:52 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.3 1996/04/30 21:53:48 isdn4dev
- * Bugs, SPV, Logging in q931.c Karsten Keil
- *
- * Revision 1.1 1996/04/13 10:25:42 fritz
- * Initial revision
- *
- *
- */
-#ifndef l3_1TR6
-#define l3_1TR6
-
-/*
- * MsgType N0
- */
-#define MT_N0_REG_IND 0x61
-#define MT_N0_CANC_IND 0x62
-#define MT_N0_FAC_STA 0x63
-#define MT_N0_STA_ACK 0x64
-#define MT_N0_STA_REJ 0x65
-#define MT_N0_FAC_INF 0x66
-#define MT_N0_INF_ACK 0x67
-#define MT_N0_INF_REJ 0x68
-#define MT_N0_CLOSE 0x75
-#define MT_N0_CLO_ACK 0x77
-
-
-/*
- * MsgType N1
- */
-
-#define MT_N1_ESC 0x00
-#define MT_N1_ALERT 0x01
-#define MT_N1_CALL_SENT 0x02
-#define MT_N1_CONN 0x07
-#define MT_N1_CONN_ACK 0x0F
-#define MT_N1_SETUP 0x05
-#define MT_N1_SETUP_ACK 0x0D
-#define MT_N1_RES 0x26
-#define MT_N1_RES_ACK 0x2E
-#define MT_N1_RES_REJ 0x22
-#define MT_N1_SUSP 0x25
-#define MT_N1_SUSP_ACK 0x2D
-#define MT_N1_SUSP_REJ 0x21
-#define MT_N1_USER_INFO 0x20
-#define MT_N1_DET 0x40
-#define MT_N1_DISC 0x45
-#define MT_N1_REL 0x4D
-#define MT_N1_REL_ACK 0x5A
-#define MT_N1_CANC_ACK 0x6E
-#define MT_N1_CANC_REJ 0x67
-#define MT_N1_CON_CON 0x69
-#define MT_N1_FAC 0x60
-#define MT_N1_FAC_ACK 0x68
-#define MT_N1_FAC_CAN 0x66
-#define MT_N1_FAC_REG 0x64
-#define MT_N1_FAC_REJ 0x65
-#define MT_N1_INFO 0x6D
-#define MT_N1_REG_ACK 0x6C
-#define MT_N1_REG_REJ 0x6F
-#define MT_N1_STAT 0x63
-
-
-
-/*
- * W Elemente
- */
-
-#define WE_Shift_F0 0x90
-#define WE_Shift_F6 0x96
-#define WE_Shift_OF0 0x98
-#define WE_Shift_OF6 0x9E
-
-#define WE0_cause 0x08
-#define WE0_connAddr 0x0C
-#define WE0_callID 0x10
-#define WE0_chanID 0x18
-#define WE0_netSpecFac 0x20
-#define WE0_display 0x28
-#define WE0_keypad 0x2C
-#define WE0_origAddr 0x6C
-#define WE0_destAddr 0x70
-#define WE0_userInfo 0x7E
-
-#define WE0_moreData 0xA0
-#define WE0_congestLevel 0xB0
-
-#define WE6_serviceInd 0x01
-#define WE6_chargingInfo 0x02
-#define WE6_date 0x03
-#define WE6_facSelect 0x05
-#define WE6_facStatus 0x06
-#define WE6_statusCalled 0x07
-#define WE6_addTransAttr 0x08
-
-/*
- * FacCodes
- */
-#define FAC_Sperre 0x01
-#define FAC_Sperre_All 0x02
-#define FAC_Sperre_Fern 0x03
-#define FAC_Sperre_Intl 0x04
-#define FAC_Sperre_Interk 0x05
-
-#define FAC_Forward1 0x02
-#define FAC_Forward2 0x03
-#define FAC_Konferenz 0x06
-#define FAC_GrabBchan 0x0F
-#define FAC_Reactivate 0x10
-#define FAC_Konferenz3 0x11
-#define FAC_Dienstwechsel1 0x12
-#define FAC_Dienstwechsel2 0x13
-#define FAC_NummernIdent 0x14
-#define FAC_GBG 0x15
-#define FAC_DisplayUebergeben 0x17
-#define FAC_DisplayUmgeleitet 0x1A
-#define FAC_Unterdruecke 0x1B
-#define FAC_Deactivate 0x1E
-#define FAC_Activate 0x1D
-#define FAC_SPV 0x1F
-#define FAC_Rueckwechsel 0x23
-#define FAC_Umleitung 0x24
-
-/*
- * Cause codes
- */
-#define CAUSE_InvCRef 0x01
-#define CAUSE_BearerNotImpl 0x03
-#define CAUSE_CIDunknown 0x07
-#define CAUSE_CIDinUse 0x08
-#define CAUSE_NoChans 0x0A
-#define CAUSE_FacNotImpl 0x10
-#define CAUSE_FacNotSubscr 0x11
-#define CAUSE_OutgoingBarred 0x20
-#define CAUSE_UserAccessBusy 0x21
-#define CAUSE_NegativeGBG 0x22
-#define CAUSE_UnknownGBG 0x23
-#define CAUSE_NoSPVknown 0x25
-#define CAUSE_DestNotObtain 0x35
-#define CAUSE_NumberChanged 0x38
-#define CAUSE_OutOfOrder 0x39
-#define CAUSE_NoUserResponse 0x3A
-#define CAUSE_UserBusy 0x3B
-#define CAUSE_IncomingBarred 0x3D
-#define CAUSE_CallRejected 0x3E
-#define CAUSE_NetworkCongestion 0x59
-#define CAUSE_RemoteUser 0x5A
-#define CAUSE_LocalProcErr 0x70
-#define CAUSE_RemoteProcErr 0x71
-#define CAUSE_RemoteUserSuspend 0x72
-#define CAUSE_RemoteUserResumed 0x73
-#define CAUSE_UserInfoDiscarded 0x7F
-
-
-#endif
diff --git a/drivers/isdn/teles/llglue.c b/drivers/isdn/teles/llglue.c
deleted file mode 100644
index 7e32c2f4f..000000000
--- a/drivers/isdn/teles/llglue.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/* $Id: llglue.c,v 1.7 1996/10/22 23:14:17 fritz Exp $
- *
- * $Log: llglue.c,v $
- * Revision 1.7 1996/10/22 23:14:17 fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.6 1996/06/03 20:03:39 fritz
- * Fixed typos.
- *
- * Revision 1.5 1996/05/31 00:58:47 fritz
- * Errata: Reverted change from rev 1.4.
- *
- * Revision 1.4 1996/05/26 14:59:57 fritz
- * Bugfix: maxbufsize had been set without respect to possible X.75 header.
- *
- * Revision 1.3 1996/05/01 14:19:57 fritz
- * Added ISDN_FEATURE_L2_TRANS
- *
- * Revision 1.2 1996/04/29 23:01:46 fritz
- * Added driverId and channel to readstatus().
- *
- * Revision 1.1 1996/04/13 10:26:29 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-#include <linux/malloc.h>
-#include <linux/timer.h>
-
-
-extern struct Channel *chanlist;
-int drid;
-char *teles_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
-
-isdn_if iif;
-
-#define TELES_STATUS_BUFSIZE 4096
-static byte *teles_status_buf = NULL;
-static byte *teles_status_read = NULL;
-static byte *teles_status_write = NULL;
-static byte *teles_status_end = NULL;
-
-int
-teles_readstatus(byte * buf, int len, int user, int id, int channel)
-{
- int count;
- byte *p;
-
- for (p = buf, count = 0; count < len; p++, count++) {
- if (user)
- put_user(*teles_status_read++, p);
- else
- *p++ = *teles_status_read++;
- if (teles_status_read > teles_status_end)
- teles_status_read = teles_status_buf;
- }
- return count;
-}
-
-void
-teles_putstatus(char *buf)
-{
- long flags;
- int len, count, i;
- byte *p;
- isdn_ctrl ic;
-
- save_flags(flags);
- cli();
- count = 0;
- len = strlen(buf);
- for (p = buf, i = len; i > 0; i--, p++) {
- *teles_status_write++ = *p;
- if (teles_status_write > teles_status_end)
- teles_status_write = teles_status_buf;
- count++;
- }
- restore_flags(flags);
- if (count) {
- ic.command = ISDN_STAT_STAVAIL;
- ic.driver = drid;
- ic.arg = count;
- iif.statcallb(&ic);
- }
-}
-
-
-int
-ll_init(void)
-{
- isdn_ctrl ic;
-
- teles_status_buf = Smalloc(TELES_STATUS_BUFSIZE,
- GFP_KERNEL, "teles_status_buf");
- if (!teles_status_buf) {
- printk(KERN_ERR "teles: Could not allocate status-buffer\n");
- return (-EIO);
- } else {
- teles_status_read = teles_status_buf;
- teles_status_write = teles_status_buf;
- teles_status_end = teles_status_buf + TELES_STATUS_BUFSIZE - 1;
- }
-
- iif.channels = CallcNewChan();
- iif.maxbufsize = BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS);
- iif.features =
- ISDN_FEATURE_L2_X75I |
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L2_TRANS |
- ISDN_FEATURE_L3_TRANS |
- ISDN_FEATURE_P_1TR6 |
- ISDN_FEATURE_P_EURO;
-
- iif.command = teles_command;
- iif.writebuf = teles_writebuf;
- iif.writecmd = NULL;
- iif.readstat = teles_readstatus;
- strncpy(iif.id, teles_id, sizeof(iif.id) - 1);
-
- register_isdn(&iif);
- drid = iif.channels;
-
- ic.driver = drid;
- ic.command = ISDN_STAT_RUN;
- iif.statcallb(&ic);
- return 0;
-}
-
-void
-ll_stop(void)
-{
- isdn_ctrl ic;
-
- ic.command = ISDN_STAT_STOP;
- ic.driver = drid;
- iif.statcallb(&ic);
-
- CallcFreeChan();
-}
-
-void
-ll_unload(void)
-{
- isdn_ctrl ic;
-
- ic.command = ISDN_STAT_UNLOAD;
- ic.driver = drid;
- iif.statcallb(&ic);
-}
diff --git a/drivers/isdn/teles/mod.c b/drivers/isdn/teles/mod.c
deleted file mode 100644
index d5486bd4b..000000000
--- a/drivers/isdn/teles/mod.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/* $Id: mod.c,v 1.3 1997/02/14 12:23:31 fritz Exp $
- *
- * $Log: mod.c,v $
- * Revision 1.3 1997/02/14 12:23:31 fritz
- * Added support for new insmod parameter handling.
- *
- * Revision 1.2 1997/02/10 11:45:14 fritz
- * More changes for Kernel 2.1.X compatibility.
- *
- * Revision 1.1 1996/04/13 10:27:02 fritz
- * Initial revision
- *
- *
- */
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern char *teles_id;
-
-int nrcards;
-
-typedef struct {
- byte *membase;
- int interrupt;
- unsigned int iobase;
- unsigned int protocol;
-} io_type;
-
-io_type io[] =
-{
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
-};
-
-#ifdef MODULE
-#if (LINUX_VERSION_CODE > 0x020111)
-MODULE_PARM(io, "1-64i");
-MODULE_PARM(teles_id, "s");
-#endif
-#endif
-
-void
-teles_mod_dec_use_count(void)
-{
- MOD_DEC_USE_COUNT;
-}
-
-void
-teles_mod_inc_use_count(void)
-{
- MOD_INC_USE_COUNT;
-}
-
-#ifdef MODULE
-#define teles_init init_module
-#else
-void teles_setup(char *str, int *ints)
-{
- int i, j, argc;
- static char sid[20];
-
- argc = ints[0];
- i = 0;
- j = 1;
- while (argc && (i<16)) {
- if (argc) {
- io[i].iobase = ints[j];
- j++; argc--;
- }
- if (argc) {
- io[i].interrupt = ints[j];
- j++; argc--;
- }
- if (argc) {
- io[i].membase = (byte *)ints[j];
- j++; argc--;
- }
- if (argc) {
- io[i].protocol = ints[j];
- j++; argc--;
- }
- i++;
- }
- if (strlen(str)) {
- strcpy(sid,str);
- teles_id = sid;
- }
-}
-#endif
-
-int
-teles_init(void)
-{
- int i;
-
- nrcards = 0;
- for (i = 0; i < 16; i++) {
- if (io[i].protocol) {
- cards[i].membase = io[i].membase;
- cards[i].interrupt = io[i].interrupt;
- cards[i].iobase = io[i].iobase;
- cards[i].protocol = io[i].protocol;
- }
- }
- for (i = 0; i < 16; i++)
- if (cards[i].protocol)
- nrcards++;
- printk(KERN_DEBUG "teles: Total %d card%s defined\n",
- nrcards, (nrcards > 1) ? "s" : "");
- if (teles_inithardware()) {
- /* Install only, if at least one card found */
- Isdnl2New();
- TeiNew();
- CallcNew();
- ll_init();
-
- /* No symbols to export, hide all symbols */
-
-#ifdef MODULE
-#if (LINUX_VERSION_CODE < 0x020111)
- register_symtab(NULL);
-#else
- EXPORT_NO_SYMBOLS;
-#endif
- printk(KERN_NOTICE "Teles module installed\n");
-#endif
- return (0);
- } else
- return -EIO;
-}
-
-#ifdef MODULE
-void
-cleanup_module(void)
-{
-
- ll_stop();
- TeiFree();
- Isdnl2Free();
- CallcFree();
- teles_closehardware();
- ll_unload();
- printk(KERN_NOTICE "Teles module removed\n");
-
-}
-#endif
diff --git a/drivers/isdn/teles/proto.h b/drivers/isdn/teles/proto.h
deleted file mode 100644
index 0d7ae8ef4..000000000
--- a/drivers/isdn/teles/proto.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* $Id: proto.h,v 1.1 1996/09/23 01:53:52 fritz Exp $
- *
- * not much now - just the l3 proto discriminator
- *
- * $Log: proto.h,v $
- * Revision 1.1 1996/09/23 01:53:52 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- */
-
-#ifndef PROTO_H
-#define PROTO_H
-
-#define PROTO_EURO 0x08
-#define PROTO_DIS_N0 0x40
-#define PROTO_DIS_N1 0x41
-
-#endif
diff --git a/drivers/isdn/teles/q931.c b/drivers/isdn/teles/q931.c
deleted file mode 100644
index c9f5fa692..000000000
--- a/drivers/isdn/teles/q931.c
+++ /dev/null
@@ -1,1155 +0,0 @@
-/* $Id: q931.c,v 1.6 1996/09/23 01:53:53 fritz Exp $
- *
- * q931.c code to decode ITU Q.931 call control messages
- *
- * Author Jan den Ouden
- *
- * Changelog
- *
- * Pauline Middelink general improvements
- *
- * Beat Doebeli cause texts, display information element
- *
- * Karsten Keil cause texts, display information element for 1TR6
- *
- *
- * $Log: q931.c,v $
- * Revision 1.6 1996/09/23 01:53:53 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.5 1996/06/03 20:03:40 fritz
- * Fixed typos.
- *
- * Revision 1.4 1996/05/17 03:46:17 fritz
- * General cleanup.
- *
- * Revision 1.3 1996/04/30 22:06:50 isdn4dev
- * logging 1TR6 messages correctly Karsten Keil
- *
- * Revision 1.2 1996/04/20 16:48:19 fritz
- * Misc. typos
- *
- * Revision 1.1 1996/04/13 10:27:49 fritz
- * Initial revision
- *
- *
- */
-
-
-#define __NO_VERSION__
-#include "teles.h"
-#include "proto.h"
-#include "l3_1TR6.h"
-
-byte *
-findie(byte * p, int size, byte ie, int wanted_set)
-{
- int l, codeset, maincodeset;
- byte *pend = p + size;
-
- /* skip protocol discriminator, callref and message type */
- p++;
- l = (*p++) & 0xf;
- p += l;
- p++;
- codeset = 0;
- maincodeset = 0;
- /* while there are bytes left... */
- while (p < pend) {
- if ((*p & 0xf0) == 0x90) {
- codeset = *p & 0x07;
- if (!(*p & 0x08))
- maincodeset = codeset;
- }
- if (*p & 0x80)
- p++;
- else {
- if (codeset == wanted_set) {
- if (*p == ie)
- return (p);
- if (*p > ie)
- return (NULL);
- }
- p++;
- l = *p++;
- p += l;
- codeset = maincodeset;
- }
- }
- return (NULL);
-}
-
-void
-iecpy(byte * dest, byte * iestart, int ieoffset)
-{
- byte *p;
- int l;
-
- p = iestart + ieoffset + 2;
- l = iestart[1] - ieoffset;
- while (l--)
- *dest++ = *p++;
- *dest++ = '\0';
-}
-
-int
-getcallref(byte * p)
-{
- p++; /* prot discr */
- p++; /* callref length */
- return (*p); /* assuming one-byte callref */
-}
-
-/*
- * According to Table 4-2/Q.931
- */
-static
-struct MessageType {
- byte nr;
- char *descr;
-} mtlist[] = {
-
- {
- 0x1, "ALERTING"
- },
- {
- 0x2, "CALL PROCEEDING"
- },
- {
- 0x7, "CONNECT"
- },
- {
- 0xf, "CONNECT ACKNOWLEDGE"
- },
- {
- 0x3, "PROGRESS"
- },
- {
- 0x5, "SETUP"
- },
- {
- 0xd, "SETUP ACKNOWLEDGE"
- },
- {
- 0x26, "RESUME"
- },
- {
- 0x2e, "RESUME ACKNOWLEDGE"
- },
- {
- 0x22, "RESUME REJECT"
- },
- {
- 0x25, "SUSPEND"
- },
- {
- 0x2d, "SUSPEND ACKNOWLEDGE"
- },
- {
- 0x21, "SUSPEND REJECT"
- },
- {
- 0x20, "USER INFORMATION"
- },
- {
- 0x45, "DISCONNECT"
- },
- {
- 0x4d, "RELEASE"
- },
- {
- 0x5a, "RELEASE COMPLETE"
- },
- {
- 0x46, "RESTART"
- },
- {
- 0x4e, "RESTART ACKNOWLEDGE"
- },
- {
- 0x60, "SEGMENT"
- },
- {
- 0x79, "CONGESTION CONTROL"
- },
- {
- 0x7b, "INFORMATION"
- },
- {
- 0x62, "FACILITY"
- },
- {
- 0x6e, "NOTIFY"
- },
- {
- 0x7d, "STATUS"
- },
- {
- 0x75, "STATUS ENQUIRY"
- }
-};
-
-#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType)
-
-static
-struct MessageType mt_n0[] =
-{
- {MT_N0_REG_IND, "REGister INDication"},
- {MT_N0_CANC_IND, "CANCel INDication"},
- {MT_N0_FAC_STA, "FACility STAtus"},
- {MT_N0_STA_ACK, "STAtus ACKnowledge"},
- {MT_N0_STA_REJ, "STAtus REJect"},
- {MT_N0_FAC_INF, "FACility INFormation"},
- {MT_N0_INF_ACK, "INFormation ACKnowledge"},
- {MT_N0_INF_REJ, "INFormation REJect"},
- {MT_N0_CLOSE, "CLOSE"},
- {MT_N0_CLO_ACK, "CLOse ACKnowledge"}
-};
-
-int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType));
-
-static
-struct MessageType mt_n1[] =
-{
- {MT_N1_ESC, "ESCape"},
- {MT_N1_ALERT, "ALERT"},
- {MT_N1_CALL_SENT, "CALL SENT"},
- {MT_N1_CONN, "CONNect"},
- {MT_N1_CONN_ACK, "CONNect ACKnowledge"},
- {MT_N1_SETUP, "SETUP"},
- {MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
- {MT_N1_RES, "RESume"},
- {MT_N1_RES_ACK, "RESume ACKnowledge"},
- {MT_N1_RES_REJ, "RESume REJect"},
- {MT_N1_SUSP, "SUSPend"},
- {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
- {MT_N1_SUSP_REJ, "SUSPend REJect"},
- {MT_N1_USER_INFO, "USER INFO"},
- {MT_N1_DET, "DETach"},
- {MT_N1_DISC, "DISConnect"},
- {MT_N1_REL, "RELease"},
- {MT_N1_REL_ACK, "RELease ACKnowledge"},
- {MT_N1_CANC_ACK, "CANCel ACKnowledge"},
- {MT_N1_CANC_REJ, "CANCel REJect"},
- {MT_N1_CON_CON, "CONgestion CONtrol"},
- {MT_N1_FAC, "FACility"},
- {MT_N1_FAC_ACK, "FACility ACKnowledge"},
- {MT_N1_FAC_CAN, "FACility CANcel"},
- {MT_N1_FAC_REG, "FACility REGister"},
- {MT_N1_FAC_REJ, "FACility REJect"},
- {MT_N1_INFO, "INFOrmation"},
- {MT_N1_REG_ACK, "REGister ACKnowledge"},
- {MT_N1_REG_REJ, "REGister REJect"},
- {MT_N1_STAT, "STATus"}
-};
-
-int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType));
-
-static struct MessageType fac_1tr6[] =
-{
- {FAC_Sperre, "Sperre"},
- {FAC_Forward1, "Forward 1"},
- {FAC_Forward2, "Forward 2"},
- {FAC_Konferenz, "Konferenz"},
- {FAC_GrabBchan, "Grab Bchannel"},
- {FAC_Reactivate, "Reactivate"},
- {FAC_Konferenz3, "Dreier Konferenz"},
- {FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"},
- {FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"},
- {FAC_NummernIdent, "Rufnummer-Identifizierung"},
- {FAC_GBG, "GBG"},
- {FAC_DisplayUebergeben, "Display Uebergeben"},
- {FAC_DisplayUmgeleitet, "Display Umgeleitet"},
- {FAC_Unterdruecke, "Unterdruecke Rufnummer"},
- {FAC_Deactivate, "Deactivate"},
- {FAC_Activate, "Activate"},
- {FAC_SPV, "SPV"},
- {FAC_Rueckwechsel, "Rueckwechsel"},
- {FAC_Umleitung, "Umleitung"}
-};
-int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType));
-
-
-
-static int
-prbits(char *dest, byte b, int start, int len)
-{
- char *dp = dest;
-
- b = b << (8 - start);
- while (len--) {
- if (b & 0x80)
- *dp++ = '1';
- else
- *dp++ = '0';
- b = b << 1;
- }
- return (dp - dest);
-}
-
-static
-byte *
-skipext(byte * p)
-{
- while (!(*p++ & 0x80));
- return (p);
-}
-
-/*
- * Cause Values According to Q.850
- * edescr: English description
- * ddescr: German description used by Swissnet II (Swiss Telecom
- * not yet written...
- */
-
-static
-struct CauseValue {
- byte nr;
- char *edescr;
- char *ddescr;
-} cvlist[] = {
-
- {
- 0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt"
- },
- {
- 0x02, "No route to specified transit network", ""
- },
- {
- 0x03, "No route to destination", ""
- },
- {
- 0x04, "Send special information tone", ""
- },
- {
- 0x05, "Misdialled trunk prefix", ""
- },
- {
- 0x06, "Channel unacceptable", "Kanal nicht akzeptierbar"
- },
- {
- 0x07, "Channel awarded and being delivered in an established channel", ""
- },
- {
- 0x08, "Preemption", ""
- },
- {
- 0x09, "Preemption - circuit reserved for reuse", ""
- },
- {
- 0x10, "Normal call clearing", "Normale Ausloesung"
- },
- {
- 0x11, "User busy", "TNB besetzt"
- },
- {
- 0x12, "No user responding", ""
- },
- {
- 0x13, "No answer from user (user alerted)", ""
- },
- {
- 0x14, "Subscriber absent", ""
- },
- {
- 0x15, "Call rejected", ""
- },
- {
- 0x16, "Number changed", ""
- },
- {
- 0x1a, "non-selected user clearing", ""
- },
- {
- 0x1b, "Destination out of order", ""
- },
- {
- 0x1c, "Invalid number format (address incomplete)", ""
- },
- {
- 0x1d, "Facility rejected", ""
- },
- {
- 0x1e, "Response to Status enquiry", ""
- },
- {
- 0x1f, "Normal, unspecified", ""
- },
- {
- 0x22, "No circuit/channel available", ""
- },
- {
- 0x26, "Network out of order", ""
- },
- {
- 0x27, "Permanent frame mode connection out-of-service", ""
- },
- {
- 0x28, "Permanent frame mode connection operational", ""
- },
- {
- 0x29, "Temporary failure", ""
- },
- {
- 0x2a, "Switching equipment congestion", ""
- },
- {
- 0x2b, "Access information discarded", ""
- },
- {
- 0x2c, "Requested circuit/channel not available", ""
- },
- {
- 0x2e, "Precedence call blocked", ""
- },
- {
- 0x2f, "Resource unavailable, unspecified", ""
- },
- {
- 0x31, "Quality of service unavailable", ""
- },
- {
- 0x32, "Requested facility not subscribed", ""
- },
- {
- 0x35, "Outgoing calls barred within CUG", ""
- },
- {
- 0x37, "Incoming calls barred within CUG", ""
- },
- {
- 0x39, "Bearer capability not authorized", ""
- },
- {
- 0x3a, "Bearer capability not presently available", ""
- },
- {
- 0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " "
- },
- {
- 0x3f, "Service or option not available, unspecified", ""
- },
- {
- 0x41, "Bearer capability not implemented", ""
- },
- {
- 0x42, "Channel type not implemented", ""
- },
- {
- 0x43, "Requested facility not implemented", ""
- },
- {
- 0x44, "Only restricted digital information bearer capability is available", ""
- },
- {
- 0x4f, "Service or option not implemented", ""
- },
- {
- 0x51, "Invalid call reference value", ""
- },
- {
- 0x52, "Identified channel does not exist", ""
- },
- {
- 0x53, "A suspended call exists, but this call identity does not", ""
- },
- {
- 0x54, "Call identity in use", ""
- },
- {
- 0x55, "No call suspended", ""
- },
- {
- 0x56, "Call having the requested call identity has been cleared", ""
- },
- {
- 0x57, "User not member of CUG", ""
- },
- {
- 0x58, "Incompatible destination", ""
- },
- {
- 0x5a, "Non-existent CUG", ""
- },
- {
- 0x5b, "Invalid transit network selection", ""
- },
- {
- 0x5f, "Invalid message, unspecified", ""
- },
- {
- 0x60, "Mandatory information element is missing", ""
- },
- {
- 0x61, "Message type non-existent or not implemented", ""
- },
- {
- 0x62, "Message not compatible with call state or message type non-existent or not implemented ", " "
- },
- {
- 0x63, "Information element/parameter non-existent or not implemented", ""
- },
- {
- 0x64, "Invalid information element contents", ""
- },
- {
- 0x65, "Message not compatible with call state", ""
- },
- {
- 0x66, "Recovery on timer expiry", ""
- },
- {
- 0x67, "Parameter non-existent or not implemented - passed on", ""
- },
- {
- 0x6e, "Message with unrecognized parameter discarded", ""
- },
- {
- 0x6f, "Protocol error, unspecified", ""
- },
- {
- 0x7f, "Interworking, unspecified", ""
- },
-};
-
-#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue)
-
-static
-int
-prcause(char *dest, byte * p)
-{
- byte *end;
- char *dp = dest;
- int i, cause;
-
- end = p + p[1] + 1;
- p += 2;
- dp += sprintf(dp, " coding ");
- dp += prbits(dp, *p, 7, 2);
- dp += sprintf(dp, " location ");
- dp += prbits(dp, *p, 4, 4);
- *dp++ = '\n';
- p = skipext(p);
-
- cause = 0x7f & *p++;
-
- /* locate cause value */
- for (i = 0; i < CVSIZE; i++)
- if (cvlist[i].nr == cause)
- break;
-
- /* display cause value if it exists */
- if (i == CVSIZE)
- dp += sprintf(dp, "Unknown cause type %x!\n", cause);
- else
- dp += sprintf(dp, " cause value %x : %s \n", cause, cvlist[i].edescr);
-
- while (!0) {
- if (p > end)
- break;
- dp += sprintf(dp, " diag attribute %d ", *p++ & 0x7f);
- dp += sprintf(dp, " rej %d ", *p & 0x7f);
- if (*p & 0x80) {
- *dp++ = '\n';
- break;
- } else
- dp += sprintf(dp, " av %d\n", (*++p) & 0x7f);
- }
- return (dp - dest);
-
-}
-
-static
-struct MessageType cause_1tr6[] =
-{
- {CAUSE_InvCRef, "Invalid Call Reference"},
- {CAUSE_BearerNotImpl, "Bearer Service Not Implemented"},
- {CAUSE_CIDunknown, "Caller Identity unknown"},
- {CAUSE_CIDinUse, "Caller Identity in Use"},
- {CAUSE_NoChans, "No Channels available"},
- {CAUSE_FacNotImpl, "Facility Not Implemented"},
- {CAUSE_FacNotSubscr, "Facility Not Subscribed"},
- {CAUSE_OutgoingBarred, "Outgoing calls barred"},
- {CAUSE_UserAccessBusy, "User Access Busy"},
- {CAUSE_NegativeGBG, "Negative GBG"},
- {CAUSE_UnknownGBG, "Unknown GBG"},
- {CAUSE_NoSPVknown, "No SPV known"},
- {CAUSE_DestNotObtain, "Destination not obtainable"},
- {CAUSE_NumberChanged, "Number changed"},
- {CAUSE_OutOfOrder, "Out Of Order"},
- {CAUSE_NoUserResponse, "No User Response"},
- {CAUSE_UserBusy, "User Busy"},
- {CAUSE_IncomingBarred, "Incoming Barred"},
- {CAUSE_CallRejected, "Call Rejected"},
- {CAUSE_NetworkCongestion, "Network Congestion"},
- {CAUSE_RemoteUser, "Remote User initiated"},
- {CAUSE_LocalProcErr, "Local Procedure Error"},
- {CAUSE_RemoteProcErr, "Remote Procedure Error"},
- {CAUSE_RemoteUserSuspend, "Remote User Suspend"},
- {CAUSE_RemoteUserResumed, "Remote User Resumed"},
- {CAUSE_UserInfoDiscarded, "User Info Discarded"}
-};
-
-int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
-
-static int
-prcause_1tr6(char *dest, byte * p)
-{
- char *dp = dest;
- int i, cause;
-
- p++;
- if (0 == *p) {
- dp += sprintf(dp, " OK (cause length=0)\n");
- return (dp - dest);
- } else if (*p > 1) {
- dp += sprintf(dp, " coding ");
- dp += prbits(dp, p[2], 7, 2);
- dp += sprintf(dp, " location ");
- dp += prbits(dp, p[2], 4, 4);
- *dp++ = '\n';
- }
- p++;
- cause = 0x7f & *p;
-
- /* locate cause value */
- for (i = 0; i < cause_1tr6_len; i++)
- if (cause_1tr6[i].nr == cause)
- break;
-
- /* display cause value if it exists */
- if (i == cause_1tr6_len)
- dp += sprintf(dp, "Unknown cause type %x!\n", cause);
- else
- dp += sprintf(dp, " cause value %x : %s \n", cause, cause_1tr6[i].descr);
-
- return (dp - dest);
-
-}
-
-static int
-prchident(char *dest, byte * p) {
- char *dp = dest;
-
- p += 2;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- return (dp - dest);
-}
-
-static int
-prcalled(char *dest, byte * p) {
- int l;
- char *dp = dest;
-
- p++;
- l = *p++ - 1;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- dp += sprintf(dp, " number digits ");
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-static int
-prcalling(char *dest, byte * p) {
- int l;
- char *dp = dest;
-
- p++;
- l = *p++ - 1;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- if (!(*p & 0x80)) {
- dp += sprintf(dp, " octet 3a ");
- dp += prbits(dp, *++p, 8, 8);
- *dp++ = '\n';
- l--;
- };
- p++;
-
- dp += sprintf(dp, " number digits ");
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-
-static
-int
-prbearer(char *dest, byte * p)
-{
- char *dp = dest, ch;
-
- p += 2;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- dp += sprintf(dp, " octet 4 ");
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- if ((*p++ & 0x1f) == 0x18) {
- dp += sprintf(dp, " octet 4.1 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- }
- /* check for user information layer 1 */
- if ((*p & 0x60) == 0x20) {
- ch = ' ';
- do {
- dp += sprintf(dp, " octet 5%c ", ch);
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- if (ch == ' ')
- ch = 'a';
- else
- ch++;
- }
- while (!(*p++ & 0x80));
- }
- /* check for user information layer 2 */
- if ((*p & 0x60) == 0x40) {
- dp += sprintf(dp, " octet 6 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- }
- /* check for user information layer 3 */
- if ((*p & 0x60) == 0x60) {
- dp += sprintf(dp, " octet 7 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- }
- return (dp - dest);
-}
-
-static int
-general(char *dest, byte * p) {
- char *dp = dest;
- char ch = ' ';
- int l, octet = 3;
-
- p++;
- l = *p++;
- /* Iterate over all octets in the information element */
- while (l--) {
- dp += sprintf(dp, " octet %d%c ", octet, ch);
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
-
- /* last octet in group? */
- if (*p & 0x80) {
- octet++;
- ch = ' ';
- } else if (ch == ' ')
- ch = 'a';
- else
- ch++;
- }
- return (dp - dest);
-}
-
-static int
-prcharge(char *dest, byte * p) {
- char *dp = dest;
- int l;
-
- p++;
- l = *p++ - 1;
- dp += sprintf(dp, " GEA ");
- dp += prbits(dp, *p++, 8, 8);
- dp += sprintf(dp, " Anzahl: ");
- /* Iterate over all octets in the * information element */
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-static int
-prtext(char *dest, byte * p) {
- char *dp = dest;
- int l;
-
- p++;
- l = *p++;
- dp += sprintf(dp, " ");
- /* Iterate over all octets in the * information element */
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-static int
-display(char *dest, byte * p) {
- char *dp = dest;
- char ch = ' ';
- int l, octet = 3;
-
- p++;
- l = *p++;
- /* Iterate over all octets in the * display-information element */
- dp += sprintf(dp, " \"");
- while (l--) {
- dp += sprintf(dp, "%c", *p++);
-
- /* last octet in group? */
- if (*p & 0x80) {
- octet++;
- ch = ' ';
- } else if (ch == ' ')
- ch = 'a';
-
- else
- ch++;
- }
- *dp++ = '\"';
- *dp++ = '\n';
- return (dp - dest);
-}
-
-int
-prfacility(char *dest, byte * p)
-{
- char *dp = dest;
- int l, l2;
-
- p++;
- l = *p++;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p++, 8, 8);
- dp += sprintf(dp, "\n");
- l -= 1;
-
- while (l > 0) {
- dp += sprintf(dp, " octet 4 ");
- dp += prbits(dp, *p++, 8, 8);
- dp += sprintf(dp, "\n");
- dp += sprintf(dp, " octet 5 %d\n", l2 = *p++ & 0x7f);
- l -= 2;
- dp += sprintf(dp, " contents ");
- while (l2--) {
- dp += sprintf(dp, "%2x ", *p++);
- l--;
- }
- dp += sprintf(dp, "\n");
- }
-
- return (dp - dest);
-}
-
-static
-struct InformationElement {
- byte nr;
- char *descr;
- int (*f) (char *, byte *);
-} ielist[] = {
-
- {
- 0x00, "Segmented message", general
- },
- {
- 0x04, "Bearer capability", prbearer
- },
- {
- 0x08, "Cause", prcause
- },
- {
- 0x10, "Call identity", general
- },
- {
- 0x14, "Call state", general
- },
- {
- 0x18, "Channel identification", prchident
- },
- {
- 0x1c, "Facility", prfacility
- },
- {
- 0x1e, "Progress indicator", general
- },
- {
- 0x20, "Network-specific facilities", general
- },
- {
- 0x27, "Notification indicator", general
- },
- {
- 0x28, "Display", display
- },
- {
- 0x29, "Date/Time", general
- },
- {
- 0x2c, "Keypad facility", general
- },
- {
- 0x34, "Signal", general
- },
- {
- 0x40, "Information rate", general
- },
- {
- 0x42, "End-to-end delay", general
- },
- {
- 0x43, "Transit delay selection and indication", general
- },
- {
- 0x44, "Packet layer binary parameters", general
- },
- {
- 0x45, "Packet layer window size", general
- },
- {
- 0x46, "Packet size", general
- },
- {
- 0x47, "Closed user group", general
- },
- {
- 0x4a, "Reverse charge indication", general
- },
- {
- 0x6c, "Calling party number", prcalling
- },
- {
- 0x6d, "Calling party subaddress", general
- },
- {
- 0x70, "Called party number", prcalled
- },
- {
- 0x71, "Called party subaddress", general
- },
- {
- 0x74, "Redirecting number", general
- },
- {
- 0x78, "Transit network selection", general
- },
- {
- 0x79, "Restart indicator", general
- },
- {
- 0x7c, "Low layer compatibility", general
- },
- {
- 0x7d, "High layer compatibility", general
- },
- {
- 0x7e, "User-user", general
- },
- {
- 0x7f, "Escape for extension", general
- },
-};
-
-
-#define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
-
-static struct InformationElement we_0[] =
-{
- {WE0_cause, "Cause", prcause_1tr6},
- {WE0_connAddr, "Connecting Address", prcalled},
- {WE0_callID, "Call IDentity", general},
- {WE0_chanID, "Channel IDentity", general},
- {WE0_netSpecFac, "Network Specific Facility", general},
- {WE0_display, "Display", general},
- {WE0_keypad, "Keypad", general},
- {WE0_origAddr, "Origination Address", prcalled},
- {WE0_destAddr, "Destination Address", prcalled},
- {WE0_userInfo, "User Info", general}
-};
-
-static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement));
-
-static struct InformationElement we_6[] =
-{
- {WE6_serviceInd, "Service Indicator", general},
- {WE6_chargingInfo, "Charging Information", prcharge},
- {WE6_date, "Date", prtext},
- {WE6_facSelect, "Facility Select", general},
- {WE6_facStatus, "Facility Status", general},
- {WE6_statusCalled, "Status Called", general},
- {WE6_addTransAttr, "Additional Transmission Attributes", general}
-};
-static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement));
-
-void
-dlogframe(struct IsdnCardState *sp, byte * buf, int size, char *comment) {
- byte *bend = buf + size;
- char *dp;
- int i, cs = 0, cs_old = 0, cs_fest = 0;
-
- /* display header */
- dp = sp->dlogspace;
- dp += sprintf(dp, "%s\n", comment);
-
- {
- byte *p = buf;
- dp += sprintf(dp, "hex: ");
- while (p < bend)
- dp += sprintf(dp, "%02x ", *p++);
- dp += sprintf(dp, "\n");
- teles_putstatus(sp->dlogspace);
- dp = sp->dlogspace;
- }
- if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */
- /* locate message type */
- if (buf[0] == PROTO_DIS_N0) { /* N0 */
- for (i = 0; i < mt_n0_len; i++)
- if (mt_n0[i].nr == buf[3])
- break;
- /* display message type iff it exists */
- if (i == mt_n0_len)
- dp += sprintf(dp, "Unknown message type N0 %x!\n", buf[3]);
- else
- dp += sprintf(dp, "call reference %d size %d message type %s\n",
- buf[2], size, mt_n0[i].descr);
- } else { /* N1 */
- for (i = 0; i < mt_n1_len; i++)
- if (mt_n1[i].nr == buf[3])
- break;
- /* display message type iff it exists */
- if (i == mt_n1_len)
- dp += sprintf(dp, "Unknown message type N1 %x!\n", buf[3]);
- else
- dp += sprintf(dp, "call reference %d size %d message type %s\n",
- buf[2], size, mt_n1[i].descr);
- }
-
- /* display each information element */
- buf += 4;
- while (buf < bend) {
- /* Is it a single octet information element? */
- if (*buf & 0x80) {
- switch ((*buf >> 4) & 7) {
- case 1:
- dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
- cs_old = cs;
- cs = *buf & 7;
- cs_fest = *buf & 8;
- break;
- case 3:
- dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf);
- break;
- case 2:
- if (*buf == 0xa0) {
- dp += sprintf(dp, " More data\n");
- break;
- }
- if (*buf == 0xa1) {
- dp += sprintf(dp, " Sending complete\n");
- }
- break;
- /* fall through */
- default:
- dp += sprintf(dp, " Reserved %x\n", *buf);
- break;
- }
- buf++;
- continue;
- }
- /* No, locate it in the table */
- if (cs == 0) {
- for (i = 0; i < we_0_len; i++)
- if (*buf == we_0[i].nr)
- break;
-
- /* When found, give appropriate msg */
- if (i != we_0_len) {
- dp += sprintf(dp, " %s\n", we_0[i].descr);
- dp += we_0[i].f(dp, buf);
- } else
- dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
- } else if (cs == 6) {
- for (i = 0; i < we_6_len; i++)
- if (*buf == we_6[i].nr)
- break;
-
- /* When found, give appropriate msg */
- if (i != we_6_len) {
- dp += sprintf(dp, " %s\n", we_6[i].descr);
- dp += we_6[i].f(dp, buf);
- } else
- dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
- } else
- dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
- /* Skip to next element */
- if (cs_fest == 8) {
- cs = cs_old;
- cs_old = 0;
- cs_fest = 0;
- }
- buf += buf[1] + 2;
- }
- } else if (buf[0]==PROTO_EURO) { /* EURO */
- /* locate message type */
- for (i = 0; i < MTSIZE; i++)
- if (mtlist[i].nr == buf[3])
- break;
-
- /* display message type iff it exists */
- if (i == MTSIZE)
- dp += sprintf(dp, "Unknown message type %x!\n", buf[3]);
- else
- dp += sprintf(dp, "call reference %d size %d message type %s\n",
- buf[2], size, mtlist[i].descr);
-
- /* display each information element */
- buf += 4;
- while (buf < bend) {
- /* Is it a single octet information element? */
- if (*buf & 0x80) {
- switch ((*buf >> 4) & 7) {
- case 1:
- dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
- break;
- case 3:
- dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf);
- break;
- case 5:
- dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf);
- break;
- case 2:
- if (*buf == 0xa0) {
- dp += sprintf(dp, " More data\n");
- break;
- }
- if (*buf == 0xa1) {
- dp += sprintf(dp, " Sending complete\n");
- }
- break;
- /* fall through */
- default:
- dp += sprintf(dp, " Reserved %x\n", *buf);
- break;
- }
- buf++;
- continue;
- }
- /* No, locate it in the table */
- for (i = 0; i < IESIZE; i++)
- if (*buf == ielist[i].nr)
- break;
-
- /* When not found, give appropriate msg */
- if (i != IESIZE) {
- dp += sprintf(dp, " %s\n", ielist[i].descr);
- dp += ielist[i].f(dp, buf);
- } else
- dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
-
- /* Skip to next element */
- buf += buf[1] + 2;
- }
- }
- else dp += sprintf(dp,"Unnown frame type %.2x, ignored\n",buf[0]);
-
- dp += sprintf(dp, "\n");
- teles_putstatus(sp->dlogspace);
-}
diff --git a/drivers/isdn/teles/tei.c b/drivers/isdn/teles/tei.c
deleted file mode 100644
index 3ab9f3646..000000000
--- a/drivers/isdn/teles/tei.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/* $Id: tei.c,v 1.1 1996/04/13 10:28:25 fritz Exp $
- *
- * $Log: tei.c,v $
- * Revision 1.1 1996/04/13 10:28:25 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern int nrcards;
-
-static struct PStack *
-findces(struct PStack *st, int ces)
-{
- struct PStack *ptr = *(st->l1.stlistp);
-
- while (ptr)
- if (ptr->l2.ces == ces)
- return (ptr);
- else
- ptr = ptr->next;
- return (NULL);
-}
-
-static struct PStack *
-findtei(struct PStack *st, int tei)
-{
- struct PStack *ptr = *(st->l1.stlistp);
-
- if (tei == 127)
- return (NULL);
-
- while (ptr)
- if (ptr->l2.tei == tei)
- return (ptr);
- else
- ptr = ptr->next;
- return (NULL);
-}
-
-void
-tei_handler(struct PStack *st,
- byte pr, struct BufHeader *ibh)
-{
- byte *bp;
- unsigned int tces;
- struct PStack *otsp, *ptr;
- unsigned int data;
-
- if (st->l2.debug)
- printk(KERN_DEBUG "teihandler %d\n", pr);
-
- switch (pr) {
- case (MDL_ASSIGN):
- data = (unsigned int) ibh;
- BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 6);
- if (!ibh)
- return;
- bp = DATAPTR(ibh);
- bp += st->l2.uihsize;
- bp[0] = 0xf;
- bp[1] = data >> 8;
- bp[2] = data & 0xff;
- bp[3] = 0x1;
- bp[4] = 0xff;
- ibh->datasize = 8;
- st->l3.l3l2(st, DL_UNIT_DATA, ibh);
- break;
- case (DL_UNIT_DATA):
- bp = DATAPTR(ibh);
- bp += 3;
- if (bp[0] != 0xf)
- break;
- switch (bp[3]) {
- case (2):
- tces = (bp[1] << 8) | bp[2];
- BufPoolRelease(ibh);
- if (st->l3.debug)
- printk(KERN_DEBUG "tei identity assigned for %d=%d\n", tces,
- bp[4] >> 1);
- if ((otsp = findces(st, tces)))
- otsp->ma.teil2(otsp, MDL_ASSIGN,
- (void *)(bp[4] >> 1));
- break;
- case (4):
- if (st->l3.debug)
- printk(KERN_DEBUG "checking identity for %d\n", bp[4] >> 1);
- if (bp[4] >> 1 == 0x7f) {
- BufPoolRelease(ibh);
- ptr = *(st->l1.stlistp);
- while (ptr) {
- if ((ptr->l2.tei & 0x7f) != 0x7f) {
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7))
- break;
- bp = DATAPTR(ibh);
- bp += 3;
- bp[0] = 0xf;
- bp[1] = ptr->l2.ces >> 8;
- bp[2] = ptr->l2.ces & 0xff;
- bp[3] = 0x5;
- bp[4] = (ptr->l2.tei << 1) | 1;
- ibh->datasize = 8;
- st->l3.l3l2(st, DL_UNIT_DATA, ibh);
- }
- ptr = ptr->next;
- }
- } else {
- otsp = findtei(st, bp[4] >> 1);
- BufPoolRelease(ibh);
- if (!otsp)
- break;
- if (st->l3.debug)
- printk(KERN_DEBUG "ces is %d\n", otsp->l2.ces);
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7))
- break;
- bp = DATAPTR(ibh);
- bp += 3;
- bp[0] = 0xf;
- bp[1] = otsp->l2.ces >> 8;
- bp[2] = otsp->l2.ces & 0xff;
- bp[3] = 0x5;
- bp[4] = (otsp->l2.tei << 1) | 1;
- ibh->datasize = 8;
- st->l3.l3l2(st, DL_UNIT_DATA, ibh);
- }
- break;
- default:
- BufPoolRelease(ibh);
- if (st->l3.debug)
- printk(KERN_DEBUG "tei message unknown %d ai %d\n", bp[3], bp[4] >> 1);
- }
- break;
- default:
- printk(KERN_WARNING "tei handler unknown primitive %d\n", pr);
- break;
- }
-}
-
-unsigned int
-randomces(void)
-{
- int x = jiffies & 0xffff;
-
- return (x);
-}
-
-static void
-tei_man(struct PStack *sp, int i, void *v)
-{
- printk(KERN_DEBUG "tei_man\n");
-}
-
-static void
-tei_l2tei(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *sp = st->l1.hardware;
-
- tei_handler(sp->teistack, pr, arg);
-}
-
-void
-setstack_tei(struct PStack *st)
-{
- st->l2.l2tei = tei_l2tei;
-}
-
-static void
-init_tei(struct IsdnCardState *sp, int protocol)
-{
- struct PStack *st;
- char tmp[128];
-
-#define DIRTY_HACK_AGAINST_SIGSEGV
-
- st = (struct PStack *) Smalloc(sizeof(struct PStack), GFP_KERNEL,
- "struct PStack");
-
-#ifdef DIRTY_HACK_AGAINST_SIGSEGV
- sp->teistack = st; /* struct is not initialized yet */
- sp->teistack->protocol = protocol; /* struct is not initialized yet */
-#endif /* DIRTY_HACK_AGAINST_SIGSEGV */
-
-
- setstack_teles(st, sp);
-
- st->l2.extended = !0;
- st->l2.laptype = LAPD;
- st->l2.window = 1;
- st->l2.orig = !0;
- st->protocol = protocol;
-
-/*
- * the following is not necessary for tei mng. (broadcast only)
- */
-
- st->l2.t200 = 500; /* 500 milliseconds */
- st->l2.n200 = 4; /* try 4 times */
-
- st->l2.sap = 63;
- st->l2.tei = 127;
-
- sprintf(tmp, "Card %d tei ", sp->cardnr);
- setstack_isdnl2(st, tmp);
- st->l2.debug = 0;
- st->l3.debug = 0;
-
- st->ma.manl2(st, MDL_NOTEIPROC, NULL);
-
- st->l2.l2l3 = (void *) tei_handler;
- st->l1.l1man = tei_man;
- st->l2.l2man = tei_man;
- st->l4.l2writewakeup = NULL;
-
- teles_addlist(sp, st);
- sp->teistack = st;
-}
-
-static void
-release_tei(struct IsdnCardState *sp)
-{
- struct PStack *st = sp->teistack;
-
- teles_rmlist(sp, st);
- Sfree((void *) st);
-}
-
-void
-TeiNew(void)
-{
- int i;
-
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp)
- init_tei(cards[i].sp, cards[i].protocol);
-}
-
-void
-TeiFree(void)
-{
- int i;
-
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp)
- release_tei(cards[i].sp);
-}
diff --git a/drivers/isdn/teles/teles.h b/drivers/isdn/teles/teles.h
deleted file mode 100644
index 339e52d4e..000000000
--- a/drivers/isdn/teles/teles.h
+++ /dev/null
@@ -1,486 +0,0 @@
-/* $Id: teles.h,v 1.3 1997/02/11 01:40:36 keil Exp $
- *
- * $Log: teles.h,v $
- * Revision 1.3 1997/02/11 01:40:36 keil
- * New Param structure
- *
- * Revision 1.2 1996/04/30 21:52:04 isdn4dev
- * SPV for 1TR6 - Karsten
- *
- * Revision 1.1 1996/04/13 10:29:00 fritz
- * Initial revision
- *
- *
- */
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/isdnif.h>
-#include <linux/tty.h>
-
-#define PH_ACTIVATE 1
-#define PH_DATA 2
-#define PH_DEACTIVATE 3
-
-#define MDL_ASSIGN 4
-#define DL_UNIT_DATA 5
-#define SC_STARTUP 6
-#define CC_ESTABLISH 7
-#define DL_ESTABLISH 8
-#define DL_DATA 9
-#define CC_S_STATUS_ENQ 10
-
-#define CC_CONNECT 15
-#define CC_CONNECT_ACKNOWLEDGE 16
-#define CO_EOF 17
-#define SC_DISCONNECT 18
-#define CO_DTMF 19
-#define DL_RELEASE 20
-
-#define CO_ALARM 22
-#define CC_REJECT 23
-
-#define CC_SETUP_REQ 24
-#define CC_SETUP_CNF 25
-#define CC_SETUP_IND 26
-#define CC_SETUP_RSP 27
-#define CC_SETUP_COMPLETE_IND 28
-
-#define CC_DISCONNECT_REQ 29
-#define CC_DISCONNECT_IND 30
-
-#define CC_RELEASE_CNF 31
-#define CC_RELEASE_IND 32
-#define CC_RELEASE_REQ 33
-
-#define CC_REJECT_REQ 34
-
-#define CC_PROCEEDING_IND 35
-
-#define CC_DLRL 36
-#define CC_DLEST 37
-
-#define CC_ALERTING_REQ 38
-#define CC_ALERTING_IND 39
-
-#define DL_STOP 40
-#define DL_START 41
-
-#define MDL_NOTEIPROC 46
-
-#define LC_ESTABLISH 47
-#define LC_RELEASE 48
-
-#define PH_REQUEST_PULL 49
-#define PH_PULL_ACK 50
-#define PH_DATA_PULLED 51
-#define CC_INFO_CHARGE 52
-
-/*
- * Message-Types
- */
-
-#define MT_ALERTING 0x01
-#define MT_CALL_PROCEEDING 0x02
-#define MT_CONNECT 0x07
-#define MT_CONNECT_ACKNOWLEDGE 0x0f
-#define MT_PROGRESS 0x03
-#define MT_SETUP 0x05
-#define MT_SETUP_ACKNOWLEDGE 0x0d
-#define MT_RESUME 0x26
-#define MT_RESUME_ACKNOWLEDGE 0x2e
-#define MT_RESUME_REJECT 0x22
-#define MT_SUSPEND 0x25
-#define MT_SUSPEND_ACKNOWLEDGE 0x2d
-#define MT_SUSPEND_REJECT 0x21
-#define MT_USER_INFORMATION 0x20
-#define MT_DISCONNECT 0x45
-#define MT_RELEASE 0x4d
-#define MT_RELEASE_COMPLETE 0x5a
-#define MT_RESTART 0x46
-#define MT_RESTART_ACKNOWLEDGE 0x4e
-#define MT_SEGMENT 0x60
-#define MT_CONGESTION_CONTROL 0x79
-#define MT_INFORMATION 0x7b
-#define MT_FACILITY 0x62
-#define MT_NOTIFY 0x6e
-#define MT_STATUS 0x7d
-#define MT_STATUS_ENQUIRY 0x75
-
-#define IE_CAUSE 0x08
-
-struct HscxIoctlArg {
- int channel;
- int mode;
- int transbufsize;
-};
-
-#ifdef __KERNEL__
-
-#undef DEBUG_MAGIC
-
-#define HSCX_SBUF_ORDER 1
-#define HSCX_SBUF_BPPS 2
-#define HSCX_SBUF_MAXPAGES 3
-
-#define HSCX_RBUF_ORDER 1
-#define HSCX_RBUF_BPPS 2
-#define HSCX_RBUF_MAXPAGES 3
-
-#define HSCX_SMALLBUF_ORDER 0
-#define HSCX_SMALLBUF_BPPS 40
-#define HSCX_SMALLBUF_MAXPAGES 1
-
-#define ISAC_SBUF_ORDER 0
-#define ISAC_SBUF_BPPS 16
-#define ISAC_SBUF_MAXPAGES 1
-
-#define ISAC_RBUF_ORDER 0
-#define ISAC_RBUF_BPPS 16
-#define ISAC_RBUF_MAXPAGES 1
-
-#define ISAC_SMALLBUF_ORDER 0
-#define ISAC_SMALLBUF_BPPS 40
-#define ISAC_SMALLBUF_MAXPAGES 1
-
-#define byte unsigned char
-
-#define MAX_WINDOW 8
-
-byte *Smalloc(int size, int pr, char *why);
-void Sfree(byte * ptr);
-
-/*
- * Statemachine
- */
-struct Fsm {
- int *jumpmatrix;
- int state_count, event_count;
- char **strEvent, **strState;
-};
-
-struct FsmInst {
- struct Fsm *fsm;
- int state;
- int debug;
- void *userdata;
- int userint;
- void (*printdebug) (struct FsmInst *, char *);
-};
-
-struct FsmNode {
- int state, event;
- void (*routine) (struct FsmInst *, int, void *);
-};
-
-struct FsmTimer {
- struct FsmInst *fi;
- struct timer_list tl;
- int event;
- void *arg;
-};
-
-struct BufHeader {
-#ifdef DEBUG_MAGIC
- int magic;
-#endif
- struct BufHeader *next;
- struct BufPool *bp;
- int datasize;
- byte primitive, where;
- void *heldby;
-};
-
-struct Pages {
- struct Pages *next;
-};
-
-struct BufPool {
-#ifdef DEBUG_MAGIC
- int magic;
-#endif
- struct BufHeader *freelist;
- struct Pages *pageslist;
- int pageorder;
- int pagescount;
- int bpps;
- int bufsize;
- int maxpages;
-};
-
-struct BufQueue {
-#ifdef DEBUG_MAGIC
- int magic;
-#endif
- struct BufHeader *head, *tail;
-};
-
-struct Layer1 {
- void *hardware;
- int hscx;
- struct BufPool *sbufpool, *rbufpool, *smallpool;
- struct PStack **stlistp;
- int act_state;
- void (*l1l2) (struct PStack *, int, struct BufHeader *);
- void (*l1man) (struct PStack *, int, void *);
- int hscxmode, hscxchannel, requestpull;
-};
-
-struct Layer2 {
- int sap, tei, ces;
- int extended, laptype;
- int uihsize, ihsize;
- int vs, va, vr;
- struct BufQueue i_queue;
- int window, orig;
- int rejexp;
- int debug;
- struct BufHeader *windowar[MAX_WINDOW];
- int sow;
- struct FsmInst l2m;
- void (*l2l1) (struct PStack *, int, struct BufHeader *);
- void (*l2l1discardq) (struct PStack *, int, void *, int);
- void (*l2man) (struct PStack *, int, void *);
- void (*l2l3) (struct PStack *, int, void *);
- void (*l2tei) (struct PStack *, int, void *);
- struct FsmTimer t200_timer, t203_timer;
- int t200, n200, t203;
- int rc, t200_running;
- char debug_id[32];
-};
-
-struct Layer3 {
- void (*l3l4) (struct PStack *, int, struct BufHeader *);
- void (*l3l2) (struct PStack *, int, void *);
- int state, callref;
- int debug;
-};
-
-struct Layer4 {
- void (*l4l3) (struct PStack *, int, void *);
- void *userdata;
- void (*l1writewakeup) (struct PStack *);
- void (*l2writewakeup) (struct PStack *);
-};
-
-struct Management {
- void (*manl1) (struct PStack *, int, void *);
- void (*manl2) (struct PStack *, int, void *);
- void (*teil2) (struct PStack *, int, void *);
-};
-
-struct Param {
- int cause;
- int bchannel;
- int callref; /* TEI-Number */
- setup_parm setup; /* from isdnif.h numbers and Serviceindicator */
- int chargeinfo; /* Charge Info - only for 1tr6 in
- * the moment
- */
- int spv; /* SPV Flag */
-};
-
-struct PStack {
- struct PStack *next;
- struct Layer1 l1;
- struct Layer2 l2;
- struct Layer3 l3;
- struct Layer4 l4;
- struct Management ma;
- struct Param *pa;
- int protocol; /* EDSS1 or 1TR6 */
-};
-
-struct HscxState {
- byte *membase;
- int iobase;
- int inuse, init, active;
- struct BufPool sbufpool, rbufpool, smallpool;
- struct IsdnCardState *sp;
- int hscx, mode;
- int transbufsize, receive;
- struct BufHeader *rcvibh, *xmtibh;
- int rcvptr, sendptr;
- struct PStack *st;
- struct tq_struct tqueue;
- int event;
- struct BufQueue rq, sq;
- int releasebuf;
-#ifdef DEBUG_MAGIC
- int magic; /* 301270 */
-#endif
-};
-
-struct IsdnCardState {
-#ifdef DEBUG_MAGIC
- int magic;
-#endif
- byte *membase;
- int iobase;
- struct BufPool sbufpool, rbufpool, smallpool;
- struct PStack *stlist;
- struct BufHeader *xmtibh, *rcvibh;
- int rcvptr, sendptr;
- int event;
- struct tq_struct tqueue;
- int ph_active;
- struct BufQueue rq, sq;
-
- int cardnr, ph_state;
- struct PStack *teistack;
- struct HscxState hs[2];
-
- int dlogflag;
- char *dlogspace;
- int debug;
- int releasebuf;
-};
-
-struct IsdnCard {
- byte *membase;
- int interrupt;
- unsigned int iobase;
- int protocol; /* EDSS1 or 1TR6 */
- struct IsdnCardState *sp;
-};
-
-#define DATAPTR(x) ((byte *)x+sizeof(struct BufHeader))
-
-#define LAPD 0
-#define LAPB 1
-
-void BufPoolInit(struct BufPool *bp, int order, int bpps,
- int maxpages);
-int BufPoolAdd(struct BufPool *bp, int priority);
-void BufPoolFree(struct BufPool *bp);
-int BufPoolGet(struct BufHeader **bh,
- struct BufPool *bp, int priority, void *heldby, int where);
-void BufPoolRelease(struct BufHeader *bh);
-void BufQueueLink(struct BufQueue *bq,
- struct BufHeader *bh);
-int BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq);
-void BufQueueInit(struct BufQueue *bq);
-void BufQueueRelease(struct BufQueue *bq);
-void BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
- int releasetoo);
-int BufQueueLength(struct BufQueue *bq);
-void BufQueueLinkFront(struct BufQueue *bq,
- struct BufHeader *bh);
-
-void l2down(struct PStack *st,
- byte pr, struct BufHeader *ibh);
-void l2up(struct PStack *st,
- byte pr, struct BufHeader *ibh);
-void acceptph(struct PStack *st,
- struct BufHeader *ibh);
-void setstack_isdnl2(struct PStack *st, char *debug_id);
-int teles_inithardware(void);
-void teles_closehardware(void);
-
-void setstack_teles(struct PStack *st, struct IsdnCardState *sp);
-unsigned int randomces(void);
-void setstack_isdnl3(struct PStack *st);
-void teles_addlist(struct IsdnCardState *sp,
- struct PStack *st);
-void releasestack_isdnl2(struct PStack *st);
-void teles_rmlist(struct IsdnCardState *sp,
- struct PStack *st);
-void newcallref(struct PStack *st);
-
-int ll_init(void);
-void ll_stop(void), ll_unload(void);
-int setstack_hscx(struct PStack *st, struct HscxState *hs);
-void modehscx(struct HscxState *hs, int mode, int ichan);
-byte *findie(byte * p, int size, byte ie, int wanted_set);
-int getcallref(byte * p);
-
-void FsmNew(struct Fsm *fsm,
- struct FsmNode *fnlist, int fncount);
-void FsmFree(struct Fsm *fsm);
-int FsmEvent(struct FsmInst *fi,
- int event, void *arg);
-void FsmChangeState(struct FsmInst *fi,
- int newstate);
-void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
-int FsmAddTimer(struct FsmTimer *ft,
- int millisec, int event, void *arg, int where);
-void FsmDelTimer(struct FsmTimer *ft, int where);
-int FsmTimerRunning(struct FsmTimer *ft);
-void jiftime(char *s, long mark);
-
-void CallcNew(void);
-void CallcFree(void);
-int CallcNewChan(void);
-void CallcFreeChan(void);
-int teles_command(isdn_ctrl * ic);
-int teles_writebuf(int id, int chan, const u_char * buf, int count, int user);
-void teles_putstatus(char *buf);
-void teles_reportcard(int cardnr);
-int ListLength(struct BufHeader *ibh);
-void dlogframe(struct IsdnCardState *sp, byte * p, int size, char *comment);
-void iecpy(byte * dest, byte * iestart, int ieoffset);
-void setstack_transl2(struct PStack *st);
-void releasestack_transl2(struct PStack *st);
-void close_hscxstate(struct HscxState *);
-void setstack_tei(struct PStack *st);
-
-struct LcFsm {
- struct FsmInst lcfi;
- int type;
- struct Channel *ch;
- void (*lccall) (struct LcFsm *, int, void *);
- struct PStack *st;
- int l2_establish;
- int l2_start;
- struct FsmTimer act_timer;
- char debug_id[32];
-};
-
-struct Channel {
- struct PStack ds, is;
- struct IsdnCardState *sp;
- int hscx;
- int chan;
- int incoming;
- struct FsmInst fi;
- struct LcFsm lc_d, lc_b;
- struct Param para;
- int debug;
-#ifdef DEBUG_MAGIC
- int magic; /* 301272 */
-#endif
- int l2_protocol, l2_active_protocol;
- int l2_primitive, l2_headersize;
- int data_open;
- int outcallref;
- int impair;
-};
-
-#define PART_SIZE(order,bpps) (( (PAGE_SIZE<<order) -\
- sizeof(void *))/bpps)
-#define BUFFER_SIZE(order,bpps) (PART_SIZE(order,bpps)-\
- sizeof(struct BufHeader))
-
-#endif
-
-void Isdnl2New(void);
-void Isdnl2Free(void);
-void TeiNew(void);
-void TeiFree(void);
-
-
-
-
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index d17ea2c93..77a5e302d 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -413,7 +413,7 @@ static int el_start_xmit(struct sk_buff *skb, struct device *dev)
* Avoid timer-based retransmission conflicts.
*/
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
{
restore_flags(flags);
printk("%s: Transmitter access conflict.\n", dev->name);
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index 31a64990a..d8a7b33ce 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -412,7 +412,7 @@ static int send_pcb(struct device *dev, pcb_struct * pcb)
return FALSE;
/* Avoid contention */
- if (set_bit(1, &adapter->send_pcb_semaphore)) {
+ if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
if (elp_debug >= 3) {
printk("%s: send_pcb entered while threaded\n", dev->name);
}
@@ -545,7 +545,7 @@ static int receive_pcb(struct device *dev, pcb_struct * pcb)
}
if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {
- if (set_bit(0, (void *) &adapter->busy)) {
+ if (test_and_set_bit(0, (void *) &adapter->busy)) {
if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) {
set_hsf(dev, HSF_PCB_NAK);
printk("%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
@@ -621,7 +621,7 @@ static void receive_packet(struct device *dev, int len)
}
/* if this happens, we die */
- if (set_bit(0, (void *) &adapter->dmaing))
+ if (test_and_set_bit(0, (void *) &adapter->dmaing))
printk("%s: rx blocked, DMA in progress, dir %d\n", dev->name, adapter->current_dma.direction);
skb->dev = dev;
@@ -1031,7 +1031,7 @@ static int send_packet(struct device *dev, struct sk_buff *skb)
*/
unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1);
- if (set_bit(0, (void *) &adapter->busy)) {
+ if (test_and_set_bit(0, (void *) &adapter->busy)) {
if (elp_debug >= 2)
printk("%s: transmit blocked\n", dev->name);
return FALSE;
@@ -1054,7 +1054,7 @@ static int send_packet(struct device *dev, struct sk_buff *skb)
return FALSE;
}
/* if this happens, we die */
- if (set_bit(0, (void *) &adapter->dmaing))
+ if (test_and_set_bit(0, (void *) &adapter->dmaing))
printk("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction);
adapter->current_dma.direction = 1;
@@ -1119,7 +1119,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct device *dev)
if (elp_debug >= 3)
printk("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
- if (set_bit(0, (void *) &dev->tbusy)) {
+ if (test_and_set_bit(0, (void *) &dev->tbusy)) {
printk("%s: transmitter access conflict\n", dev->name);
return 1;
}
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index 00038f96d..c12d6ee98 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -479,7 +479,7 @@ static int el16_send_packet(struct sk_buff *skb, struct device *dev)
}
/* Block a timer-based transmit from overlapping. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else
{
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index d3d941d20..af1be0848 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -468,7 +468,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct device *dev)
#endif
#endif
/* Avoid timer-based retransmission conflicts. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
lp->stats.tx_bytes+=skb->len;
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index 63c6240d3..39750860e 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -1137,7 +1137,7 @@ elmc_send_packet(struct sk_buff *skb, struct device *dev)
return 0;
}
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
} else {
memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 69464b4e9..56541f0c2 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -799,7 +799,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
If this ever occurs the queue layer is doing something evil! */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index b62102e7a..8de7f28b9 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -599,7 +599,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
#ifdef OLD_METHOD
dev->tbusy = 1;
#else
- if (set_bit (0, (void *) &dev->tbusy) != 0) {
+ if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) {
printk ("Transmitter access conflict.\n");
return -1;
}
diff --git a/drivers/net/apricot.c b/drivers/net/apricot.c
index 2a00c4481..cc118f7e3 100644
--- a/drivers/net/apricot.c
+++ b/drivers/net/apricot.c
@@ -616,7 +616,7 @@ i596_start_xmit(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else
{
diff --git a/drivers/net/arcnet.c b/drivers/net/arcnet.c
index b25dd02c2..7a8069fd6 100644
--- a/drivers/net/arcnet.c
+++ b/drivers/net/arcnet.c
@@ -1588,7 +1588,7 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
{
BUGMSG(D_NORMAL,"transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
ARCSTATUS,lp->intx,jiffies-dev->trans_start);
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index 290b9761e..884398c53 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -593,12 +593,12 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return(1);
}
- if (set_bit(0, (void*)&priv->lock) != 0) {
+ if (test_and_set_bit(0, (void*)&priv->lock) != 0) {
if (ariadne_debug > 0)
printk("%s: tx queue lock!.\n", dev->name);
/* don't clear dev->tbusy flag. */
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index bd1f93846..c75274c01 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -395,7 +395,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index bb08b8927..764416d79 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -776,12 +776,12 @@ static int lance_start_xmit( struct sk_buff *skb, struct device *dev )
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit( 0, (void*)&dev->tbusy ) != 0) {
+ if (test_and_set_bit( 0, (void*)&dev->tbusy ) != 0) {
DPRINTK( 0, ( "%s: Transmitter access conflict.\n", dev->name ));
return 1;
}
- if (set_bit( 0, (void*)&lp->lock ) != 0) {
+ if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) {
DPRINTK( 0, ( "%s: tx queue lock!.\n", dev->name ));
/* don't clear dev->tbusy flag. */
return 1;
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 411374119..997368ef4 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -437,7 +437,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 6a38177b6..66852e388 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -752,7 +752,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
struct net_local *lp = (struct net_local *)dev->priv;
diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c
index aae249ed0..a199c7f8a 100644
--- a/drivers/net/de4x5.c
+++ b/drivers/net/de4x5.c
@@ -3,8 +3,30 @@
Copyright 1994, 1995 Digital Equipment Corporation.
- This software may be used and distributed according to the terms of
- the GNU Public License, incorporated herein by reference.
+ Testing resources for this driver have been made available
+ in part by NASA Ames Research Center (mjacob@nas.nasa.gov).
+
+ The author may be reached at davies@maniac.ultranet.com.
+
+ 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ 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.
Originally, this driver was written for the Digital Equipment
Corporation series of EtherWORKS ethernet cards:
@@ -15,8 +37,8 @@
DE450 TP/COAX/AUI PCI
DE500 10/100 PCI Fasternet
- but it will now attempt to support all cards which conform to the
- Digital Semiconductor SROM Specification. The driver currently
+ but it will now attempt to support all cards which conform to the
+ Digital Semiconductor SROM Specification. The driver currently
recognises the following chips:
DC21040 (no SROM)
@@ -32,6 +54,7 @@
SMC8432
SMC9332 (w/new SROM)
ZNYX31[45]
+ ZNYX346 10/100 4 port (can act as a 10/100 bridge!)
The driver has been tested on a relatively busy network using the DE425,
DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred
@@ -48,13 +71,11 @@
measurement. Their error is +/-20k on a quiet (private) network and also
depend on what load the CPU has.
- The author may be reached at davies@maniac.ultranet.com.
-
=========================================================================
- This driver has been written substantially from scratch, although its
+ This driver has been written substantially from scratch, although its
inheritance of style and stack interface from 'ewrk3.c' and in turn from
Donald Becker's 'lance.c' should be obvious. With the module autoload of
- every usable DECchip board, I pinched Donald's 'next_module' field to
+ every usable DECchip board, I pinched Donald's 'next_module' field to
link my modules together.
Upto 15 EISA cards can be supported under this driver, limited primarily
@@ -80,7 +101,7 @@
1) copy de4x5.c from the /linux/drivers/net directory to your favourite
temporary directory.
2) for fixed autoprobes (not recommended), edit the source code near
- line 4927 to reflect the I/O address you're using, or assign these when
+ line 5005 to reflect the I/O address you're using, or assign these when
loading by:
insmod de4x5 io=0xghh where g = bus number
@@ -113,7 +134,7 @@
By default, the driver will now autodetect any DECchip based card.
Should you have a need to restrict the driver to DIGITAL only cards, you
can compile with a DEC_ONLY define, or if loading as a module, use the
- 'dec_only=1' parameter.
+ 'dec_only=1' parameter.
I've changed the timing routines to use the kernel timer and scheduling
functions so that the hangs and other assorted problems that occurred
@@ -145,6 +166,19 @@
(quad 21041 MAC) cards also appear to work despite their incorrectly
wired IRQs.
+ I have added a temporary fix for interrupt problems when some SCSI cards
+ share the same interrupt as the DECchip based cards. The problem occurs
+ because the SCSI card wants to grab the interrupt as a fast interrupt
+ (runs the service routine with interrupts turned off) vs. this card
+ which really needs to run the service routine with interrupts turned on.
+ This driver will now add the interrupt service routine as a fast
+ interrupt if it is bounced from the slow interrupt. THIS IS NOT A
+ RECOMMENDED WAY TO RUN THE DRIVER and has been done for a limited time
+ until people sort out their compatibility issues and the kernel
+ interrupt service code is fixed. YOU SHOULD SEPARATE OUT THE FAST
+ INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not
+ run on the same interrupt. PCMCIA/CardBus is another can of worms...
+
TO DO:
------
@@ -234,7 +268,7 @@
0.442 9-Sep-96 Include AUI in dc21041 media printout. Bug reported
by <bhat@mundook.cs.mu.OZ.AU>
0.45 8-Dec-96 Include endian functions for PPC use, from work
- by <cort@cs.nmt.edu>.
+ by <cort@cs.nmt.edu> and <g.thomas@opengroup.org>.
0.451 28-Dec-96 Added fix to allow autoprobe for modules after
suggestion from <mjacob@feral.com>.
0.5 30-Jan-97 Added SROM decoding functions.
@@ -247,11 +281,30 @@
Added attempt to use an SMC9332 with broken SROM.
Added fix for ZYNX multi-mac cards that didn't
get their IRQs wired correctly.
+ 0.51 13-Feb-97 Added endian fixes for the SROM accesses from
+ <paubert@iram.es>
+ Fix init_connection() to remove extra device reset.
+ Fix MAC/PHY reset ordering in dc21140m_autoconf().
+ Fix initialisation problem with lp->timeout in
+ typeX_infoblock() from <paubert@iram.es>.
+ Fix MII PHY reset problem from work done by
+ <paubert@iram.es>.
+ 0.52 26-Apr-97 Some changes may not credit the right people -
+ a disk crash meant I lost some mail.
+ Change RX interrupt routine to drop rather than
+ defer packets to avoid hang reported by
+ <g.thomas@opengroup.org>.
+ Fix srom_exec() to return for COMPACT and type 1
+ infoblocks.
+ Added DC21142 and DC21143 functions.
+ Added byte counters from <phil@tazenda.demon.co.uk>
+ Added SA_INTERRUPT temporary fix from
+ <mjacob@feral.com>.
=========================================================================
*/
-static const char *version = "de4x5.c:V0.5 97/1/30 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.52 1997/4/26 davies@maniac.ultranet.com\n";
#include <linux/module.h>
@@ -270,8 +323,8 @@ static const char *version = "de4x5.c:V0.5 97/1/30 davies@maniac.ultranet.com\n"
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
-#include <asm/uaccess.h>
#include <asm/byteorder.h>
+#include <asm/unaligned.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -286,14 +339,37 @@ static const char *version = "de4x5.c:V0.5 97/1/30 davies@maniac.ultranet.com\n"
#define c_char const char
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < ((2 << 16) | (1 << 8))
+#define net_device_stats enet_statistics
+#define copy_to_user(a,b,c) memcpy_tofs(a,b,c)
+#define copy_from_user(a,b,c) memcpy_fromfs(a,b,c)
+#define le16_to_cpu(a) cpu_to_le16(a)
+#define le32_to_cpu(a) cpu_to_le32(a)
+#ifdef __powerpc__
+#define cpu_to_le16(a) ((((a) & 0x00ffU) << 8) | (((a) & 0xff00U) >> 8))
+#define cpu_to_le32(a) ((((a) & 0x000000ffU) << 24) |\
+ (((a) & 0x0000ff00U) << 8) |\
+ (((a) & 0x00ff0000U) >> 8) |\
+ (((a) & 0xff000000U) >> 24))
+#else
+#define cpu_to_le16(a) (a)
+#define cpu_to_le32(a) (a)
+#endif /* __powerpc__ */
+#include <asm/segment.h>
+#else
+#include <asm/uaccess.h>
+#endif /* LINUX_VERSION_CODE */
+#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a)))
+
/*
** MII Information
*/
struct phy_table {
- int reset; /* Hard reset required? */
- int id; /* IEEE OUI */
+ int reset; /* Hard reset required? */
+ int id; /* IEEE OUI */
int ta; /* One cycle TA time - 802.3u is confusing here */
- struct { /* Non autonegotiation (parallel) speed det. */
+ struct { /* Non autonegotiation (parallel) speed det. */
int reg;
int mask;
int value;
@@ -301,25 +377,35 @@ struct phy_table {
};
struct mii_phy {
- int reset; /* Hard reset required? */
- int id; /* IEEE OUI */
- int ta; /* One cycle TA time */
+ int reset; /* Hard reset required? */
+ int id; /* IEEE OUI */
+ int ta; /* One cycle TA time */
struct { /* Non autonegotiation (parallel) speed det. */
int reg;
int mask;
int value;
} spd;
- int addr; /* MII address for the PHY */
- u_char *gep; /* Start of GEP sequence block in SROM */
- u_char *rst; /* Start of reset sequence in SROM */
- u_int mc; /* Media Capabilities */
- u_int ana; /* NWay Advertisement */
- u_int fdx; /* Full DupleX capabilites for each media */
- u_int ttm; /* Transmit Threshold Mode for each media */
+ int addr; /* MII address for the PHY */
+ u_char *gep; /* Start of GEP sequence block in SROM */
+ u_char *rst; /* Start of reset sequence in SROM */
+ u_int mc; /* Media Capabilities */
+ u_int ana; /* NWay Advertisement */
+ u_int fdx; /* Full DupleX capabilites for each media */
+ u_int ttm; /* Transmit Threshold Mode for each media */
};
#define DE4X5_MAX_PHY 8 /* Allow upto 8 attached PHY devices per board */
+struct sia_phy {
+ u_char mc; /* Media Code */
+ u_char ext; /* csr13-15 valid when set */
+ int csr13; /* SIA Connectivity Register */
+ int csr14; /* SIA TX/RX Register */
+ int csr15; /* SIA General Register */
+ int gepc; /* SIA GEP Control Information */
+ int gep; /* SIA GEP Data */
+};
+
/*
** Define the know universe of PHY devices that can be
** recognised by this driver
@@ -327,8 +413,8 @@ struct mii_phy {
static struct phy_table phy_info[] = {
{0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}}, /* National TX */
{1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}}, /* Broadcom T4 */
- {0, SEEQ_T4 , 1, {0x12, 0x10, 0x10}}, /* SEEQ T4 */
- {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}} /* Cypress T4 */
+ {0, SEEQ_T4 , 1, {0x12, 0x10, 0x10}}, /* SEEQ T4 */
+ {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}} /* Cypress T4 */
};
/*
@@ -354,7 +440,6 @@ static c_char srom_repair_info[][100] = {
0x00,0x18,}
};
-#undef DE4X5_VERBOSE /* define to get more verbose startup messages */
#ifdef DE4X5_DEBUG
static int de4x5_debug = DE4X5_DEBUG;
@@ -581,6 +666,7 @@ struct de4x5_private {
int setup_f; /* Setup frame filtering type */
int local_state; /* State within a 'media' state */
struct mii_phy phy[DE4X5_MAX_PHY]; /* List of attached PHY devices */
+ struct sia_phy sia; /* SIA PHY Information */
int active; /* Index to active PHY device */
int mii_cnt; /* Number of attached PHY's */
int timeout; /* Scheduling counter */
@@ -770,9 +856,6 @@ static void timeout(struct device *dev, void (*fn)(u_long data), u_long data,
static void yawn(struct device *dev, int state);
static int de4x5_dev_index(char *s);
static void link_modules(struct device *dev, struct device *tmp);
-#ifdef MODULE
-static struct device *unlink_modules(struct device *p);
-#endif
static void de4x5_dbg_open(struct device *dev);
static void de4x5_dbg_mii(struct device *dev, int k);
static void de4x5_dbg_media(struct device *dev);
@@ -794,6 +877,7 @@ static int compact_infoblock(struct device *dev, u_char count, u_char *p);
#ifdef MODULE
int init_module(void);
void cleanup_module(void);
+static struct device *unlink_modules(struct device *p);
static int autoprobed = 0, loading_module = 1;
# else
static int autoprobed = 0, loading_module = 0;
@@ -898,7 +982,7 @@ de4x5_hw_init(struct device *dev, u_long iobase))
PCI_CFDA_PSM, WAKEUP);
}
de4x5_ms_delay(10);
-
+
RESET_DE4X5;
if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) {
@@ -964,6 +1048,9 @@ de4x5_hw_init(struct device *dev, u_long iobase))
lp->chipset = bus.chipset;
lp->cache.priv = tmp;
lp->cache.gepc = GEP_INIT;
+ lp->asBit = GEP_SLNK;
+ lp->asPolarity = GEP_SLNK;
+ lp->asBitValid = TRUE;
lp->timeout = -1;
lp->useSROM = useSROM;
memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom));
@@ -1071,11 +1158,6 @@ de4x5_hw_init(struct device *dev, u_long iobase))
printk(" and requires IRQ%d (provided by %s).\n", dev->irq,
((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
-
-#ifdef DE4X5_VERBOSE
- printk("%s: INFOLEAF_SIZE: %ld, COMPACT: %ld\n", dev->name,
- INFOLEAF_SIZE, COMPACT);
-#endif
}
if (de4x5_debug & DEBUG_VERSION) {
@@ -1133,18 +1215,29 @@ de4x5_open(struct device *dev)
if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ,
lp->adapter_name, dev)) {
- printk("de4x5_open(): Requested IRQ%d is busy\n",dev->irq);
- status = -EAGAIN;
- } else {
- dev->tbusy = 0;
- dev->start = 1;
- dev->interrupt = UNMASK_INTERRUPTS;
- dev->trans_start = jiffies;
-
- START_DE4X5;
-
- de4x5_setup_intr(dev);
+ printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq);
+ if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ,
+ lp->adapter_name, dev)) {
+ printk("\n Cannot get IRQ- reconfigure your hardware.\n");
+ disable_ast(dev);
+ de4x5_free_rx_buffs(dev);
+ de4x5_free_tx_buffs(dev);
+ yawn(dev, SLEEP);
+ lp->state = CLOSED;
+ return -EAGAIN;
+ } else {
+ printk("\n Succeeded, but you should reconfigure your hardware to avoid this.\n");
+ printk("WARNING: there may be IRQ related problems in heavily loaded systems.\n");
+ }
}
+ dev->tbusy = 0;
+ dev->start = 1;
+ dev->interrupt = UNMASK_INTERRUPTS;
+ dev->trans_start = jiffies;
+
+ START_DE4X5;
+
+ de4x5_setup_intr(dev);
if (de4x5_debug & DEBUG_OPEN) {
printk("\tsts: 0x%08x\n", inl(DE4X5_STS));
@@ -1287,7 +1380,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
sti();
/* Test if cache is already locked - requeue skb if so */
- if (set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1;
+ if (test_and_set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1;
/* Transmit descriptor ring full or stale skb */
if (dev->tbusy || lp->tx_skb[lp->tx_new]) {
@@ -1300,9 +1393,6 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%ld\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO"));
}
} else if (skb->len > 0) {
- /* Update the byte counter */
- lp->stats.tx_bytes += skb->len;
-
/* If we already have stuff queued locally, use that first */
if (lp->cache.skb && !dev->interrupt) {
de4x5_put_cache(dev, skb);
@@ -1313,6 +1403,9 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
cli();
set_bit(0, (void*)&dev->tbusy);
load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
+#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
+ lp->stats.tx_bytes += skb->len;
+#endif
outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
@@ -1326,7 +1419,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
}
if (skb) de4x5_putb_cache(dev, skb);
}
-
+
lp->cache.lock = 0;
return status;
@@ -1360,9 +1453,11 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (dev->interrupt)
printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
+
DISABLE_IRQs; /* Ensure non re-entrancy */
+#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
synchronize_irq();
+#endif
dev->interrupt = MASK_INTERRUPTS;
for (limit=0; limit<8; limit++) {
@@ -1394,8 +1489,8 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
/* Load the TX ring with any locally stored packets */
- if (!set_bit(0, (void *)&lp->cache.lock)) {
- if (lp->cache.skb && !dev->tbusy && lp->tx_enable) {
+ if (!test_and_set_bit(0, (void *)&lp->cache.lock)) {
+ while (lp->cache.skb && !dev->tbusy && lp->tx_enable) {
de4x5_queue_pkt(de4x5_get_cache(dev), dev);
}
lp->cache.lock = 0;
@@ -1450,19 +1545,21 @@ de4x5_rx(struct device *dev)
if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) {
printk("%s: Insufficient memory; nuking packet.\n",
dev->name);
- lp->stats.rx_dropped++; /* Really, deferred. */
- break;
- }
- de4x5_dbg_rx(skb, pkt_len);
+ lp->stats.rx_dropped++;
+ } else {
+ de4x5_dbg_rx(skb, pkt_len);
- /* Push up the protocol stack */
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
+ /* Push up the protocol stack */
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
- /* Update stats */
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
- de4x5_local_stats(dev, skb->data, pkt_len);
+ /* Update stats */
+ lp->stats.rx_packets++;
+#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
+ lp->stats.rx_bytes += pkt_len;
+#endif
+ de4x5_local_stats(dev, skb->data, pkt_len);
+ }
}
/* Change buffer ownership for this frame, back to the adapter */
@@ -1575,10 +1672,7 @@ de4x5_txur(struct device *dev)
if ((omr & OMR_TR) < OMR_TR) {
omr += 0x4000;
} else {
- if (omr & OMR_TTM)
- omr &= ~OMR_TTM;
- else
- omr |= OMR_SF;
+ omr |= OMR_SF;
}
outl(omr | OMR_ST | OMR_SR, DE4X5_OMR);
}
@@ -1645,7 +1739,8 @@ de4x5_close(struct device *dev)
return 0;
}
-static struct net_device_stats *de4x5_get_stats(struct device *dev)
+static struct net_device_stats *
+de4x5_get_stats(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
u_long iobase = dev->base_addr;
@@ -1880,7 +1975,7 @@ pci_probe(struct device *dev, u_long ioaddr))
{
u_char irq;
u_char pb, pbus, dev_num, dnum, dev_fn;
- u_short vendor, index, status;
+ u_short dev_id, vendor, index, status;
u_int class = DE4X5_CLASS_CODE;
u_int device, iobase;
struct bus_type *lp = &bus;
@@ -1908,7 +2003,8 @@ pci_probe(struct device *dev, u_long ioaddr))
if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) {
device = 0;
pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, (u_short *)&device);
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
+ device = dev_id;
device <<= 8;
if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
continue;
@@ -2091,31 +2187,6 @@ link_modules(struct device *dev, struct device *tmp))
return;
}
-#ifdef MODULE
-static struct device *
-unlink_modules(struct device *p)
-{
- struct device *next = NULL;
-
- if (p->priv) { /* Private areas allocated? */
- struct de4x5_private *lp = (struct de4x5_private *)p->priv;
-
- next = lp->next_module;
- if (lp->cache.buf) { /* MAC buffers allocated? */
- kfree(lp->cache.buf); /* Free the MAC buffers */
- }
- kfree(lp->cache.priv); /* Free the private area */
- release_region(p->base_addr, (lp->bus == PCI ?
- DE4X5_PCI_TOTAL_SIZE :
- DE4X5_EISA_TOTAL_SIZE));
- }
- unregister_netdev(p);
- kfree(p); /* Free the device structure */
-
- return next;
-}
-#endif
-
/*
** Auto configure the media here rather than setting the port at compile
** time. This routine is called by de4x5_init() and when a loss of media is
@@ -2300,6 +2371,7 @@ de4x5_suspect_state(struct device *dev, int timeout, int prev_state,
lp->media = prev_state;
} else {
lp->media = INIT;
+ lp->tcount++;
}
}
@@ -2527,16 +2599,22 @@ dc21140m_autoconf(struct device *dev)
switch(lp->media) {
case INIT:
- DISABLE_IRQs;
- lp->tx_enable = FALSE;
- lp->linkOK = 0;
-/* lp->timeout = -1;*/
+ if (lp->timeout < 0) {
+ DISABLE_IRQs;
+ lp->tx_enable = FALSE;
+ lp->linkOK = 0;
+ de4x5_save_skbs(dev); /* Save non transmitted skb's */
+ }
if ((next_tick = de4x5_reset_phy(dev)) < 0) {
next_tick &= ~TIMER_CB;
} else {
- de4x5_save_skbs(dev); /* Save non transmitted skb's */
if (lp->useSROM) {
srom_map_media(dev);
+ srom_exec(dev, lp->phy[lp->active].gep);
+ if (lp->infoblock_media == ANS) {
+ ana = lp->phy[lp->active].ana | MII_ANA_CSMA;
+ mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+ }
} else {
lp->tmp = MII_SR_ASSC; /* Fake out the MII speed set */
SET_10Mb;
@@ -2752,9 +2830,9 @@ de4x5_init_connection(struct device *dev)
de4x5_dbg_media(dev);
lp->c_media = lp->media; /* Stop scrolling media messages */
}
- de4x5_restore_skbs(dev);
+
cli();
- de4x5_rx(dev);
+ de4x5_restore_skbs(dev);
de4x5_setup_intr(dev);
lp->tx_enable = YES;
dev->tbusy = 0;
@@ -2766,7 +2844,9 @@ de4x5_init_connection(struct device *dev)
}
/*
-** General PHY reset function.
+** General PHY reset function. Some MII devices don't reset correctly
+** since their MII address pins can float at voltages that are dependent
+** on the signal pin use. Do a double reset to ensure a reset.
*/
static int
de4x5_reset_phy(struct device *dev)
@@ -2780,8 +2860,10 @@ de4x5_reset_phy(struct device *dev)
if (lp->useSROM) {
if (lp->phy[lp->active].rst) { /* MII device specific reset */
srom_exec(dev, lp->phy[lp->active].rst);
+ srom_exec(dev, lp->phy[lp->active].rst);
} else if (lp->rst) { /* Type 5 infoblock reset */
srom_exec(dev, lp->rst);
+ srom_exec(dev, lp->rst);
}
} else {
PHY_HARD_RESET;
@@ -3151,13 +3233,26 @@ de4x5_restore_skbs(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
u_long iobase = dev->base_addr;
+ int i;
s32 omr;
if (lp->cache.save_cnt) {
STOP_DE4X5;
- de4x5_cache_state(dev, DE4X5_SAVE_STATE);
- de4x5_sw_reset(dev);
- de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
+ outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+ outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
+
+ lp->rx_new = lp->rx_old = 0;
+ lp->tx_new = lp->tx_old = 0;
+
+ for (i = 0; i < lp->rxRingSize; i++) {
+ lp->rx_ring[i].status = cpu_to_le32(R_OWN);
+ }
+
+ for (i = 0; i < lp->txRingSize; i++) {
+ lp->tx_ring[i].status = cpu_to_le32(0);
+ }
+
+ barrier();
lp->cache.save_cnt--;
START_DE4X5;
}
@@ -3446,9 +3541,10 @@ DevicePresent(u_long aprom_addr)
if (lp->chipset == DC21040) {
outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */
} else { /* Read new srom */
- short *p = (short *)&lp->srom;
+ u_short tmp, *p = (short *)&lp->srom;
for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) {
- *p++ = srom_rd(aprom_addr, i);
+ tmp = srom_rd(aprom_addr, i);
+ *p++ = le16_to_cpu(tmp);
}
de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
}
@@ -3756,7 +3852,7 @@ srom_infoleaf_info(struct device *dev)
}
}
- lp->infoleaf_offset = (u_short)*((u_short *)(p+1));
+ lp->infoleaf_offset = TWIDDLE(p+1);
return 0;
}
@@ -3776,14 +3872,10 @@ srom_init(struct device *dev)
u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
u_char count;
+ p+=2;
if (lp->chipset == DC21140) {
- p+=2;
lp->cache.gepc = (*p++ | GEP_CTRL);
outl(lp->cache.gepc, DE4X5_GEP);
- } else if (lp->chipset == DC21142) {
- p+=2;
- } else if (lp->chipset == DC21143) {
- p+=2;
}
/* Block count */
@@ -3815,7 +3907,7 @@ srom_exec(struct device *dev, u_char *p)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
u_long iobase = dev->base_addr;
- u_char count = *p++;
+ u_char count = (p ? *p++ : 0);
while (count--) {
if (lp->chipset == DC21140) {
@@ -3910,7 +4002,7 @@ compact_infoblock(struct device *dev, u_char count, u_char *p)
}
}
- if (lp->media == INIT) {
+ if ((lp->media == INIT) && (lp->timeout < 0)) {
outl(lp->cache.gepc, DE4X5_GEP);
lp->infoblock_media = (*p++) & COMPACT_MC;
lp->cache.gep = *p++;
@@ -3949,7 +4041,7 @@ type0_infoblock(struct device *dev, u_char count, u_char *p)
}
}
- if (lp->media == INIT) {
+ if ((lp->media == INIT) && (lp->timeout < 0)) {
outl(lp->cache.gepc, DE4X5_GEP);
p+=2;
lp->infoblock_media = (*p++) & BLOCK0_MC;
@@ -3976,9 +4068,7 @@ static int
type1_infoblock(struct device *dev, u_char count, u_char *p)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- u_long iobase = dev->base_addr;
u_char len = (*p & BLOCK_LEN)+1;
- int ana;
/* Recursively figure out the info blocks */
if (--count > lp->tcount) {
@@ -3989,22 +4079,20 @@ type1_infoblock(struct device *dev, u_char count, u_char *p)
}
}
+ p += 2;
if (lp->state == INITIALISED) {
- lp->ibn = 1; p += 2;
+ lp->ibn = 1;
lp->active = *p++;
lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
- lp->phy[lp->active].mc = *(u_short *)p; p += 2;
- lp->phy[lp->active].ana = *(u_short *)p; p += 2;
- lp->phy[lp->active].fdx = *(u_short *)p; p += 2;
- lp->phy[lp->active].ttm = *(u_short *)p;
+ lp->phy[lp->active].mc = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].ttm = TWIDDLE(p);
return 0;
- } else if (lp->media == INIT) {
- if (lp->phy[lp->active].gep) {
- srom_exec(dev, lp->phy[lp->active].gep);
- }
- ana = lp->phy[lp->active].ana | MII_ANA_CSMA;
- mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+ } else if ((lp->media == INIT) && (lp->timeout < 0)) {
+ lp->ibn = 1;
+ lp->active = *p;
lp->infoblock_csr6 = OMR_PS | OMR_HBD;
lp->useMII = TRUE;
lp->infoblock_media = ANS;
@@ -4040,10 +4128,10 @@ type3_infoblock(struct device *dev, u_char count, u_char *p)
lp->active = *p++;
lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
- lp->phy[lp->active].mc = *(u_short *)p; p += 2;
- lp->phy[lp->active].ana = *(u_short *)p; p += 2;
- lp->phy[lp->active].fdx = *(u_short *)p; p += 2;
- lp->phy[lp->active].ttm = *(u_short *)p;
+ lp->phy[lp->active].mc = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].ttm = TWIDDLE(p);
return 0;
} else if (lp->media == INIT) {
p+=2;
@@ -4672,18 +4760,12 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
u_long iobase = dev->base_addr;
int i, j, status = 0;
s32 omr;
- struct {
- u8 *addr;
- u16 *sval;
- u32 *lval;
+ union {
+ u8 addr[144];
+ u16 sval[72];
+ u32 lval[36];
} tmp;
-
- tmp.addr = tmp.sval = tmp.lval = kmalloc(HASH_TABLE_LEN * ETH_ALEN, GFP_KERNEL);
- if (!tmp.addr){
- printk("%s ioctl: memory squeeze.\n", dev->name);
- return -ENOMEM;
- }
-
+
switch(ioc->cmd) {
case DE4X5_GET_HWADDR: /* Get the hardware address */
ioc->len = ETH_ALEN;
@@ -4710,7 +4792,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
build_setup_frame(dev, PHYS_ADDR_ONLY);
/* Set up the descriptor and give ownership to the card */
- while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
+ while (test_and_set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
SETUP_FRAME_LEN, NULL);
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
@@ -4743,39 +4825,12 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
break;
case DE4X5_GET_MCA: /* Get the multicast address table */
- ioc->len = (HASH_TABLE_LEN >> 3);
- status = verify_area(VERIFY_WRITE, ioc->data, ioc->len);
- if (!status) {
- copy_to_user(ioc->data, lp->setup_frame, ioc->len);
- }
-
break;
case DE4X5_SET_MCA: /* Set a multicast address */
- if (suser()) {
- /******* FIX ME! ********/
- if (ioc->len != HASH_TABLE_LEN) { /* MCA changes */
- if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN * ioc->len))) {
- copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
- set_multicast_list(dev);
- }
- } else {
- set_multicast_list(dev);
- }
- } else {
- status = -EPERM;
- }
-
break;
case DE4X5_CLR_MCA: /* Clear all multicast addresses */
- if (suser()) {
- /******* FIX ME! ********/
- set_multicast_list(dev);
- } else {
- status = -EPERM;
- }
-
break;
- case DE4X5_MCA_EN: /* Enable pass all multicast addressing */
+ case DE4X5_MCA_EN: /* Enable pass all multicast addresses*/
if (suser()) {
omr = inl(DE4X5_OMR);
omr |= OMR_PM;
@@ -4840,7 +4895,8 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
break;
-#define DE4X5_DUMP 0x0f /* Dump the DE4X5 Status */
+/*
+#define DE4X5_DUMP 0x0f / * Dump the DE4X5 Status * /
case DE4X5_DUMP:
j = 0;
@@ -4931,12 +4987,11 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
break;
+*/
default:
status = -EOPNOTSUPP;
}
-
- kfree(tmp.addr);
-
+
return status;
}
@@ -4975,6 +5030,30 @@ cleanup_module(void)
return;
}
+
+static struct device *
+unlink_modules(struct device *p)
+{
+ struct device *next = NULL;
+
+ if (p->priv) { /* Private areas allocated? */
+ struct de4x5_private *lp = (struct de4x5_private *)p->priv;
+
+ next = lp->next_module;
+ if (lp->cache.buf) { /* MAC buffers allocated? */
+ kfree(lp->cache.buf); /* Free the MAC buffers */
+ }
+ kfree(lp->cache.priv); /* Free the private area */
+ release_region(p->base_addr, (lp->bus == PCI ?
+ DE4X5_PCI_TOTAL_SIZE :
+ DE4X5_EISA_TOTAL_SIZE));
+ }
+ unregister_netdev(p);
+ kfree(p); /* Free the device structure */
+
+ return next;
+}
+
#endif /* MODULE */
diff --git a/drivers/net/de4x5.h b/drivers/net/de4x5.h
index bda97578c..525e0122d 100644
--- a/drivers/net/de4x5.h
+++ b/drivers/net/de4x5.h
@@ -139,7 +139,7 @@
#define CFCS_DST 0x06000000 /* DEVSEL Timing (S) */
#define CFCS_DPR 0x01000000 /* Data Parity Report (S) */
#define CFCS_FBB 0x00800000 /* Fast Back-To-Back (S) */
-#define CFCS_SLE 0x00000100 /* System Error Enable (C) */
+#define CFCS_SEE 0x00000100 /* System Error Enable (C) */
#define CFCS_PER 0x00000040 /* Parity Error Response (C) */
#define CFCS_MO 0x00000004 /* Master Operation (C) */
#define CFCS_MSA 0x00000002 /* Memory Space Access (C) */
@@ -150,8 +150,8 @@
*/
#define CFRV_BC 0xff000000 /* Base Class */
#define CFRV_SC 0x00ff0000 /* Subclass */
-#define CFRV_SN 0x000000f0 /* Step Number */
-#define CFRV_RN 0x0000000f /* Revision Number */
+#define CFRV_RN 0x000000f0 /* Revision Number */
+#define CFRV_SN 0x0000000f /* Step Number */
#define BASE_CLASS 0x02000000 /* Indicates Network Controller */
#define SUB_CLASS 0x00000000 /* Indicates Ethernet Controller */
#define STEP_NUMBER 0x00000020 /* Increments for future chips */
@@ -170,12 +170,33 @@
#define CBIO_IOSI 0x00000001 /* I/O Space Indicator (RO, value is 1) */
/*
+** PCI Configuration Card Information Structure Register (PCI_CCIS)
+*/
+#define CCIS_ROMI 0xf0000000 /* ROM Image */
+#define CCIS_ASO 0x0ffffff8 /* Address Space Offset */
+#define CCIS_ASI 0x00000007 /* Address Space Indicator */
+
+/*
+** PCI Configuration Subsystem ID Register (PCI_SSID)
+*/
+#define SSID_SSID 0xffff0000 /* Subsystem ID */
+#define SSID_SVID 0x0000ffff /* Subsystem Vendor ID */
+
+/*
** PCI Configuration Expansion ROM Base Address Register (PCI_CBER)
*/
#define CBER_MASK 0xfffffc00 /* Expansion ROM Base Address Mask */
#define CBER_ROME 0x00000001 /* ROM Enable */
/*
+** PCI Configuration Interrupt Register (PCI_CFIT)
+*/
+#define CFIT_MXLT 0xff000000 /* MAX_LAT Value (0.25us periods) */
+#define CFIT_MNGT 0x00ff0000 /* MIN_GNT Value (0.25us periods) */
+#define CFIT_IRQP 0x0000ff00 /* Interrupt Pin */
+#define CFIT_IRQL 0x000000ff /* Interrupt Line */
+
+/*
** PCI Configuration Power Management Area Register (PCI_CFPM)
*/
#define SLEEP 0x80 /* Power Saving Sleep Mode */
@@ -188,6 +209,7 @@
/*
** DC21040 Bus Mode Register (DE4X5_BMR)
*/
+#define BMR_RML 0x00200000 /* [Memory] Read Multiple */
#define BMR_DBO 0x00100000 /* Descriptor Byte Ordering (Endian) */
#define BMR_TAP 0x000e0000 /* Transmit Automatic Polling */
#define BMR_DAS 0x00010000 /* Diagnostic Address Space */
@@ -198,6 +220,7 @@
#define BMR_BAR 0x00000002 /* Bus ARbitration */
#define BMR_SWR 0x00000001 /* Software Reset */
+ /* Timings here are for 10BASE-T/AUI only*/
#define TAP_NOPOLL 0x00000000 /* No automatic polling */
#define TAP_200US 0x00020000 /* TX automatic polling every 200us */
#define TAP_800US 0x00040000 /* TX automatic polling every 800us */
@@ -249,18 +272,21 @@
#define TRBA 0xfffffffc /* TX Descriptor List Start Address */
/*
-** DC21040 Status Register (DE4X5_STS)
+** Status Register (DE4X5_STS)
*/
+#define STS_GPI 0x04000000 /* General Purpose Port Interrupt */
#define STS_BE 0x03800000 /* Bus Error Bits */
#define STS_TS 0x00700000 /* Transmit Process State */
#define STS_RS 0x000e0000 /* Receive Process State */
#define STS_NIS 0x00010000 /* Normal Interrupt Summary */
#define STS_AIS 0x00008000 /* Abnormal Interrupt Summary */
#define STS_ER 0x00004000 /* Early Receive */
+#define STS_FBE 0x00002000 /* Fatal Bus Error */
#define STS_SE 0x00002000 /* System Error */
#define STS_LNF 0x00001000 /* Link Fail */
#define STS_FD 0x00000800 /* Full-Duplex Short Frame Received */
#define STS_TM 0x00000800 /* Timer Expired (DC21041) */
+#define STS_ETI 0x00000400 /* Early Transmit Interupt */
#define STS_AT 0x00000400 /* AUI/TP Pin */
#define STS_RWT 0x00000200 /* Receive Watchdog Time-Out */
#define STS_RPS 0x00000100 /* Receive Process Stopped */
@@ -268,6 +294,7 @@
#define STS_RI 0x00000040 /* Receive Interrupt */
#define STS_UNF 0x00000020 /* Transmit Underflow */
#define STS_LNP 0x00000010 /* Link Pass */
+#define STS_ANC 0x00000010 /* Autonegotiation Complete */
#define STS_TJT 0x00000008 /* Transmit Jabber Time-Out */
#define STS_TU 0x00000004 /* Transmit Buffer Unavailable */
#define STS_TPS 0x00000002 /* Transmit Process Stopped */
@@ -300,8 +327,10 @@
#define INT_CANCEL 0x0001ffff /* For zeroing all interrupt sources */
/*
-** DC21040 Operation Mode Register (DE4X5_OMR)
+** Operation Mode Register (DE4X5_OMR)
*/
+#define OMR_SC 0x80000000 /* Special Capture Effect Enable */
+#define OMR_RA 0x40000000 /* Receive All */
#define OMR_SDP 0x02000000 /* SD Polarity - MUST BE ASSERTED */
#define OMR_SCR 0x01000000 /* Scrambler Mode */
#define OMR_PCS 0x00800000 /* PCS Function */
@@ -326,27 +355,31 @@
#define OMR_SR 0x00000002 /* Start/Stop Receive */
#define OMR_HP 0x00000001 /* Hash/Perfect Receive Filtering Mode */
-#define TR_72 0x00000000 /* Threshold set to 72 bytes */
-#define TR_96 0x00004000 /* Threshold set to 96 bytes */
-#define TR_128 0x00008000 /* Threshold set to 128 bytes */
-#define TR_160 0x0000c000 /* Threshold set to 160 bytes */
+#define TR_72 0x00000000 /* Threshold set to 72 (128) bytes */
+#define TR_96 0x00004000 /* Threshold set to 96 (256) bytes */
+#define TR_128 0x00008000 /* Threshold set to 128 (512) bytes */
+#define TR_160 0x0000c000 /* Threshold set to 160 (1024) bytes */
/*
** DC21040 Interrupt Mask Register (DE4X5_IMR)
*/
+#define IMR_GPM 0x04000000 /* General Purpose Port Mask */
#define IMR_NIM 0x00010000 /* Normal Interrupt Summary Mask */
#define IMR_AIM 0x00008000 /* Abnormal Interrupt Summary Mask */
#define IMR_ERM 0x00004000 /* Early Receive Mask */
+#define IMR_FBM 0x00002000 /* Fatal Bus Error Mask */
#define IMR_SEM 0x00002000 /* System Error Mask */
#define IMR_LFM 0x00001000 /* Link Fail Mask */
#define IMR_FDM 0x00000800 /* Full-Duplex (Short Frame) Mask */
#define IMR_TMM 0x00000800 /* Timer Expired Mask (DC21041) */
+#define IMR_ETM 0x00000400 /* Early Transmit Interrupt Mask */
#define IMR_ATM 0x00000400 /* AUI/TP Switch Mask */
#define IMR_RWM 0x00000200 /* Receive Watchdog Time-Out Mask */
#define IMR_RSM 0x00000100 /* Receive Stopped Mask */
#define IMR_RUM 0x00000080 /* Receive Buffer Unavailable Mask */
#define IMR_RIM 0x00000040 /* Receive Interrupt Mask */
#define IMR_UNM 0x00000020 /* Underflow Interrupt Mask */
+#define IMR_ANM 0x00000010 /* Autonegotiation Complete Mask */
#define IMR_LPM 0x00000010 /* Link Pass */
#define IMR_TJM 0x00000008 /* Transmit Time-Out Jabber Mask */
#define IMR_TUM 0x00000004 /* Transmit Buffer Unavailable Mask */
@@ -354,13 +387,7 @@
#define IMR_TIM 0x00000001 /* Transmit Interrupt Mask */
/*
-** DC21040 Missed Frames Counter (DE4X5_MFC)
-*/
-#define MFC_OVFL 0x00010000 /* Missed Frames Counter Overflow Bit */
-#define MFC_CNTR 0x0000ffff /* Missed Frames Counter Bits */
-
-/*
-** DC21140 Missed Frames and FIFO Overflow Counters (DE4X5_MFC)
+** Missed Frames and FIFO Overflow Counters (DE4X5_MFC)
*/
#define MFC_FOCO 0x10000000 /* FIFO Overflow Counter Overflow Bit */
#define MFC_FOC 0x0ffe0000 /* FIFO Overflow Counter Bits */
@@ -461,7 +488,7 @@
** MII Management Auto Negotiation Advertisement Register
*/
#define MII_ANA_TAF 0x03e0 /* Technology Ability Field */
-#define MII_ANA_T4AM 0x0400 /* T4 Technology Ability Mask */
+#define MII_ANA_T4AM 0x0200 /* T4 Technology Ability Mask */
#define MII_ANA_TXAM 0x0180 /* TX Technology Ability Mask */
#define MII_ANA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */
#define MII_ANA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */
@@ -476,7 +503,7 @@
#define MII_ANLPA_ACK 0x4000 /* Remote Acknowledge */
#define MII_ANLPA_RF 0x2000 /* Remote Fault */
#define MII_ANLPA_TAF 0x03e0 /* Technology Ability Field */
-#define MII_ANLPA_T4AM 0x0400 /* T4 Technology Ability Mask */
+#define MII_ANLPA_T4AM 0x0200 /* T4 Technology Ability Mask */
#define MII_ANLPA_TXAM 0x0180 /* TX Technology Ability Mask */
#define MII_ANLPA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */
#define MII_ANLPA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */
@@ -547,6 +574,8 @@
#define SROM_100BASEFF 0x0008 /* 100BASE-FX full duplex */
#define BLOCK_LEN 0x7f /* Extended blocks length mask */
+#define EXT_FIELD 0x40 /* Extended blocks extension field bit */
+#define MEDIA_CODE 0x3f /* Extended blocks media code mask */
/*
** SROM Compact Format Block Masks
@@ -589,14 +618,18 @@
#define GEP_CTRL 0x00000100 /* GEP control bit */
/*
-** DC21040 SIA Status Register (DE4X5_SISR)
+** SIA Status Register (DE4X5_SISR)
*/
#define SISR_LPC 0xffff0000 /* Link Partner's Code Word */
#define SISR_LPN 0x00008000 /* Link Partner Negotiable */
#define SISR_ANS 0x00007000 /* Auto Negotiation Arbitration State */
-#define SISR_NSN 0x00000800 /* Non Stable NLPs Detected */
+#define SISR_NSN 0x00000800 /* Non Stable NLPs Detected (DC21041) */
+#define SISR_TRF 0x00000800 /* Transmit Remote Fault */
+#define SISR_NSND 0x00000400 /* Non Stable NLPs Detected (DC21142) */
#define SISR_ANR_FDS 0x00000400 /* Auto Negotiate Restart/Full Duplex Sel.*/
+#define SISR_TRA 0x00000200 /* 10BASE-T Receive Port Activity */
#define SISR_NRA 0x00000200 /* Non Selected Port Receive Activity */
+#define SISR_ARA 0x00000100 /* AUI Receive Port Activity */
#define SISR_SRA 0x00000100 /* Selected Port Receive Activity */
#define SISR_DAO 0x00000080 /* PLL All One */
#define SISR_DAZ 0x00000040 /* PLL All Zero */
@@ -606,7 +639,7 @@
#define SISR_LKF 0x00000004 /* Link Fail Status */
#define SISR_NCR 0x00000002 /* Network Connection Error */
#define SISR_PAUI 0x00000001 /* AUI_TP Indication */
-#define SIA_RESET 0x00000000 /* SIA Reset */
+#define SISR_MRA 0x00000001 /* MII Receive Port Activity */
#define ANS_NDIS 0x00000000 /* Nway disable */
#define ANS_TDIS 0x00001000 /* Transmit Disable */
@@ -617,7 +650,7 @@
#define ANS_LCHK 0x00006000 /* Link Check */
/*
-** DC21040 SIA Connectivity Register (DE4X5_SICR)
+** SIA Connectivity Register (DE4X5_SICR)
*/
#define SICR_SDM 0xffff0000 /* SIA Diagnostics Mode */
#define SICR_OE57 0x00008000 /* Output Enable 5 6 7 */
@@ -636,14 +669,14 @@
#define SICR_SIM 0x00000040 /* Serial Interface Input Multiplexer */
#define SICR_ENI 0x00000020 /* Encoder Input Multiplexer */
#define SICR_EDP 0x00000010 /* SIA PLL External Input Enable */
-#define SICR_AUI 0x00000008 /* 10Base-T or AUI */
+#define SICR_AUI 0x00000008 /* 10Base-T (0) or AUI (1) */
#define SICR_CAC 0x00000004 /* CSR Auto Configuration */
#define SICR_PS 0x00000002 /* Pin AUI/TP Selection */
#define SICR_SRL 0x00000001 /* SIA Reset */
-#define SICR_RESET 0xffff0000 /* Reset value for SICR */
+#define SIA_RESET 0x00000000 /* SIA Reset Value */
/*
-** DC21040 SIA Transmit and Receive Register (DE4X5_STRR)
+** SIA Transmit and Receive Register (DE4X5_STRR)
*/
#define STRR_TAS 0x00008000 /* 10Base-T/AUI Autosensing Enable */
#define STRR_SPP 0x00004000 /* Set Polarity Plus */
@@ -663,8 +696,20 @@
#define STRR_RESET 0xffffffff /* Reset value for STRR */
/*
-** DC21040 SIA General Register (DE4X5_SIGR)
-*/
+** SIA General Register (DE4X5_SIGR)
+*/
+#define SIGR_RMI 0x40000000 /* Receive Match Interrupt */
+#define SIGR_GI1 0x20000000 /* General Port Interrupt 1 */
+#define SIGR_GI0 0x10000000 /* General Port Interrupt 0 */
+#define SIGR_CWE 0x08000000 /* Control Write Enable */
+#define SIGR_RME 0x04000000 /* Receive Match Enable */
+#define SIGR_GEI1 0x02000000 /* GEP Interrupt Enable on Port 1 */
+#define SIGR_GEI0 0x01000000 /* GEP Interrupt Enable on Port 0 */
+#define SIGR_LGS3 0x00800000 /* LED/GEP3 Select */
+#define SIGR_LGS2 0x00400000 /* LED/GEP2 Select */
+#define SIGR_LGS1 0x00200000 /* LED/GEP1 Select */
+#define SIGR_LGS0 0x00100000 /* LED/GEP0 Select */
+#define SIGR_MD 0x000f0000 /* General Purpose Mode and Data */
#define SIGR_LV2 0x00008000 /* General Purpose LED2 value */
#define SIGR_LE2 0x00004000 /* General Purpose LED2 enable */
#define SIGR_FRL 0x00002000 /* Force Receiver Low */
@@ -687,7 +732,8 @@
** Receive Descriptor Bit Summary
*/
#define R_OWN 0x80000000 /* Own Bit */
-#define RD_FL 0x7fff0000 /* Frame Length */
+#define RD_FF 0x40000000 /* Filtering Fail */
+#define RD_FL 0x3fff0000 /* Frame Length */
#define RD_ES 0x00008000 /* Error Summary */
#define RD_LE 0x00004000 /* Length Error */
#define RD_DT 0x00003000 /* Data Type */
@@ -699,6 +745,7 @@
#define RD_CS 0x00000040 /* Collision Seen */
#define RD_FT 0x00000020 /* Frame Type */
#define RD_RJ 0x00000010 /* Receive Watchdog */
+#define RD_RE 0x00000008 /* Report on MII Error */
#define RD_DB 0x00000004 /* Dribbling Bit */
#define RD_CE 0x00000002 /* CRC Error */
#define RD_OF 0x00000001 /* Overflow */
@@ -734,40 +781,39 @@
#define TD_TCH 0x01000000 /* Second Address Chained */
#define TD_DPD 0x00800000 /* Disabled Padding */
#define TD_FT0 0x00400000 /* Filtering Type */
-#define TD_RBS2 0x003ff800 /* Buffer 2 Size */
-#define TD_RBS1 0x000007ff /* Buffer 1 Size */
+#define TD_TBS2 0x003ff800 /* Buffer 2 Size */
+#define TD_TBS1 0x000007ff /* Buffer 1 Size */
#define PERFECT_F 0x00000000
#define HASH_F TD_FT0
#define INVERSE_F TD_FT1
-#define HASH_O_F TD_FT1| TD_F0
+#define HASH_O_F (TD_FT1 | TD_F0)
/*
** Media / mode state machine definitions
*/
-#define NC 0x0000 /* No Connection */
-#define TP 0x0001 /* 10Base-T */
-#define TP_NW 0x0002 /* 10Base-T with Nway */
-#define BNC 0x0004 /* Thinwire */
-#define AUI 0x0008 /* Thickwire */
+#define NC 0x0000 /* No Connection */
+#define TP 0x0001 /* 10Base-T */
+#define TP_NW 0x0002 /* 10Base-T with Nway */
+#define BNC 0x0004 /* Thinwire */
+#define AUI 0x0008 /* Thickwire */
#define BNC_AUI 0x0010 /* BNC/AUI on DC21040 indistinguishable */
-#define ANS 0x0020 /* Intermediate AutoNegotiation State */
-#define ANS_1 0x0021 /* Intermediate AutoNegotiation State */
-
-#define _10Mb 0x0040 /* 10Mb/s Ethernet */
-#define _100Mb 0x0080 /* 100Mb/s Ethernet */
-#define SPD_DET 0x0100 /* Parallel speed detection */
-#define INIT 0x0200 /* Initial state */
-#define EXT_SIA 0x0400 /* External SIA for motherboard chip */
-#define ANS_SUSPECT 0x0802 /* Suspect the ANS (TP) port is down */
-#define TP_SUSPECT 0x0803 /* Suspect the TP port is down */
-#define BNC_AUI_SUSPECT 0x0804 /* Suspect the BNC or AUI port is down */
-#define EXT_SIA_SUSPECT 0x0805 /* Suspect the EXT SIA port is down */
-#define BNC_SUSPECT 0x0806 /* Suspect the BNC port is down */
-#define AUI_SUSPECT 0x0807 /* Suspect the AUI port is down */
-
-#define AUTO 0x4000 /* Auto sense the media or speed */
-#define TIMER_CB 0x80000000 /* Timer callback detection */
+#define ANS 0x0020 /* Intermediate AutoNegotiation State */
+#define _10Mb 0x0040 /* 10Mb/s Ethernet */
+#define _100Mb 0x0080 /* 100Mb/s Ethernet */
+#define SPD_DET 0x0100 /* Parallel speed detection */
+#define INIT 0x0200 /* Initial state */
+#define EXT_SIA 0x0400 /* External SIA for motherboard chip */
+#define ANS_SUSPECT 0x0802 /* Suspect the ANS (TP) port is down */
+#define TP_SUSPECT 0x0803 /* Suspect the TP port is down */
+#define BNC_AUI_SUSPECT 0x0804 /* Suspect the BNC or AUI port is down */
+#define EXT_SIA_SUSPECT 0x0805 /* Suspect the EXT SIA port is down */
+#define BNC_SUSPECT 0x0806 /* Suspect the BNC port is down */
+#define AUI_SUSPECT 0x0807 /* Suspect the AUI port is down */
+#define MII 0x1000 /* MII on the 21143 */
+
+#define AUTO 0x4000 /* Auto sense the media or speed */
+#define TIMER_CB 0x80000000 /* Timer callback detection */
/*
** DE4X5 DEBUG Options
@@ -798,7 +844,6 @@
#define POLL_DEMAND 1
#define LOST_MEDIA_THRESHOLD 3
-#define LOST_MEDIA (lp->lostMedia > LOST_MEDIA_THRESHOLD)
#define MASK_INTERRUPTS 1
#define UNMASK_INTERRUPTS 0
@@ -859,7 +904,7 @@
}\
omr |= ((lp->fdx ? OMR_FDX : 0) | OMR_TTM);\
outl(omr, DE4X5_OMR);\
- lp->cache.gep = 0;\
+ if (!lp->useSROM) lp->cache.gep = 0;\
} else if (lp->useSROM && !lp->useMII) {\
omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
omr |= (lp->fdx ? OMR_FDX : 0);\
@@ -887,7 +932,7 @@
}\
if (fdx) omr |= OMR_FDX;\
outl(omr, DE4X5_OMR);\
- lp->cache.gep = 0;\
+ if (!lp->useSROM) lp->cache.gep = 0;\
} else if (lp->useSROM && !lp->useMII) {\
omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
omr |= (lp->fdx ? OMR_FDX : 0);\
@@ -906,7 +951,6 @@
mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
outl(omr, DE4X5_OMR);\
- lp->cache.gep = 0;\
} else if (lp->useSROM && !lp->useMII) {\
omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
outl(omr, DE4X5_OMR);\
@@ -934,7 +978,7 @@ struct de4x5_ioctl {
** Recognised commands for the driver
*/
#define DE4X5_GET_HWADDR 0x01 /* Get the hardware address */
-#define DE4X5_SET_HWADDR 0x02 /* Get the hardware address */
+#define DE4X5_SET_HWADDR 0x02 /* Set the hardware address */
#define DE4X5_SET_PROM 0x03 /* Set Promiscuous Mode */
#define DE4X5_CLR_PROM 0x04 /* Clear Promiscuous Mode */
#define DE4X5_SAY_BOO 0x05 /* Say "Boo!" to the kernel log file */
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 5e50cbfa5..659e71f32 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -226,6 +226,11 @@ static const char *version = "defxx.c:v1.04 09/16/96 Lawrence V. Stefani (stefa
#include "defxx.h"
+#define DYNAMIC_BUFFERS 1
+
+#define SKBUFF_RX_COPYBREAK 200
+#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX)
+
/* Define global routines */
int dfx_probe(struct device *dev);
@@ -1083,7 +1088,9 @@ __initfunc(int dfx_driver_init(
alloc_size = sizeof(PI_DESCR_BLOCK) +
PI_CMD_REQ_K_SIZE_MAX +
PI_CMD_RSP_K_SIZE_MAX +
+#ifndef DYNAMIC_BUFFERS
(bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) +
+#endif
sizeof(PI_CONSUMER_BLOCK) +
(PI_ALIGN_K_DESC_BLK - 1);
top_v = (char *) kmalloc(alloc_size, GFP_KERNEL);
@@ -1135,8 +1142,11 @@ __initfunc(int dfx_driver_init(
bp->rcv_block_virt = curr_v;
bp->rcv_block_phys = curr_p;
+
+#ifndef DYNAMIC_BUFFERS
curr_v += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX);
curr_p += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX);
+#endif
/* Reserve space for the consumer block */
@@ -2926,6 +2936,22 @@ void dfx_rcv_init(
* driver initialization when we allocated memory for the receive buffers.
*/
+#ifdef DYNAMIC_BUFFERS
+ for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++)
+ for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post)
+ {
+ struct sk_buff *newskb;
+ bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP |
+ ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN));
+ newskb = dev_alloc_skb(NEW_SKB_SIZE);
+ bp->descr_block_virt->rcv_data[i+j].long_1 = virt_to_bus(newskb->data);
+ /*
+ * p_rcv_buff_va is only used inside the
+ * kernel so we put the skb pointer here.
+ */
+ bp->p_rcv_buff_va[i+j] = (char *) newskb;
+ }
+#else
for (i=0; i < (int)(bp->rcv_bufs_to_post); i++)
for (j=0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post)
{
@@ -2934,6 +2960,7 @@ void dfx_rcv_init(
bp->descr_block_virt->rcv_data[i+j].long_1 = (u32) (bp->rcv_block_phys + (i * PI_RCV_DATA_K_SIZE_MAX));
bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX));
}
+#endif
/* Update receive producer and Type 2 register */
@@ -2985,6 +3012,8 @@ void dfx_rcv_queue_process(
u32 descr, pkt_len; /* FMC descriptor field and packet length */
struct sk_buff *skb; /* pointer to a sk_buff to hold incoming packet data */
+ static int testing_dyn;
+
/* Service all consumed LLC receive frames */
p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data);
@@ -2992,7 +3021,14 @@ void dfx_rcv_queue_process(
{
/* Process any errors */
- p_buff = (char *) bp->p_rcv_buff_va[bp->rcv_xmt_reg.index.rcv_comp];
+ int entry;
+
+ entry = bp->rcv_xmt_reg.index.rcv_comp;
+#ifdef DYNAMIC_BUFFERS
+ p_buff = (char *) (((struct sk_buff *)bp->p_rcv_buff_va[entry])->data);
+#else
+ p_buff = (char *) bp->p_rcv_buff_va[entry];
+#endif
memcpy(&descr, p_buff + RCV_BUFF_K_DESCR, sizeof(u32));
if (descr & PI_FMC_DESCR_M_RCC_FLUSH)
@@ -3003,29 +3039,60 @@ void dfx_rcv_queue_process(
bp->rcv_frame_status_errors++;
}
else
- {
+ {
+ int rx_in_place = 0;
+
/* The frame was received without errors - verify packet length */
pkt_len = (u32)((descr & PI_FMC_DESCR_M_LEN) >> PI_FMC_DESCR_V_LEN);
pkt_len -= 4; /* subtract 4 byte CRC */
if (!IN_RANGE(pkt_len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN))
bp->rcv_length_errors++;
- else
- {
- skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */
+ else{
+#ifdef DYNAMIC_BUFFERS
+ if (pkt_len > SKBUFF_RX_COPYBREAK) {
+ struct sk_buff *newskb;
+
+ newskb = dev_alloc_skb(NEW_SKB_SIZE);
+ if (newskb){
+ rx_in_place = 1;
+#define JES_TESTING
+#ifdef JES_TESTING
+ if(testing_dyn++ < 5)
+ printk("Skipping a memcpy\n");
+ skb = (struct sk_buff *)bp->p_rcv_buff_va[entry];
+ skb->data += RCV_BUFF_K_PADDING;
+ bp->p_rcv_buff_va[entry] = (char *)newskb;
+ bp->descr_block_virt->rcv_data[entry].long_1 = virt_to_bus(newskb->data);
+#else
+ memcpy(newskb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
+ skb = newskb;
+#endif
+ } else
+ skb = 0;
+ } else
+#endif
+ skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */
if (skb == NULL)
{
printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name);
bp->rcv_discards++;
+ break;
}
- else
+ else {
+#ifndef DYNAMIC_BUFFERS
+ if (! rx_in_place)
+#endif
{
- /* Receive buffer allocated, pass receive packet up */
+ /* Receive buffer allocated, pass receive packet up */
+
+ memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
+ }
- memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
skb->data += 3; /* adjust data field so that it points to FC byte */
skb->len = pkt_len; /* pass up packet length, NOT including CRC */
skb->dev = bp->dev; /* pass up device pointer */
+
skb->protocol = fddi_type_trans(skb, bp->dev);
netif_rx(skb);
@@ -3034,9 +3101,9 @@ void dfx_rcv_queue_process(
bp->rcv_total_frames++;
if (*(p_buff + RCV_BUFF_K_DA) & 0x01)
bp->rcv_multicast_frames++;
- }
}
}
+ }
/*
* Advance the producer (for recycling) and advance the completion
@@ -3140,6 +3207,7 @@ int dfx_xmt_queue_pkt(
dev->name, skb->len);
bp->xmt_length_errors++; /* bump error counter */
dev_tint(dev); /* dequeue packets from xmt queue and send them */
+ dev_kfree_skb(skb, FREE_WRITE);
return(0); /* return "success" */
}
/*
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 85cf704c5..74246fa7a 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -804,7 +804,7 @@ depca_start_xmit(struct sk_buff *skb, struct device *dev)
dev_tint(dev);
} else if (skb->len > 0) {
/* Enforce 1 process per h/w access */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
status = -1;
} else {
diff --git a/drivers/net/dlci.c b/drivers/net/dlci.c
index e42b0dcf4..08d9901ba 100644
--- a/drivers/net/dlci.c
+++ b/drivers/net/dlci.c
@@ -248,7 +248,7 @@ static int dlci_transmit(struct sk_buff *skb, struct device *dev)
dlp = dev->priv;
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
else
{
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 814d798c5..877e2256e 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -134,7 +134,7 @@ int init_module(void)
{
/* Find a name for this unit */
int err=dev_alloc_name(&dev_dummy,"dummy%d");
- if(err)
+ if(err<0)
return err;
if (register_netdev(&dev_dummy) != 0)
return -EIO;
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 72060c53b..25167fa0b 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -714,7 +714,7 @@ eepro_send_packet(struct sk_buff *skb, struct device *dev)
}
/* Block a timer-based transmit from overlapping. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index cf67f942b..af117e223 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -1033,7 +1033,7 @@ speedo_start_xmit(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
If this ever occurs the queue layer is doing something evil! */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < TX_TIMEOUT - 2)
return 1;
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index f5b75bb9f..8e8852bc0 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -94,6 +94,7 @@
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -301,7 +302,7 @@ static inline short int SHADOW(short int addr)
* checks for presence of EtherExpress card
*/
-int express_probe(struct device *dev)
+__initfunc(int express_probe(struct device *dev))
{
unsigned short *port;
static unsigned short ports[] = { 0x300,0x310,0x270,0x320,0x340,0 };
@@ -525,7 +526,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev)
}
}
- if (set_bit(0,(void *)&dev->tbusy))
+ if (test_and_set_bit(0,(void *)&dev->tbusy))
{
lp->stats.tx_dropped++;
}
@@ -913,7 +914,7 @@ static void eexp_hw_tx_pio(struct device *dev, unsigned short *buf,
* than one card in a machine.
*/
-static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)
+__initfunc(static int eexp_hw_probe(struct device *dev, unsigned short ioaddr))
{
unsigned short hw_addr[3];
unsigned char buswidth;
@@ -1034,8 +1035,8 @@ static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)
* Read a word from the EtherExpress on-board serial EEPROM.
* The EEPROM contains 64 words of 16 bits.
*/
-static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
- unsigned char location)
+__initfunc(static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
+ unsigned char location))
{
unsigned short cmd = 0x180|(location&0x7f);
unsigned short rval = 0,wval = EC_CS|i586_RST;
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index 24e449390..74cf38d50 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -932,7 +932,7 @@ static int eth16i_tx(struct sk_buff *skb, struct device *dev)
/* Turn off TX interrupts */
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- if(set_bit(0, (void *)&dev->tbusy) != 0)
+ if(test_and_set_bit(0, (void *)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index 3c3752251..75492e1c1 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -767,7 +767,7 @@ ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev)
** Block a timer-based transmit from overlapping. This could better be
** done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
*/
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
DISABLE_IRQs; /* So that the page # remains correct */
@@ -783,7 +783,7 @@ ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev)
/*
** Set up shared memory window and pointer into the window
*/
- while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+ while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
if (lp->shmem_length == IO_ONLY) {
outb(page, EWRK3_IOPR);
} else if (lp->shmem_length == SHMEM_2K) {
@@ -953,7 +953,7 @@ ewrk3_rx(struct device *dev)
** Preempt any process using the current page register. Check for
** an existing lock to reduce time taken in I/O transactions.
*/
- if ((tmpLock = set_bit(0, (void *)&lp->lock)) == 1) { /* Assert lock */
+ if ((tmpLock = test_and_set_bit(0, (void *)&lp->lock)) == 1) { /* Assert lock */
if (lp->shmem_length == IO_ONLY) { /* Get existing page */
tmpPage = inb(EWRK3_IOPR);
} else {
@@ -1217,7 +1217,7 @@ static void SetMulticastFilter(struct device *dev)
u16 hashcode;
s32 crc, poly = CRC_POLYNOMIAL_LE;
- while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+ while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
if (lp->shmem_length == IO_ONLY) {
outb(0, EWRK3_IOPR);
@@ -1723,7 +1723,7 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd)
break;
case EWRK3_GET_MCA: /* Get the multicast address table */
if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
- while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+ while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
if (lp->shmem_length == IO_ONLY) {
outb(0, EWRK3_IOPR);
outw(PAGE0_HTE, EWRK3_PIR1);
diff --git a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c
index 7536a7e04..59362c8fe 100644
--- a/drivers/net/fmv18x.c
+++ b/drivers/net/fmv18x.c
@@ -348,7 +348,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/net/hdlcdrv.c b/drivers/net/hdlcdrv.c
index 9098fdf2e..467980406 100644
--- a/drivers/net/hdlcdrv.c
+++ b/drivers/net/hdlcdrv.c
@@ -288,7 +288,7 @@ void hdlcdrv_receiver(struct device *dev, struct hdlcdrv_state *s)
if (!s || s->magic != HDLCDRV_MAGIC)
return;
- if (set_bit(0, &s->hdlcrx.in_hdlc_rx))
+ if (test_and_set_bit(0, &s->hdlcrx.in_hdlc_rx))
return;
while (!hdlcdrv_hbuf_empty(&s->hdlcrx.hbuf)) {
@@ -387,7 +387,7 @@ void hdlcdrv_transmitter(struct device *dev, struct hdlcdrv_state *s)
if (!s || s->magic != HDLCDRV_MAGIC)
return;
- if (set_bit(0, &s->hdlctx.in_hdlc_tx))
+ if (test_and_set_bit(0, &s->hdlctx.in_hdlc_tx))
return;
for (;;) {
if (s->hdlctx.numbits >= 16) {
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 6a599dd60..0780e038f 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1,89 +1,54 @@
/*
- * hp100.c: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux.
- *
- * Author: Jaroslav Kysela, <perex@pf.jcu.cz>
- *
- * Supports only the following Hewlett Packard cards:
- *
- * HP J2577 10/100 EISA card with REVA Cascade chip
- * HP J2573 10/100 ISA card with REVA Cascade chip
- * HP 27248B 10 only EISA card with Cascade chip
- * HP J2577 10/100 EISA card with Cascade chip
- * HP J2573 10/100 ISA card with Cascade chip
- * HP J2585 10/100 PCI card
- *
- * Other ATT2MD01 Chip based boards might be supported in the future
- * (there are some minor changes needed).
- *
- * This driver is based on the 'hpfepkt' crynwr packet driver.
- *
- * This source/code is public free; you can distribute it and/or modify
- * it under terms of the GNU General Public License (published by the
- * Free Software Foundation) either version two of this License, or any
- * later version.
- * ----------------------------------------------------------------------------
- *
- * Note: Some routines (interrupt handling, transmit) assumes that
- * there is the PERFORMANCE page selected...
- *
- * ----------------------------------------------------------------------------
- *
- * If you are going to use the module version of this driver, you may
- * change this values at the "insert time" :
- *
- * Variable Description
- *
- * hp100_rx_ratio Range 1-99 - onboard memory used for RX
- * packets in %.
- * hp100_priority_tx If this variable is nonzero - all outgoing
- * packets will be transmitted as priority.
- * hp100_port Adapter port (for example 0x380).
- *
- * ----------------------------------------------------------------------------
- * MY BEST REGARDS GOING TO:
- *
- * IPEX s.r.o which lend me two HP J2573 cards and
- * the HP AdvanceStack 100VG Hub-15 for debugging.
- *
- * Russel Nellson <nelson@crynwr.com> for help with obtaining sources
- * of the 'hpfepkt' packet driver.
- *
- * Also thanks to Abacus Electric s.r.o which let me to use their
- * motherboard for my second computer.
- *
- * ----------------------------------------------------------------------------
- *
- * TO DO:
- * ======
- * - ioctl handling - some runtime setup things
- * - 100Mb/s Voice Grade AnyLAN network adapter/hub services support
- * - 802.5 frames
- * - promiscuous mode
- * - bridge mode
- * - cascaded repeater mode
- * - 100Mbit MAC
- *
- * Revision history:
- * =================
- *
- * Version Date Description
- *
- * 0.1 14-May-95 Initial writing. ALPHA code was released.
- * Only HP J2573 on 10Mb/s (two machines) tested.
- * 0.11 14-Jun-95 Reset interface bug fixed?
- * Little bug in hp100_close function fixed.
- * 100Mb/s connection debugged.
- * 0.12 14-Jul-95 Link down is now handled better.
- * 0.20 01-Aug-95 Added PCI support for HP J2585A card.
- * Statistics bug fixed.
- * 0.21 04-Aug-95 Memory mapped access support for PCI card.
- * Added priority transmit support for 100Mb/s
- * Voice Grade AnyLAN network.
- *
- */
-
+** hp100.c
+** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters
+**
+** $Id: hp100.c,v 1.52 1997/04/21 14:20:20 perex Exp perex $
+**
+** Based on the HP100 driver written by Jaroslav Kysela <perex@jcu.cz>
+** Extended for new busmaster capable chipsets by
+** Siegfried "Frieder" Loeffler (dg1sek) <floeff@mathematik.uni-stuttgart.de>
+**
+** Maintained by: Jaroslav Kysela <perex@jcu.cz>
+**
+** This driver has only been tested with
+** -- HP J2585B 10/100 Mbit/s PCI Busmaster
+** -- HP J2585A 10/100 Mbit/s PCI
+** -- HP J2970 10 Mbit/s PCI Combo 10base-T/BNC
+** -- HP J2973 10 Mbit/s PCI 10base-T
+** -- HP J2573 10/100 ISA
+** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA
+**
+** but it should also work with the other CASCADE based adapters.
+**
+** TODO:
+** - J2573 seems to hang sometimes when in shared memory mode.
+** - Mode for Priority TX
+** - Check PCI registers, performance might be improved?
+** - To reduce interrupt load in busmaster, one could switch off
+** the interrupts that are used to refill the queues whenever the
+** queues are filled up to more than a certain threshold.
+**
+**
+** This source/code is public free; you can distribute it and/or modify
+** it under terms of the GNU General Public License (published by the
+** Free Software Foundation) either version two of this License, or any
+** later version.
+**
+*/
+
+#define HP100_DEFAULT_PRIORITY_TX 0
+
+#undef HP100_DEBUG
+#undef HP100_DEBUG_B /* Trace */
+#undef HP100_DEBUG_BM /* Debug busmaster code (PDL stuff) */
+
+#undef HP100_DEBUG_TRAINING /* Debug login-to-hub procedure */
+#undef HP100_DEBUG_TX
+#undef HP100_DEBUG_IRQ
+#undef HP100_DEBUG_RX
+
+#include <linux/version.h>
#include <linux/module.h>
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -102,7 +67,17 @@
#include <linux/skbuff.h>
#include <linux/types.h>
-#include <linux/config.h> /* for CONFIG_PCI */
+#include <linux/config.h> /* for CONFIG_PCI */
+#include <linux/delay.h>
+
+#if LINUX_VERSION_CODE < 0x020100
+#define ioremap vremap
+#define iounmap vfree
+typedef struct enet_statistics hp100_stats_t;
+#else
+#define LINUX_2_1
+typedef struct net_device_stats hp100_stats_t;
+#endif
#include "hp100.h"
@@ -110,18 +85,28 @@
* defines
*/
-#define HP100_BUS_ISA 0
-#define HP100_BUS_EISA 1
-#define HP100_BUS_PCI 2
+#define HP100_BUS_ISA 0
+#define HP100_BUS_EISA 1
+#define HP100_BUS_PCI 2
-#define HP100_REGION_SIZE 0x20
+#ifndef PCI_DEVICE_ID_HP_J2585B
+#define PCI_DEVICE_ID_HP_J2585B 0x1031
+#endif
+#ifndef PCI_VENDOR_ID_COMPEX
+#define PCI_VENDOR_ID_COMPEX 0x11f6
+#endif
+#ifndef PCI_DEVICE_ID_COMPEX_ENET100VG4
+#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112
+#endif
+
+#define HP100_REGION_SIZE 0x20 /* for ioports */
-#define HP100_MAX_PACKET_SIZE (1536+4)
-#define HP100_MIN_PACKET_SIZE 60
+#define HP100_MAX_PACKET_SIZE (1536+4)
+#define HP100_MIN_PACKET_SIZE 60
#ifndef HP100_DEFAULT_RX_RATIO
-/* default - 65% onboard memory on the card are used for RX packets */
-#define HP100_DEFAULT_RX_RATIO 65
+/* default - 75% onboard memory on the card are used for RX packets */
+#define HP100_DEFAULT_RX_RATIO 75
#endif
#ifndef HP100_DEFAULT_PRIORITY_TX
@@ -141,18 +126,37 @@ struct hp100_eisa_id {
struct hp100_private {
struct hp100_eisa_id *id;
+ u_short chip;
u_short soft_model;
- u_int memory_size;
- u_short rx_ratio; /* 1 - 99 */
- u_short priority_tx; /* != 0 - priority tx */
- short mem_mapped; /* memory mapped access */
- u_char *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */
- u_char *mem_ptr_phys; /* physical memory mapped area */
- short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */
- int hub_status; /* login to hub was successful? */
+ u_int memory_size;
+ u_short rx_ratio; /* 1 - 99 */
+ u_short priority_tx; /* != 0 - priority tx */
+ u_short mode; /* PIO, Shared Mem or Busmaster */
+ u_char bus;
+ u_char pci_bus;
+ u_char pci_device_fn;
+ short mem_mapped; /* memory mapped access */
+ u_int *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */
+ u_int *mem_ptr_phys; /* physical memory mapped area */
+ short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */
+ int hub_status; /* was login to hub successful? */
u_char mac1_mode;
u_char mac2_mode;
- struct net_device_stats stats;
+ hp100_stats_t stats;
+
+ /* Rings for busmaster mode: */
+ hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */
+ hp100_ring_t *rxrtail; /* Tail (newest) index into rxring */
+ hp100_ring_t *txrhead; /* Head (oldest) index into txring */
+ hp100_ring_t *txrtail; /* Tail (newest) index into txring */
+
+ hp100_ring_t rxring[ MAX_RX_PDL ];
+ hp100_ring_t txring[ MAX_TX_PDL ];
+
+ u_int *page_vaddr; /* Virtual address of allocated page */
+ u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */
+ int rxrcommit; /* # Rx PDLs commited to adapter */
+ int txrcommit; /* # Tx PDLs commited to adapter */
};
/*
@@ -161,78 +165,124 @@ struct hp100_private {
static struct hp100_eisa_id hp100_eisa_ids[] = {
- /* 10/100 EISA card with REVA Cascade chip */
- { 0x080F1F022, "HP J2577 rev A", HP100_BUS_EISA },
+ /* 10/100 EISA card with revision A Cascade chip */
+ { 0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA },
- /* 10/100 ISA card with REVA Cascade chip */
- { 0x050F1F022, "HP J2573 rev A", HP100_BUS_ISA },
+ /* 10/100 ISA card with revision A Cascade chip */
+ { 0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA },
/* 10 only EISA card with Cascade chip */
- { 0x02019F022, "HP 27248B", HP100_BUS_EISA },
+ { 0x2019F022, "HP 27248B", HP100_BUS_EISA },
/* 10/100 EISA card with Cascade chip */
- { 0x04019F022, "HP J2577", HP100_BUS_EISA },
+ { 0x4019F022, "HP J2577", HP100_BUS_EISA },
/* 10/100 ISA card with Cascade chip */
- { 0x05019F022, "HP J2573", HP100_BUS_ISA },
+ { 0x5019F022, "HP J2573", HP100_BUS_ISA },
- /* 10/100 PCI card */
- /* Note: ID for this card is same as PCI vendor/device numbers. */
- { 0x01030103c, "HP J2585", HP100_BUS_PCI },
+ /* 10/100 PCI card - old J2585A */
+ { 0x1030103c, "HP J2585A", HP100_BUS_PCI },
+
+ /* 10/100 PCI card - new J2585B - master capable */
+ { 0x1041103c, "HP J2585B", HP100_BUS_PCI },
+
+ /* 10 Mbit Combo Adapter */
+ { 0x1042103c, "HP J2970", HP100_BUS_PCI },
+
+ /* 10 Mbit 10baseT Adapter */
+ { 0x1040103c, "HP J2973", HP100_BUS_PCI },
+
+ /* 10/100 EISA card from Compex */
+ { 0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA },
+
+ /* 10/100 PCI card from Compex (J2585A compatible) */
+ { 0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI }
};
static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO;
static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX;
+static int hp100_mode = 1;
+
+#ifdef LINUX_2_1
+MODULE_PARM( hp100_rx_ratio, "1i" );
+MODULE_PARM( hp100_priority_tx, "1i" );
+MODULE_PARM( hp100_mode, "1i" );
+#endif
/*
* prototypes
*/
-static int hp100_probe1( struct device *dev, int ioaddr, int bus );
-static int hp100_open( struct device *dev );
-static int hp100_close( struct device *dev );
-static int hp100_start_xmit( struct sk_buff *skb, struct device *dev );
+static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn );
+static int hp100_open( struct device *dev );
+static int hp100_close( struct device *dev );
+static int hp100_start_xmit( struct sk_buff *skb, struct device *dev );
+static int hp100_start_xmit_bm (struct sk_buff *skb, struct device *dev );
static void hp100_rx( struct device *dev );
-static struct net_device_stats *hp100_get_stats( struct device *dev );
+static hp100_stats_t *hp100_get_stats( struct device *dev );
static void hp100_update_stats( struct device *dev );
static void hp100_clear_stats( int ioaddr );
static void hp100_set_multicast_list( struct device *dev);
static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs );
-
static void hp100_start_interface( struct device *dev );
static void hp100_stop_interface( struct device *dev );
static void hp100_load_eeprom( struct device *dev );
-static int hp100_sense_lan( struct device *dev );
-static int hp100_login_to_vg_hub( struct device *dev );
-static int hp100_down_vg_link( struct device *dev );
+static int hp100_sense_lan( struct device *dev );
+static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin );
+static int hp100_down_vg_link( struct device *dev );
+static void hp100_cascade_reset( struct device *dev, u_short enable );
+static void hp100_BM_shutdown( struct device *dev );
+static void hp100_mmuinit( struct device *dev );
+static void hp100_init_pdls( struct device *dev );
+static int hp100_init_rxpdl( register hp100_ring_t *ringptr, register u_int *pdlptr);
+static int hp100_init_txpdl( register hp100_ring_t *ringptr, register u_int *pdlptr);
+static void hp100_rxfill( struct device *dev );
+static void hp100_hwinit( struct device *dev );
+static void hp100_clean_txring( struct device *dev );
+#ifdef HP100_DEBUG
+static void hp100_RegisterDump( struct device *dev );
+#endif
+
+/* TODO: This function should not really be needed in a good design... */
+static void wait( void )
+{
+ udelay( 1000 );
+}
/*
* probe functions
+ * These functions should - if possible - avoid doing write operations
+ * since this could cause problems when the card is not installed.
*/
__initfunc(int hp100_probe( struct device *dev ))
{
int base_addr = dev ? dev -> base_addr : 0;
- int ioaddr;
+ int ioaddr = 0;
#ifdef CONFIG_PCI
int pci_start_index = 0;
#endif
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4200, TRACE );
+ printk( "hp100: probe\n" );
+#endif
+
if ( base_addr > 0xff ) /* Check a single specified location. */
{
if ( check_region( base_addr, HP100_REGION_SIZE ) ) return -EINVAL;
if ( base_addr < 0x400 )
- return hp100_probe1( dev, base_addr, HP100_BUS_ISA );
- else
- return hp100_probe1( dev, base_addr, HP100_BUS_EISA );
+ return hp100_probe1( dev, base_addr, HP100_BUS_ISA, 0, 0 );
+ else
+ return hp100_probe1( dev, base_addr, HP100_BUS_EISA, 0, 0 );
}
- else
+ else
#ifdef CONFIG_PCI
- if ( base_addr > 0 && base_addr < 8 + 1 )
- pci_start_index = 0x100 | ( base_addr - 1 );
- else
+ if ( base_addr > 0 && base_addr < 8 + 1 )
+ pci_start_index = 0x100 | ( base_addr - 1 );
+ else
#endif
- if ( base_addr != 0 ) return -ENXIO;
+ if ( base_addr != 0 ) return -ENXIO;
/* at first - scan PCI bus(es) */
@@ -249,65 +299,80 @@ __initfunc(int hp100_probe( struct device *dev ))
u_char pci_bus, pci_device_fn;
u_short pci_command;
- if ( pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A,
- pci_index, &pci_bus,
- &pci_device_fn ) != 0 ) break;
+ if ((pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A,
+ pci_index, &pci_bus,
+ &pci_device_fn ) != 0 ) &&
+ (pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B,
+ pci_index, &pci_bus,
+ &pci_device_fn ) != 0 ) &&
+ (pcibios_find_device( PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4,
+ pci_index, &pci_bus,
+ &pci_device_fn ) != 0 ) ) break;
+
pcibios_read_config_dword( pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &ioaddr );
+ PCI_BASE_ADDRESS_0, &ioaddr );
- ioaddr &= ~3; /* remove I/O space marker in bit 0. */
+ ioaddr &= ~3; /* remove I/O space marker in bit 0. */
if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
pcibios_read_config_word( pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command );
+ PCI_COMMAND, &pci_command );
if ( !( pci_command & PCI_COMMAND_MASTER ) )
{
-#ifdef HP100_DEBUG_PCI
+#ifdef HP100_DEBUG
printk( "hp100: PCI Master Bit has not been set. Setting...\n" );
#endif
pci_command |= PCI_COMMAND_MASTER;
pcibios_write_config_word( pci_bus, pci_device_fn,
- PCI_COMMAND, pci_command );
+ PCI_COMMAND, pci_command );
}
-#ifdef HP100_DEBUG_PCI
+#ifdef HP100_DEBUG
printk( "hp100: PCI adapter found at 0x%x\n", ioaddr );
#endif
- if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI ) == 0 ) return 0;
+ if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn ) == 0 )
+ return 0;
}
}
if ( pci_start_index > 0 ) return -ENODEV;
#endif /* CONFIG_PCI */
- /* at second - probe all EISA possible port regions (if EISA bus present) */
-
+ /* Second: Probe all EISA possible port regions (if EISA bus present) */
for ( ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400 )
{
if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
- if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA ) == 0 ) return 0;
+ if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA, 0, 0 ) == 0 ) return 0;
}
- /* at third - probe all ISA possible port regions */
-
+ /* Third Probe all ISA possible port regions */
for ( ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20 )
{
if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
- if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA ) == 0 ) return 0;
+ if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA, 0, 0 ) == 0 ) return 0;
}
return -ENODEV;
}
-__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus ))
+
+__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ))
{
int i;
+
u_char uc, uc_1;
u_int eisa_id;
+ u_int chip;
+ u_int memory_size = 0;
short mem_mapped;
- u_char *mem_ptr_phys, *mem_ptr_virt;
+ u_int *mem_ptr_phys, *mem_ptr_virt;
struct hp100_private *lp;
struct hp100_eisa_id *eid;
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4201, TRACE );
+ printk("hp100: probe1\n");
+#endif
+
if ( dev == NULL )
{
#ifdef HP100_DEBUG
@@ -315,19 +380,27 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus ))
#endif
return EIO;
}
+
+ if ( hp100_inw( HW_ID ) != HP100_HW_ID_CASCADE )
+ {
+ return -ENODEV;
+ }
+ else
+ {
+ chip = hp100_inw( PAGING ) & HP100_CHIPID_MASK;
+#ifdef HP100_DEBUG
+ if ( chip == HP100_CHIPID_SHASTA )
+ printk("hp100: Shasta Chip detected. (This is a pre 802.12 chip)\n");
+ else if ( chip == HP100_CHIPID_RAINIER )
+ printk("hp100: Rainier Chip detected. (This is a pre 802.12 chip)\n");
+ else if ( chip == HP100_CHIPID_LASSEN )
+ printk("hp100: Lassen Chip detected.\n");
+ else
+ printk("hp100: Warning: Unknown CASCADE chip (id=0x%.4x).\n",chip);
+#endif
+ }
- if ( bus != HP100_BUS_PCI ) /* don't check PCI cards again */
- if ( inb( ioaddr + 0 ) != HP100_HW_ID_0 ||
- inb( ioaddr + 1 ) != HP100_HW_ID_1 ||
- ( inb( ioaddr + 2 ) & 0xf0 ) != HP100_HW_ID_2_REVA ||
- inb( ioaddr + 3 ) != HP100_HW_ID_3 )
- return -ENODEV;
-
- dev -> base_addr = ioaddr;
-
-#ifdef HP100_DEBUG_PROBE1
- printk( "hp100_probe1: card found at port 0x%x\n", ioaddr );
-#endif
+ dev->base_addr = ioaddr;
hp100_page( ID_MAC_ADDR );
for ( i = uc = eisa_id = 0; i < 4; i++ )
@@ -339,17 +412,13 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus ))
}
uc += hp100_inb( BOARD_ID + 4 );
-#ifdef HP100_DEBUG_PROBE1
- printk( "hp100_probe1: EISA ID = 0x%08x checksum = 0x%02x\n", eisa_id, uc );
-#endif
-
- if ( uc != 0xff ) /* bad checksum? */
+ if ( uc != 0xff ) /* bad checksum? */
{
- printk( "hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr );
+ printk("hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr );
return -ENODEV;
}
- for ( i = 0; i < sizeof( hp100_eisa_ids ) / sizeof( struct hp100_eisa_id ); i++ )
+ for ( i=0; i<sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id); i++)
if ( ( hp100_eisa_ids[ i ].id & 0xf0ffffff ) == ( eisa_id & 0xf0ffffff ) )
break;
if ( i >= sizeof( hp100_eisa_ids ) / sizeof( struct hp100_eisa_id ) )
@@ -358,10 +427,10 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus ))
return -ENODEV;
}
eid = &hp100_eisa_ids[ i ];
- if ( ( eid -> id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) )
+ if ( ( eid->id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) )
{
printk( "hp100_probe1: newer version of card %s at port 0x%x - unsupported\n",
- eid -> name, ioaddr );
+ eid->name, ioaddr );
return -ENODEV;
}
@@ -369,461 +438,1592 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus ))
uc += hp100_inb( LAN_ADDR + i );
if ( uc != 0xff )
{
- printk( "hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n",
- eid -> name, ioaddr );
+ printk("hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n",
+ eid->name, ioaddr );
return -EIO;
}
-#ifndef HP100_IO_MAPPED
+ /* Determine driver operation mode
+ *
+ * Use the variable "hp100_mode" upon insmod or as kernel parameter to
+ * force driver modes:
+ * hp100_mode=1 -> default, use busmaster mode if configured.
+ * hp100_mode=2 -> enable shared memory mode
+ * hp100_mode=3 -> force use of i/o mapped mode.
+ * hp100_mode=4 -> same as 1, but re-set the enable bit on the card.
+ */
+
+ if(hp100_mode==3)
+ {
+ hp100_outw(HP100_MEM_EN|HP100_RESET_LB, OPTION_LSW);
+ hp100_outw(HP100_IO_EN|HP100_SET_LB, OPTION_LSW);
+ hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW);
+ printk("hp100: IO mapped mode forced.\n");
+ }
+ else if(hp100_mode==2)
+ {
+ hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW);
+ hp100_outw(HP100_IO_EN |HP100_SET_LB, OPTION_LSW);
+ hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW);
+ printk("hp100: Shared memory mode requested.\n");
+ }
+ else if(hp100_mode==4)
+ {
+ if(chip==HP100_CHIPID_LASSEN)
+ {
+ hp100_outw(HP100_BM_WRITE|
+ HP100_BM_READ | HP100_SET_HB, OPTION_LSW);
+ hp100_outw(HP100_IO_EN |
+ HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW);
+ printk("hp100: Busmaster mode requested.\n");
+ }
+ hp100_mode=1;
+ }
+
+ if(hp100_mode==1) /* default behaviour */
+ {
+ if( (hp100_inw(OPTION_LSW)&HP100_IO_EN) &&
+ (~hp100_inw(OPTION_LSW)&HP100_MEM_EN) &&
+ (~hp100_inw(OPTION_LSW)&(HP100_BM_WRITE|HP100_BM_READ))
+ )
+ {
+#ifdef HP100_DEBUG
+ printk("hp100: IO_EN bit is set on card.\n");
+#endif
+ hp100_mode=3;
+ }
+ else if( ( chip==HP100_CHIPID_LASSEN ) &&
+ ( (hp100_inw(OPTION_LSW)&(HP100_BM_WRITE|HP100_BM_READ) ) ==
+ (HP100_BM_WRITE|HP100_BM_READ) ) )
+ {
+ printk("hp100: Busmaster mode enabled.\n");
+ hp100_outw(HP100_MEM_EN|HP100_IO_EN|HP100_RESET_LB, OPTION_LSW);
+ }
+ else
+ {
+#ifdef HP100_DEBUG
+ printk("hp100: Card not configured for BM or BM not supported with this card. Trying shared memory mode.\n");
+#endif
+ /* In this case, try shared memory mode */
+ hp100_mode=2;
+ hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW);
+ /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */
+ }
+ }
+
+ /* Check for shared memory on the card, eventually remap it */
hp100_page( HW_MAP );
- mem_mapped = ( hp100_inw( OPTION_LSW ) &
- ( HP100_MEM_EN | HP100_BM_WRITE | HP100_BM_READ ) ) != 0;
+ mem_mapped = (( hp100_inw( OPTION_LSW ) & ( HP100_MEM_EN ) ) != 0);
mem_ptr_phys = mem_ptr_virt = NULL;
- if ( mem_mapped )
+ memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07));
+
+ /* For memory mapped or busmaster mode, we want the memory address */
+ if ( mem_mapped || (hp100_mode==1))
{
- mem_ptr_phys = (u_char *)( hp100_inw( MEM_MAP_LSW ) |
- ( hp100_inw( MEM_MAP_MSW ) << 16 ) );
- (u_int)mem_ptr_phys &= ~0x1fff; /* 8k alignment */
+ mem_ptr_phys = (u_int *)( hp100_inw( MEM_MAP_LSW ) |
+ ( hp100_inw( MEM_MAP_MSW ) << 16 ) );
+ (u_int)mem_ptr_phys &= ~0x1fff; /* 8k alignment */
+
if ( bus == HP100_BUS_ISA && ( (u_long)mem_ptr_phys & ~0xfffff ) != 0 )
{
+ printk("hp100: Can only use programmed i/o mode.\n");
mem_ptr_phys = NULL;
mem_mapped = 0;
+ hp100_mode=3; /* Use programmed i/o */
}
- if ( mem_mapped && bus == HP100_BUS_PCI )
- {
- if ( ( mem_ptr_virt = ioremap( (u_long)mem_ptr_phys, 0x2000 ) ) == NULL )
- {
- printk( "hp100: ioremap for high PCI memory at 0x%lx failed\n", (u_long)mem_ptr_phys );
- mem_ptr_phys = NULL;
- mem_mapped = 0;
- }
- }
- }
-#else
- mem_mapped = 0;
- mem_ptr_phys = mem_ptr_virt = NULL;
+
+ /* We do not need access to shared memory in busmaster mode */
+ /* However in slave mode we need to remap high (>1GB) card memory */
+ if(hp100_mode!=1) /* = not busmaster */
+ {
+ if ( bus == HP100_BUS_PCI )
+ {
+ /* We try with smaller memory sizes, if ioremap fails */
+ for(; memory_size>16383; memory_size=memory_size/2)
+ {
+ if((mem_ptr_virt=ioremap((u_long)mem_ptr_phys,memory_size))==NULL)
+ {
+#ifdef HP100_DEBUG
+ printk( "hp100: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", memory_size, (u_long)mem_ptr_phys );
+#endif
+ }
+ else
+ {
+#ifdef HP100_DEBUG
+ printk( "hp100: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", memory_size, (u_long)mem_ptr_phys, (u_long)mem_ptr_virt);
#endif
+ break;
+ }
+ }
+
+ if(mem_ptr_virt==NULL) /* all ioremap tries failed */
+ {
+ printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n");
+ hp100_mode=3;
+ memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07) );
+ }
+ }
+ }
+
+ }
- if ( ( dev -> priv = kmalloc( sizeof( struct hp100_private ), GFP_KERNEL ) ) == NULL )
- return -ENOMEM;
- memset( dev -> priv, 0, sizeof( struct hp100_private ) );
+ if(hp100_mode==3) /* io mapped forced */
+ {
+ mem_mapped = 0;
+ mem_ptr_phys = mem_ptr_virt = NULL;
+ printk("hp100: Using (slow) programmed i/o mode.\n");
+ }
- lp = (struct hp100_private *)dev -> priv;
- lp -> id = eid;
- lp -> mem_mapped = mem_mapped;
- lp -> mem_ptr_phys = mem_ptr_phys;
- lp -> mem_ptr_virt = mem_ptr_virt;
+ /* Initialise the "private" data structure for this card. */
+ if ( (dev->priv=kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memset( dev->priv, 0, sizeof(struct hp100_private) );
+
+ lp = (struct hp100_private *)dev->priv;
+ lp->id = eid;
+ lp->chip = chip;
+ lp->mode = hp100_mode;
+ lp->pci_bus = pci_bus;
+ lp->bus = bus;
+ lp->pci_device_fn = pci_device_fn;
+ lp->priority_tx = hp100_priority_tx;
+ lp->rx_ratio = hp100_rx_ratio;
+ lp->mem_ptr_phys = mem_ptr_phys;
+ lp->mem_ptr_virt = mem_ptr_virt;
hp100_page( ID_MAC_ADDR );
- lp -> soft_model = hp100_inb( SOFT_MODEL );
- lp -> mac1_mode = HP100_MAC1MODE3;
- lp -> mac2_mode = HP100_MAC2MODE3;
+ lp->soft_model = hp100_inb( SOFT_MODEL );
+ lp->mac1_mode = HP100_MAC1MODE3;
+ lp->mac2_mode = HP100_MAC2MODE3;
- dev -> base_addr = ioaddr;
- hp100_page( HW_MAP );
- dev -> irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQ_MASK;
- if ( dev -> irq == 2 ) dev -> irq = 9;
- lp -> memory_size = 0x200 << ( ( hp100_inb( SRAM ) & 0xe0 ) >> 5 );
- lp -> rx_ratio = hp100_rx_ratio;
+ dev->base_addr = ioaddr;
+
+ lp->memory_size = memory_size;
+ lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */
+
+ /* memory region for programmed i/o */
+ request_region( dev->base_addr, HP100_REGION_SIZE, eid->name );
+
+ dev->open = hp100_open;
+ dev->stop = hp100_close;
- dev -> open = hp100_open;
- dev -> stop = hp100_close;
- dev -> hard_start_xmit = hp100_start_xmit;
- dev -> get_stats = hp100_get_stats;
- dev -> set_multicast_list = &hp100_set_multicast_list;
+ if (lp->mode==1) /* busmaster */
+ dev->hard_start_xmit = hp100_start_xmit_bm;
+ else
+ dev->hard_start_xmit = hp100_start_xmit;
- request_region( dev -> base_addr, HP100_REGION_SIZE, eid -> name );
+ dev->get_stats = hp100_get_stats;
+ dev->set_multicast_list = &hp100_set_multicast_list;
+ /* Ask the card for which IRQ line it is configured */
+ hp100_page( HW_MAP );
+ dev->irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQMASK;
+ if ( dev->irq == 2 )
+ dev->irq = 9;
+
+ if(lp->mode==1) /* busmaster */
+ dev->dma=4;
+
+ /* Ask the card for its MAC address and store it for later use. */
hp100_page( ID_MAC_ADDR );
for ( i = uc = 0; i < 6; i++ )
- dev -> dev_addr[ i ] = hp100_inb( LAN_ADDR + i );
+ dev->dev_addr[ i ] = hp100_inb( LAN_ADDR + i );
+ /* Reset statistics (counters) */
hp100_clear_stats( ioaddr );
ether_setup( dev );
- lp -> lan_type = hp100_sense_lan( dev );
+ /* If busmaster mode is wanted, a dma-capable memory area is needed for
+ * the rx and tx PDLs
+ * PCI cards can access the whole PC memory. Therefore GFP_DMA is not
+ * needed for the allocation of the memory area.
+ */
- printk( "%s: %s at 0x%x, IRQ %d, ",
- dev -> name, lp -> id -> name, ioaddr, dev -> irq );
+ /* TODO: We do not need this with old cards, where PDLs are stored
+ * in the cards shared memory area. But currently, busmaster has been
+ * implemented/tested only with the lassen chip anyway... */
+ if(lp->mode==1) /* busmaster */
+ {
+ /* Get physically continous memory for TX & RX PDLs */
+ if ( (lp->page_vaddr=kmalloc(MAX_RINGSIZE+0x0f,GFP_KERNEL) ) == NULL)
+ return -ENOMEM;
+ lp->page_vaddr_algn=((u_int *) ( ((u_int)(lp->page_vaddr)+0x0f) &~0x0f));
+ memset(lp->page_vaddr, 0, MAX_RINGSIZE+0x0f);
+
+#ifdef HP100_DEBUG_BM
+ printk("hp100: Reserved DMA memory from 0x%x to 0x%x\n",
+ (u_int)lp->page_vaddr_algn,
+ (u_int)lp->page_vaddr_algn+MAX_RINGSIZE);
+#endif
+ lp->rxrcommit = lp->txrcommit = 0;
+ lp->rxrhead = lp->rxrtail = &(lp->rxring[0]);
+ lp->txrhead = lp->txrtail = &(lp->txring[0]);
+ }
+
+ /* Initialise the card. */
+ /* (I'm not really sure if it's a good idea to do this during probing, but
+ * like this it's assured that the lan connection type can be sensed
+ * correctly)
+ */
+ hp100_hwinit( dev );
+
+ /* Try to find out which kind of LAN the card is connected to. */
+ lp->lan_type = hp100_sense_lan( dev );
+
+ /* Print out a message what about what we think we have probed. */
+ printk( "hp100: %s: %s at 0x%x, IRQ %d, ",
+ dev->name, lp->id->name, ioaddr, dev->irq );
switch ( bus ) {
- case HP100_BUS_EISA: printk( "EISA" ); break;
- case HP100_BUS_PCI: printk( "PCI" ); break;
- default: printk( "ISA" ); break;
+ case HP100_BUS_EISA: printk( "EISA" ); break;
+ case HP100_BUS_PCI: printk( "PCI" ); break;
+ default: printk( "ISA" ); break;
}
printk( " bus, %dk SRAM (rx/tx %d%%).\n",
- lp -> memory_size >> ( 10 - 4 ), lp -> rx_ratio );
- if ( mem_mapped )
+ lp->memory_size >> 10, lp->rx_ratio );
+
+ if ( lp->mode==2 ) /* memory mapped */
{
printk( "%s: Memory area at 0x%lx-0x%lx",
- dev -> name, (u_long)mem_ptr_phys, (u_long)mem_ptr_phys + 0x1fff );
+ dev->name,(u_long)mem_ptr_phys,(u_long)mem_ptr_phys+(u_long)lp->memory_size );
if ( mem_ptr_virt )
- printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt );
+ printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt );
printk( ".\n" );
+
+ /* Set for info when doing ifconfig */
+ dev->mem_start = (u_long)mem_ptr_phys;
+ dev->mem_end = (u_long)mem_ptr_phys+(u_long)lp->memory_size;
}
- printk( "%s: ", dev -> name );
- if ( lp -> lan_type != HP100_LAN_ERR )
+ printk( "%s: ", dev->name );
+ if ( lp->lan_type != HP100_LAN_ERR )
printk( "Adapter is attached to " );
- switch ( lp -> lan_type ) {
- case HP100_LAN_100:
- printk( "100Mb/s Voice Grade AnyLAN network.\n" );
- break;
- case HP100_LAN_10:
- printk( "10Mb/s network.\n" );
- break;
- default:
- printk( "Warning! Link down.\n" );
+ switch ( lp->lan_type ) {
+ case HP100_LAN_100:
+ printk( "100Mb/s Voice Grade AnyLAN network.\n" );
+ break;
+ case HP100_LAN_10:
+ printk( "10Mb/s network.\n" );
+ break;
+ default:
+ printk( "Warning! Link down.\n" );
}
+ return 0;
+}
- hp100_stop_interface( dev );
+
+/* This procedure puts the card into a stable init state */
+static void hp100_hwinit( struct device *dev )
+{
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
- return 0;
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4202, TRACE );
+ printk("hp100: hwinit\n");
+#endif
+
+ /* Initialise the card. -------------------------------------------- */
+
+ /* Clear all pending Ints and disable Ints */
+ hp100_page( PERFORMANCE );
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* clear all pending ints */
+
+ hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW );
+ hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW );
+
+ if(lp->mode==1)
+ {
+ hp100_BM_shutdown( dev ); /* disables BM, puts cascade in reset */
+ wait();
+ }
+ else
+ {
+ hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW );
+ hp100_cascade_reset( dev, TRUE );
+ hp100_page( MAC_CTRL );
+ hp100_andb( ~(HP100_RX_EN|HP100_TX_EN), MAC_CFG_1);
+ }
+
+ /* Initiate EEPROM reload */
+ hp100_load_eeprom( dev );
+
+ wait();
+
+ /* Go into reset again. */
+ hp100_cascade_reset( dev, TRUE );
+
+ /* Set Option Registers to a safe state */
+ hp100_outw( HP100_DEBUG_EN |
+ HP100_RX_HDR |
+ HP100_EE_EN |
+ HP100_BM_WRITE |
+ HP100_BM_READ | HP100_RESET_HB |
+ HP100_FAKE_INT |
+ HP100_INT_EN |
+ HP100_MEM_EN |
+ HP100_IO_EN | HP100_RESET_LB, OPTION_LSW);
+
+ hp100_outw( HP100_TRI_INT |
+ HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
+
+ hp100_outb( HP100_PRIORITY_TX |
+ HP100_ADV_NXT_PKT |
+ HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW );
+
+ /* TODO: Configure MMU for Ram Test. */
+ /* TODO: Ram Test. */
+
+ /* Re-check if adapter is still at same i/o location */
+ /* (If the base i/o in eeprom has been changed but the */
+ /* registers had not been changed, a reload of the eeprom */
+ /* would move the adapter to the address stored in eeprom */
+
+ /* TODO: Code to implement. */
+
+ /* Until here it was code from HWdiscover procedure. */
+ /* Next comes code from mmuinit procedure of SCO BM driver which is
+ * called from HWconfigure in the SCO driver. */
+
+ /* Initialise MMU, eventually switch on Busmaster Mode, initialise
+ * multicast filter...
+ */
+ hp100_mmuinit( dev );
+
+ /* We don't turn the interrupts on here - this is done by start_interface. */
+ wait(); /* TODO: Do we really need this? */
+
+ /* Enable Hardware (e.g. unreset) */
+ hp100_cascade_reset( dev, FALSE );
+
+ /* ------- initialisation complete ----------- */
+
+ /* Finally try to log in the Hub if there may be a VG connection. */
+ if( lp->lan_type != HP100_LAN_10 )
+ hp100_login_to_vg_hub( dev, FALSE ); /* relogin */
}
-/*
- * open/close functions
+
+/*
+ * mmuinit - Reinitialise Cascade MMU and MAC settings.
+ * Note: Must already be in reset and leaves card in reset.
*/
-
-static int hp100_open( struct device *dev )
+static void hp100_mmuinit( struct device *dev )
{
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
int i;
- int ioaddr = dev -> base_addr;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
- if ( request_irq( dev -> irq, hp100_interrupt, SA_INTERRUPT, lp -> id -> name, NULL ) )
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4203, TRACE );
+ printk("hp100: mmuinit\n");
+#endif
+
+#ifdef HP100_DEBUG
+ if( 0!=(hp100_inw(OPTION_LSW)&HP100_HW_RST) )
{
- printk( "%s: unable to get IRQ %d\n", dev -> name, dev -> irq );
- return -EAGAIN;
+ printk("hp100: Not in reset when entering mmuinit. Fix me.\n");
+ return;
}
- irq2dev_map[ dev -> irq ] = dev;
-
- MOD_INC_USE_COUNT;
+#endif
- dev -> tbusy = 0;
- dev -> trans_start = jiffies;
- dev -> interrupt = 0;
- dev -> start = 1;
+ /* Make sure IRQs are masked off and ack'ed. */
+ hp100_page( PERFORMANCE );
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */
+
+ /*
+ * Enable Hardware
+ * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En
+ * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable
+ * - Clear Priority, Advance Pkt and Xmit Cmd
+ */
+
+ hp100_outw( HP100_DEBUG_EN |
+ HP100_RX_HDR |
+ HP100_EE_EN | HP100_RESET_HB |
+ HP100_IO_EN |
+ HP100_FAKE_INT |
+ HP100_INT_EN | HP100_RESET_LB, OPTION_LSW );
+
+ hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW);
+
+ if(lp->mode==1) /* busmaster */
+ {
+ hp100_outw( HP100_BM_WRITE |
+ HP100_BM_READ |
+ HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
+ }
+ else if(lp->mode==2) /* memory mapped */
+ {
+ hp100_outw( HP100_BM_WRITE |
+ HP100_BM_READ | HP100_RESET_HB, OPTION_LSW );
+ hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW );
+ hp100_outw( HP100_MEM_EN | HP100_SET_LB, OPTION_LSW );
+ hp100_outw( HP100_IO_EN | HP100_SET_LB, OPTION_LSW );
+ }
+ else if( lp->mode==3 ) /* i/o mapped mode */
+ {
+ hp100_outw( HP100_MMAP_DIS | HP100_SET_HB |
+ HP100_IO_EN | HP100_SET_LB, OPTION_LSW );
+ }
- lp -> lan_type = hp100_sense_lan( dev );
- lp -> mac1_mode = HP100_MAC1MODE3;
- lp -> mac2_mode = HP100_MAC2MODE3;
+ hp100_page( HW_MAP );
+ hp100_outb( 0, EARLYRXCFG );
+ hp100_outw( 0, EARLYTXCFG );
+
+ /*
+ * Enable Bus Master mode
+ */
+ if(lp->mode==1) /* busmaster */
+ {
+ /* Experimental: Set some PCI configuration bits */
+ hp100_page( HW_MAP );
+ hp100_andb( ~HP100_PDL_USE3, MODECTRL1 ); /* BM engine read maximum */
+ hp100_andb( ~HP100_TX_DUALQ, MODECTRL1 ); /* No Queue for Priority TX */
+
+ /* PCI Bus failures should result in a Misc. Interrupt */
+ hp100_orb( HP100_EN_BUS_FAIL, MODECTRL2);
+
+ hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW );
+ hp100_page( HW_MAP );
+ /* Use Burst Mode and switch on PAGE_CK */
+ hp100_orb( HP100_BM_BURST_RD |
+ HP100_BM_BURST_WR, BM);
+ if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA))
+ hp100_orb( HP100_BM_PAGE_CK, BM );
+ hp100_orb( HP100_BM_MASTER, BM );
+ }
+ else /* not busmaster */
+ {
+ hp100_page(HW_MAP);
+ hp100_andb(~HP100_BM_MASTER, BM );
+ }
- hp100_page( MAC_CTRL );
- hp100_orw( HP100_LINK_BEAT_DIS | HP100_RESET_LB, LAN_CFG_10 );
+ /*
+ * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs
+ */
+ hp100_page( MMU_CFG );
+ if(lp->mode==1) /* only needed for Busmaster */
+ {
+ int xmit_stop, recv_stop;
- hp100_stop_interface( dev );
- hp100_load_eeprom( dev );
+ if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA))
+ {
+ int pdl_stop;
+
+ /*
+ * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and
+ * 4 bytes for for header). We will leave NUM_RXPDLS * 508 (rounded
+ * to the next higher 1k boundary) bytes for the rx-pdl's
+ * Note: For non-etr chips the transmit stop register must be
+ * programmed on a 1k boundary, i.e. bits 9:0 must be zero.
+ */
+ pdl_stop = lp->memory_size;
+ xmit_stop = ( pdl_stop-508*(MAX_RX_PDL)-16 )& ~(0x03ff);
+ recv_stop = ( xmit_stop * (lp->rx_ratio)/100 ) &~(0x03ff);
+ hp100_outw( (pdl_stop>>4)-1, PDL_MEM_STOP );
+#ifdef HP100_DEBUG_BM
+ printk("hp100: PDL_STOP = 0x%x\n", pdl_stop);
+#endif
+ }
+ else /* ETR chip (Lassen) in busmaster mode */
+ {
+ xmit_stop = ( lp->memory_size ) - 1;
+ recv_stop = ( ( lp->memory_size * lp->rx_ratio ) / 100 ) & ~(0x03ff);
+ }
- hp100_outw( HP100_MMAP_DIS | HP100_SET_HB |
- HP100_IO_EN | HP100_SET_LB, OPTION_LSW );
- hp100_outw( HP100_DEBUG_EN | HP100_RX_HDR | HP100_EE_EN | HP100_RESET_HB |
- HP100_FAKE_INT | HP100_RESET_LB, OPTION_LSW );
- hp100_outw( HP100_ADV_NXT_PKT | HP100_TX_CMD | HP100_RESET_LB |
- HP100_PRIORITY_TX | ( hp100_priority_tx ? HP100_SET_HB : HP100_RESET_HB ),
- OPTION_MSW );
+ hp100_outw( xmit_stop>>4 , TX_MEM_STOP );
+ hp100_outw( recv_stop>>4 , RX_MEM_STOP );
+#ifdef HP100_DEBUG_BM
+ printk("hp100: TX_STOP = 0x%x\n",xmit_stop>>4);
+ printk("hp100: RX_STOP = 0x%x\n",recv_stop>>4);
+#endif
+ }
+ else /* Slave modes (memory mapped and programmed io) */
+ {
+ hp100_outw( (((lp->memory_size*lp->rx_ratio)/100)>>4), RX_MEM_STOP );
+ hp100_outw( ((lp->memory_size - 1 )>>4), TX_MEM_STOP );
+#ifdef HP100_DEBUG
+ printk("hp100: TX_MEM_STOP: 0x%x\n", hp100_inw(TX_MEM_STOP));
+ printk("hp100: RX_MEM_STOP: 0x%x\n", hp100_inw(RX_MEM_STOP));
+#endif
+ }
+ /* Write MAC address into page 1 */
hp100_page( MAC_ADDRESS );
for ( i = 0; i < 6; i++ )
- hp100_outb( dev -> dev_addr[ i ], MAC_ADDR + i );
- for ( i = 0; i < 8; i++ ) /* setup multicast filter to receive all */
- hp100_outb( 0xff, HASH_BYTE0 + i );
+ hp100_outb( dev->dev_addr[ i ], MAC_ADDR + i );
+
+ /* Zero the multicast hash registers */
+ for ( i = 0; i < 8; i++ )
+ hp100_outb( 0x0, HASH_BYTE0 + i );
+
+ /* Set up MAC defaults */
+ hp100_page( MAC_CTRL );
+
+ /* Go to LAN Page and zero all filter bits */
+ /* Zero accept error, accept multicast, accept broadcast and accept */
+ /* all directed packet bits */
+ hp100_andb( ~(HP100_RX_EN|
+ HP100_TX_EN|
+ HP100_ACC_ERRORED|
+ HP100_ACC_MC|
+ HP100_ACC_BC|
+ HP100_ACC_PHY), MAC_CFG_1 );
+
+ hp100_outb( 0x00, MAC_CFG_2 );
+
+ /* Zero the frame format bit. This works around a training bug in the */
+ /* new hubs. */
+ hp100_outb( 0x00, VG_LAN_CFG_2); /* (use 802.3) */
+
+ if(lp->priority_tx)
+ hp100_outb( HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW );
+ else
+ hp100_outb( HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW );
+
+ hp100_outb( HP100_ADV_NXT_PKT |
+ HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW );
+
+ /* If busmaster, initialize the PDLs */
+ if(lp->mode==1)
+ hp100_init_pdls( dev );
+
+ /* Go to performance page and initalize isr and imr registers */
hp100_page( PERFORMANCE );
- hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
- hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */
- hp100_outw( (HP100_RX_PACKET | HP100_RX_ERROR | HP100_SET_HB) |
- (HP100_TX_ERROR | HP100_SET_LB ), IRQ_MASK );
- /* and enable few */
- hp100_reset_card();
- hp100_page( MMU_CFG );
- hp100_outw( ( lp -> memory_size * lp -> rx_ratio ) / 100, RX_MEM_STOP );
- hp100_outw( lp -> memory_size - 1, TX_MEM_STOP );
- hp100_unreset_card();
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */
+}
+
+
+/*
+ * open/close functions
+ */
+
+static int hp100_open( struct device *dev )
+{
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+#ifdef HP100_DEBUG_B
+ int ioaddr=dev->base_addr;
+#endif
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4204, TRACE );
+ printk("hp100: open\n");
+#endif
+
+ /* New: if bus is PCI or EISA, interrupts might be shared interrupts */
+ if((lp->bus==HP100_BUS_PCI)||(lp->bus==HP100_BUS_EISA))
+ {
+ if(request_irq(dev->irq,hp100_interrupt,SA_SHIRQ,lp->id->name,dev))
+ {
+ printk( "%s: unable to get IRQ %d\n", dev->name, dev->irq );
+ return -EAGAIN;
+ }
+ }
+ else
+ if(request_irq(dev->irq, hp100_interrupt, SA_INTERRUPT, lp->id->name, NULL))
+ {
+ printk( "%s: unable to get IRQ %d\n", dev->name, dev->irq );
+ return -EAGAIN;
+ }
+
+ irq2dev_map[ dev->irq ] = dev;
+
+ MOD_INC_USE_COUNT;
- if ( lp -> lan_type == HP100_LAN_100 )
- lp -> hub_status = hp100_login_to_vg_hub( dev );
+ dev->tbusy = 0;
+ dev->trans_start = jiffies;
+ dev->interrupt = 0;
+ dev->start = 1;
- hp100_start_interface( dev );
+ lp->lan_type = hp100_sense_lan( dev );
+ lp->mac1_mode = HP100_MAC1MODE3;
+ lp->mac2_mode = HP100_MAC2MODE3;
+
+ hp100_stop_interface( dev );
+
+ hp100_hwinit( dev );
+
+ hp100_start_interface( dev ); /* sets mac modes, enables interrupts */
return 0;
}
+
+/* The close function is called when the interface is to be brought down */
static int hp100_close( struct device *dev )
{
- int ioaddr = dev -> base_addr;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4205, TRACE );
+ printk("hp100:close\n");
+#endif
hp100_page( PERFORMANCE );
- hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all IRQs */
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all IRQs */
hp100_stop_interface( dev );
- if ( lp -> lan_type == HP100_LAN_100 ) /* relogin */
- hp100_login_to_vg_hub( dev );
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status=hp100_login_to_vg_hub( dev, FALSE );
- dev -> tbusy = 1;
- dev -> start = 0;
+ dev->tbusy = 1;
+ dev->start = 0;
- free_irq( dev -> irq, NULL );
- irq2dev_map[ dev -> irq ] = NULL;
+ if ((lp->bus==HP100_BUS_PCI)||(lp->bus==HP100_BUS_EISA))
+ free_irq( dev->irq, dev );
+ else
+ free_irq( dev->irq, NULL );
+ irq2dev_map[ dev->irq ] = NULL;
MOD_DEC_USE_COUNT;
return 0;
}
+
+/*
+ * Configure the PDL Rx rings and LAN
+ */
+static void hp100_init_pdls( struct device *dev )
+{
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ hp100_ring_t *ringptr;
+ u_int *pageptr;
+ int i;
+
+#ifdef HP100_DEBUG_B
+ int ioaddr = dev->base_addr;
+#endif
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4206, TRACE );
+ printk("hp100: init pdls\n");
+#endif
+
+ if(0==lp->page_vaddr_algn)
+ printk("hp100: Warning: lp->page_vaddr_algn not initialised!\n");
+ else
+ {
+ /* pageptr shall point into the DMA accessible memory region */
+ /* we use this pointer to status the upper limit of allocated */
+ /* memory in the allocated page. */
+ /* note: align the pointers to the pci cache line size */
+ memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero Rx/Tx ring page */
+ pageptr=lp->page_vaddr_algn;
+
+ lp->rxrcommit =0;
+ ringptr = lp->rxrhead = lp-> rxrtail = &(lp->rxring[0]);
+
+ /* Initialise Rx Ring */
+ for (i=MAX_RX_PDL-1; i>=0; i--)
+ {
+ lp->rxring[i].next = ringptr;
+ ringptr=&(lp->rxring[i]);
+ pageptr+=hp100_init_rxpdl(ringptr, pageptr);
+ }
+
+ /* Initialise Tx Ring */
+ lp->txrcommit = 0;
+ ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]);
+ for (i=MAX_TX_PDL-1; i>=0; i--)
+ {
+ lp->txring[i].next = ringptr;
+ ringptr=&(lp->txring[i]);
+ pageptr+=hp100_init_txpdl(ringptr, pageptr);
+ }
+ }
+}
+
+
+/* These functions "format" the entries in the pdl structure */
+/* They return how much memory the fragments need. */
+static int hp100_init_rxpdl( register hp100_ring_t *ringptr, register u32 *pdlptr )
+{
+ /* pdlptr is starting adress for this pdl */
+
+ if( 0!=( ((unsigned)pdlptr) & 0xf) )
+ printk("hp100: Init rxpdl: Unaligned pdlptr 0x%x.\n",(unsigned)pdlptr);
+
+ ringptr->pdl = pdlptr+1;
+ ringptr->pdl_paddr = virt_to_bus(pdlptr+1);
+ ringptr->skb = (void *) NULL;
+
+ /*
+ * Write address and length of first PDL Fragment (which is used for
+ * storing the RX-Header
+ * We use the 4 bytes _before_ the PDH in the pdl memory area to
+ * store this information. (PDH is at offset 0x04)
+ */
+ /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */
+
+ *(pdlptr+2) =(u_int) virt_to_bus(pdlptr); /* Address Frag 1 */
+ *(pdlptr+3) = 4; /* Length Frag 1 */
+
+ return( ( ((MAX_RX_FRAG*2+2)+3) /4)*4 );
+}
+
+
+static int hp100_init_txpdl( register hp100_ring_t *ringptr, register u32 *pdlptr )
+{
+ if( 0!=( ((unsigned)pdlptr) & 0xf) )
+ printk("hp100: Init txpdl: Unaligned pdlptr 0x%x.\n",(unsigned) pdlptr);
+
+ ringptr->pdl = pdlptr; /* +1; */
+ ringptr->pdl_paddr = virt_to_bus(pdlptr); /* +1 */
+ ringptr->skb = (void *) NULL;
+
+ return((((MAX_TX_FRAG*2+2)+3)/4)*4);
+}
+
+
+/*
+ * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes
+ * for possible odd word alignment rounding up to next dword and set PDL
+ * address for fragment#2
+ * Returns: 0 if unable to allocate skb_buff
+ * 1 if successful
+ */
+int hp100_build_rx_pdl( hp100_ring_t *ringptr, struct device *dev )
+{
+#ifdef HP100_DEBUG_B
+ int ioaddr = dev->base_addr;
+#endif
+#ifdef HP100_DEBUG_BM
+ u_int *p;
+#endif
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4207, TRACE );
+ printk("hp100: build rx pdl\n");
+#endif
+
+ /* Allocate skb buffer of maximum size */
+ /* Note: This depends on the alloc_skb functions allocating more
+ * space than requested, i.e. aligning to 16bytes */
+
+ ringptr->skb = dev_alloc_skb( ((MAX_ETHER_SIZE+2+3)/4)*4 );
+
+ if(NULL!=ringptr->skb)
+ {
+ /*
+ * Reserve 2 bytes at the head of the buffer to land the IP header
+ * on a long word boundary (According to the Network Driver section
+ * in the Linux KHG, this should help to increase performance.)
+ */
+ skb_reserve(ringptr->skb, 2);
+
+ ringptr->skb->dev=dev;
+ ringptr->skb->data=(u_char *)skb_put(ringptr->skb, MAX_ETHER_SIZE );
+
+ /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */
+ /* Note: 1st Fragment is used for the 4 byte packet status
+ * (receive header). Its PDL entries are set up by init_rxpdl. So
+ * here we only have to set up the PDL fragment entries for the data
+ * part. Those 4 bytes will be stored in the DMA memory region
+ * directly before the PDL.
+ */
+#ifdef HP100_DEBUG_BM
+ printk("hp100: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n",
+ (u_int) ringptr->pdl,
+ ((MAX_ETHER_SIZE+2+3)/4)*4,
+ (unsigned int) ringptr->skb->data);
+#endif
+
+ ringptr->pdl[0] = 0x00020000; /* Write PDH */
+ ringptr->pdl[3] = ((u_int)virt_to_bus(ringptr->skb->data));
+ ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */
+
+#ifdef HP100_DEBUG_BM
+ for(p=(ringptr->pdl); p<(ringptr->pdl+5); p++)
+ printk("Adr 0x%.8x = 0x%.8x\n",(u_int) p,(u_int) *p );
+#endif
+ return(1);
+ }
+ /* else: */
+ /* alloc_skb failed (no memory) -> still can receive the header
+ * fragment into PDL memory. make PDL safe by clearing msgptr and
+ * making the PDL only 1 fragment (i.e. the 4 byte packet status)
+ */
+#ifdef HP100_DEBUG_BM
+ printk("hp100: build_rx_pdl: PDH@0x%x, No space for skb.\n",
+ (u_int) ringptr->pdl);
+#endif
+
+ ringptr->pdl[0]=0x00010000; /* PDH: Count=1 Fragment */
+
+ return(0);
+}
+
+
+/*
+ * hp100_rxfill - attempt to fill the Rx Ring will empty skb's
+ *
+ * Makes assumption that skb's are always contiguous memory areas and
+ * therefore PDLs contain only 2 physical fragments.
+ * - While the number of Rx PDLs with buffers is less than maximum
+ * a. Get a maximum packet size skb
+ * b. Put the physical address of the buffer into the PDL.
+ * c. Output physical address of PDL to adapter.
+ */
+static void hp100_rxfill( struct device *dev )
+{
+ int ioaddr=dev->base_addr;
+
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ hp100_ring_t *ringptr;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4208, TRACE );
+ printk("hp100: rxfill\n");
+#endif
+
+ hp100_page( PERFORMANCE );
+
+ while (lp->rxrcommit < MAX_RX_PDL)
+ {
+ /*
+ ** Attempt to get a buffer and build a Rx PDL.
+ */
+ ringptr = lp->rxrtail;
+ if (0 == hp100_build_rx_pdl( ringptr, dev ))
+ {
+ return; /* None available, return */
+ }
+
+ /* Hand this PDL over to the card */
+ /* Note: This needs performance page selected! */
+#ifdef HP100_DEBUG_BM
+ printk("hp100: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n",
+ lp->rxrcommit,
+ (u_int)ringptr->pdl,
+ (u_int)ringptr->pdl_paddr,
+ (u_int)ringptr->pdl[3]);
+#endif
+
+ hp100_outl( (u32)ringptr->pdl_paddr, RX_PDA);
+
+ lp->rxrcommit += 1;
+ lp->rxrtail = ringptr->next;
+ }
+}
+
+
/*
- * transmit
+ * BM_shutdown - shutdown bus mastering and leave chip in reset state
*/
+static void hp100_BM_shutdown( struct device *dev )
+{
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ unsigned long time;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4209, TRACE );
+ printk("hp100: bm shutdown\n");
+#endif
+
+ hp100_page( PERFORMANCE );
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* Ack all ints */
+
+ /* Ensure Interrupts are off */
+ hp100_outw( HP100_INT_EN | HP100_RESET_LB , OPTION_LSW );
+
+ /* Disable all MAC activity */
+ hp100_page( MAC_CTRL );
+ hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */
+
+ /* If cascade MMU is not already in reset */
+ if (0 != (hp100_inw(OPTION_LSW)&HP100_HW_RST) )
+ {
+ /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so
+ * MMU pointers will not be reset out from underneath
+ */
+ hp100_page( MAC_CTRL );
+ for(time=0; time<5000; time++)
+ {
+ if( (hp100_inb(MAC_CFG_1)&(HP100_TX_IDLE|HP100_RX_IDLE))==
+ (HP100_TX_IDLE|HP100_RX_IDLE) ) break;
+ }
+
+ /* Shutdown algorithm depends on the generation of Cascade */
+ if( lp->chip==HP100_CHIPID_LASSEN )
+ { /* ETR shutdown/reset */
+ /* Disable Busmaster mode and wait for bit to go to zero. */
+ hp100_page(HW_MAP);
+ hp100_andb( ~HP100_BM_MASTER, BM );
+ /* 100 ms timeout */
+ for(time=0; time<32000; time++)
+ {
+ if ( 0 == (hp100_inb( BM ) & HP100_BM_MASTER) ) break;
+ }
+ }
+ else
+ { /* Shasta or Rainier Shutdown/Reset */
+ /* To ensure all bus master inloading activity has ceased,
+ * wait for no Rx PDAs or no Rx packets on card.
+ */
+ hp100_page( PERFORMANCE );
+ /* 100 ms timeout */
+ for(time=0; time<10000; time++)
+ {
+ /* RX_PDL: PDLs not executed. */
+ /* RX_PKT_CNT: RX'd packets on card. */
+ if ( (hp100_inb( RX_PDL ) == 0) &&
+ (hp100_inb( RX_PKT_CNT ) == 0) ) break;
+ }
+
+ if(time>=10000)
+ printk("hp100: BM shutdown error.\n");
+
+ /* To ensure all bus master outloading activity has ceased,
+ * wait until the Tx PDA count goes to zero or no more Tx space
+ * available in the Tx region of the card.
+ */
+ /* 100 ms timeout */
+ for(time=0; time<10000; time++) {
+ if ( (0 == hp100_inb( TX_PKT_CNT )) &&
+ (0 != (hp100_inb( TX_MEM_FREE )&HP100_AUTO_COMPARE))) break;
+ }
+
+ /* Disable Busmaster mode */
+ hp100_page(HW_MAP);
+ hp100_andb( ~HP100_BM_MASTER, BM );
+ } /* end of shutdown procedure for non-etr parts */
+
+ hp100_cascade_reset( dev, TRUE );
+ }
+ hp100_page( PERFORMANCE );
+ hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW );
+ /* Busmaster mode should be shut down now. */
+}
+
+
+
+/*
+ * transmit functions
+ */
+
+/* tx function for busmaster mode */
+static int hp100_start_xmit_bm( struct sk_buff *skb, struct device *dev )
+{
+ int i, ok_flag;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ hp100_ring_t *ringptr;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4210, TRACE );
+ printk("hp100: start_xmit_bm\n");
+#endif
+
+ if ( skb==NULL )
+ {
+ dev_tint( dev );
+ return 0;
+ }
+
+ if ( skb->len <= 0 ) return 0;
+
+ /* Get Tx ring tail pointer */
+ if( lp->txrtail->next==lp->txrhead )
+ {
+ /* No memory. */
+#ifdef HP100_DEBUG
+ printk("hp100: start_xmit_bm: No TX PDL available.\n");
+#endif
+ /* not waited long enough since last tx? */
+ if ( jiffies - dev->trans_start < HZ/10 ) return -EAGAIN;
+
+ if ( lp->lan_type < 0 ) /* no LAN type detected yet? */
+ {
+ hp100_stop_interface( dev );
+ if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 )
+ {
+ printk( "%s: no connection found - check wire\n", dev->name );
+ hp100_start_interface( dev ); /* 10Mb/s RX pkts maybe handled */
+ return -EIO;
+ }
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */
+ hp100_start_interface( dev );
+ }
+
+ if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 )
+ /* we have a 100Mb/s adapter but it isn't connected to hub */
+ {
+ printk( "%s: login to 100Mb/s hub retry\n", dev->name );
+ hp100_stop_interface( dev );
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+ hp100_start_interface( dev );
+ }
+ else
+ {
+ hp100_ints_off();
+ i = hp100_sense_lan( dev );
+ hp100_page( PERFORMANCE );
+ hp100_ints_on();
+ if ( i == HP100_LAN_ERR )
+ printk( "%s: link down detected\n", dev->name );
+ else
+ if ( lp->lan_type != i ) /* cable change! */
+ {
+ /* it's very hard - all network setting must be changed!!! */
+ printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name );
+ lp->lan_type = i;
+ hp100_stop_interface( dev );
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+ hp100_start_interface( dev );
+ }
+ else
+ {
+ printk( "%s: interface reset\n", dev->name );
+ hp100_stop_interface( dev );
+ hp100_start_interface( dev );
+ }
+ }
+
+ dev->trans_start = jiffies;
+ return -EAGAIN;
+ }
+
+ /*
+ * we have to turn int's off before modifying this, otherwise
+ * a tx_pdl_cleanup could occur at the same time
+ */
+ cli();
+ ringptr=lp->txrtail;
+ lp->txrtail=ringptr->next;
+
+ /* Check whether packet has minimal packet size */
+ ok_flag = skb->len >= HP100_MIN_PACKET_SIZE;
+ i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE;
+
+ ringptr->skb=skb;
+ ringptr->pdl[0]=((1<<16) | i); /* PDH: 1 Fragment & length */
+ ringptr->pdl[1]=(u32)virt_to_bus(skb->data); /* 1st Frag: Adr. of data */
+ if(lp->chip==HP100_CHIPID_SHASTA)
+ {
+ /* TODO:Could someone who has the EISA card please check if this works? */
+ ringptr->pdl[2]=i;
+ }
+ else /* Lassen */
+ {
+ /* In the PDL, don't use the padded size but the real packet size: */
+ ringptr->pdl[2]=skb->len; /* 1st Frag: Length of frag */
+ }
+
+ /* Hand this PDL to the card. */
+ hp100_outl( ringptr->pdl_paddr, TX_PDA_L ); /* Low Prio. Queue */
+
+ lp->txrcommit++;
+ sti();
+
+ /* Update statistics */
+ lp->stats.tx_packets++;
+#ifdef LINUX_2_1
+ lp->stats.tx_bytes += skb->len;
+#endif
+ dev->trans_start = jiffies;
+
+ return 0;
+}
+
+
+/* clean_txring checks if packets have been sent by the card by reading
+ * the TX_PDL register from the performance page and comparing it to the
+ * number of commited packets. It then frees the skb's of the packets that
+ * obviously have been sent to the network.
+ *
+ * Needs the PERFORMANCE page selected.
+ */
+static void hp100_clean_txring( struct device *dev )
+{
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int donecount;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4211, TRACE );
+ printk("hp100: clean txring\n");
+#endif
+
+ /* How many PDLs have been transmitted? */
+ donecount=(lp->txrcommit)-hp100_inb(TX_PDL);
+
+#ifdef HP100_DEBUG
+ if(donecount>MAX_TX_PDL)
+ printk("hp100: Warning: More PDLs transmitted than commited to card???\n");
+#endif
+
+ for( ; 0!=donecount; donecount-- )
+ {
+#ifdef HP100_DEBUG_BM
+ printk("hp100: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n",
+ (u_int) lp->txrhead->skb->data,
+ lp->txrcommit,
+ hp100_inb(TX_PDL),
+ donecount);
+#endif
+ dev_kfree_skb( lp->txrhead->skb, FREE_WRITE );
+ lp->txrhead->skb=(void *)NULL;
+ lp->txrhead=lp->txrhead->next;
+ lp->txrcommit--;
+ }
+}
+
+
+/* tx function for slave modes */
static int hp100_start_xmit( struct sk_buff *skb, struct device *dev )
{
int i, ok_flag;
- int ioaddr = dev -> base_addr;
+ int ioaddr = dev->base_addr;
u_short val;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4212, TRACE );
+ printk("hp100: start_xmit\n");
+#endif
- if ( lp -> lan_type < 0 )
+ if ( lp->lan_type < 0 ) /* no LAN type detected yet? */
{
hp100_stop_interface( dev );
- if ( ( lp -> lan_type = hp100_sense_lan( dev ) ) < 0 )
+ if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 )
{
- printk( "%s: no connection found - check wire\n", dev -> name );
- hp100_start_interface( dev ); /* 10Mb/s RX packets maybe handled */
+ printk( "%s: no connection found - check wire\n", dev->name );
+ hp100_start_interface( dev ); /* 10Mb/s RX packets maybe handled */
return -EIO;
}
- if ( lp -> lan_type == HP100_LAN_100 )
- lp -> hub_status = hp100_login_to_vg_hub( dev );
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */
hp100_start_interface( dev );
}
- if ( ( i = ( hp100_inl( TX_MEM_FREE ) & ~0x7fffffff ) ) < skb -> len + 16 )
+ /* If there is not enough free memory on the card... */
+ i=hp100_inl(TX_MEM_FREE)&0x7fffffff;
+ if ( !(((i/2)-539)>(skb->len+16) && (hp100_inb(TX_PKT_CNT)<255)) )
{
#ifdef HP100_DEBUG
- printk( "hp100_start_xmit: rx free mem = 0x%x\n", i );
+ printk( "hp100_start_xmit: tx free mem = 0x%x\n", i );
#endif
- if ( jiffies - dev -> trans_start < 2 * HZ ) return -EAGAIN;
- if ( lp -> lan_type == HP100_LAN_100 && lp -> hub_status < 0 )
- /* 100Mb/s adapter isn't connected to hub */
+ /* not waited long enough since last failed tx try? */
+ if ( jiffies - dev->trans_start < HZ/2 )
+ {
+#ifdef HP100_DEBUG
+ printk("hp100: trans_start timing problem\n");
+#endif
+ return -EAGAIN;
+ }
+ if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 )
+ /* we have a 100Mb/s adapter but it isn't connected to hub */
{
- printk( "%s: login to 100Mb/s hub retry\n", dev -> name );
+ printk( "%s: login to 100Mb/s hub retry\n", dev->name );
hp100_stop_interface( dev );
- lp -> hub_status = hp100_login_to_vg_hub( dev );
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
hp100_start_interface( dev );
}
- else
+ else
{
hp100_ints_off();
i = hp100_sense_lan( dev );
hp100_page( PERFORMANCE );
hp100_ints_on();
if ( i == HP100_LAN_ERR )
- printk( "%s: link down detected\n", dev -> name );
- else
- if ( lp -> lan_type != i )
- {
- /* it's very heavy - all network setting must be changed!!! */
- printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev -> name );
- lp -> lan_type = i;
- hp100_stop_interface( dev );
- if ( lp -> lan_type == HP100_LAN_100 )
- lp -> hub_status = hp100_login_to_vg_hub( dev );
- hp100_start_interface( dev );
- }
- else
- {
- printk( "%s: interface reset\n", dev -> name );
- hp100_stop_interface( dev );
- hp100_start_interface( dev );
- }
+ printk( "%s: link down detected\n", dev->name );
+ else
+ if ( lp->lan_type != i ) /* cable change! */
+ {
+ /* it's very hard - all network setting must be changed!!! */
+ printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name );
+ lp->lan_type = i;
+ hp100_stop_interface( dev );
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+ hp100_start_interface( dev );
+ }
+ else
+ {
+ printk( "%s: interface reset\n", dev->name );
+ hp100_stop_interface( dev );
+ hp100_start_interface( dev );
+ udelay(1000);
+ }
}
- dev -> trans_start = jiffies;
+ dev->trans_start = jiffies;
return -EAGAIN;
}
- for ( i = 0; i < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_TX_CMD ); i++ )
+ for ( i=0; i<6000 && ( hp100_inb( OPTION_MSW ) & HP100_TX_CMD ); i++ )
{
#ifdef HP100_DEBUG_TX
printk( "hp100_start_xmit: busy\n" );
#endif
}
-
+
hp100_ints_off();
val = hp100_inw( IRQ_STATUS );
- hp100_outw( val & HP100_TX_COMPLETE, IRQ_STATUS );
+ /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set
+ * when the current packet being transmitted on the wire is completed. */
+ hp100_outw( HP100_TX_COMPLETE, IRQ_STATUS );
#ifdef HP100_DEBUG_TX
- printk( "hp100_start_xmit: irq_status = 0x%x, len = %d\n", val, (int)skb -> len );
+ printk("hp100_start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n",val,hp100_inw(IRQ_MASK),(int)skb->len );
#endif
- ok_flag = skb -> len >= HP100_MIN_PACKET_SIZE;
- i = ok_flag ? skb -> len : HP100_MIN_PACKET_SIZE;
- hp100_outw( i, DATA32 ); /* length to memory manager */
- hp100_outw( i, FRAGMENT_LEN );
- if ( lp -> mem_mapped )
+
+ ok_flag = skb->len >= HP100_MIN_PACKET_SIZE;
+ i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE;
+
+ hp100_outw( i, DATA32 ); /* tell card the total packet length */
+ hp100_outw( i, FRAGMENT_LEN ); /* and first/only fragment length */
+
+ if ( lp->mode==2 ) /* memory mapped */
{
- if ( lp -> mem_ptr_virt )
- {
- memcpy( lp -> mem_ptr_virt, skb -> data, skb -> len );
- if ( !ok_flag )
- memset( lp -> mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb -> len );
- }
- else
- {
- memcpy_toio( lp -> mem_ptr_phys, skb -> data, skb -> len );
- if ( !ok_flag )
- memset_io( lp -> mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb -> len );
- }
+ if ( lp->mem_ptr_virt ) /* high pci memory was remapped */
+ {
+ /* Note: The J2585B needs alignment to 32bits here! */
+ memcpy( lp->mem_ptr_virt, skb->data, ( skb->len +3 ) & ~3 );
+ if ( !ok_flag )
+ memset( lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len );
+ }
+ else
+ {
+ memcpy_toio( lp->mem_ptr_phys, skb->data, skb->len );
+ if ( !ok_flag )
+ memset_io( lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len );
+ }
}
- else
+ else /* programmed i/o */
{
- outsl( ioaddr + HP100_REG_DATA32, skb -> data, ( skb -> len + 3 ) >> 2 );
+ outsl( ioaddr + HP100_REG_DATA32, skb->data, ( skb->len + 3 ) >> 2 );
if ( !ok_flag )
- for ( i = ( skb -> len + 3 ) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4 )
- hp100_outl( 0, DATA32 );
+ for ( i = ( skb->len + 3 ) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4 )
+ hp100_outl( 0, DATA32 );
}
- hp100_outw( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */
- lp -> stats.tx_packets++;
- dev -> trans_start = jiffies;
+
+ hp100_outb( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */
+
+ lp->stats.tx_packets++;
+#ifdef LINUX_2_1
+ lp->stats.tx_bytes += skb->len;
+#endif
+ dev->trans_start=jiffies;
hp100_ints_on();
-
+
dev_kfree_skb( skb, FREE_WRITE );
-
+
#ifdef HP100_DEBUG_TX
printk( "hp100_start_xmit: end\n" );
#endif
-
+
return 0;
}
+
/*
- * receive - called from interrupt handler
+ * Receive Function (Non-Busmaster mode)
+ * Called when an "Receive Packet" interrupt occurs, i.e. the receive
+ * packet counter is non-zero.
+ * For non-busmaster, this function does the whole work of transfering
+ * the packet to the host memory and then up to higher layers via skb
+ * and netif_rx.
*/
static void hp100_rx( struct device *dev )
{
int packets, pkt_len;
- int ioaddr = dev -> base_addr;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
u_int header;
struct sk_buff *skb;
-#if 0
- if ( lp -> lan_type < 0 )
- {
- if ( ( lp -> lan_type = hp100_sense_lan( dev ) ) == HP100_LAN_100 )
- lp -> hub_status = hp100_login_to_vg_hub( dev );
- hp100_page( PERFORMANCE );
- }
+#ifdef DEBUG_B
+ hp100_outw( 0x4213, TRACE );
+ printk("hp100: rx\n");
#endif
+ /* First get indication of received lan packet */
+ /* RX_PKT_CND indicates the number of packets which have been fully */
+ /* received onto the card but have not been fully transfered of the card */
packets = hp100_inb( RX_PKT_CNT );
-#ifdef HP100_DEBUG
+#ifdef HP100_DEBUG_RX
if ( packets > 1 )
printk( "hp100_rx: waiting packets = %d\n", packets );
#endif
+
while ( packets-- > 0 )
{
- for ( pkt_len = 0; pkt_len < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_ADV_NXT_PKT ); pkt_len++ )
+ /* If ADV_NXT_PKT is still set, we have to wait until the card has */
+ /* really advanced to the next packet. */
+ for (pkt_len=0; pkt_len<6000 &&(hp100_inb(OPTION_MSW)&HP100_ADV_NXT_PKT);
+ pkt_len++ )
{
-#ifdef HP100_DEBUG_TX
+#ifdef HP100_DEBUG_RX
printk( "hp100_rx: busy, remaining packets = %d\n", packets );
-#endif
+#endif
}
- if ( lp -> mem_mapped )
+
+ /* First we get the header, which contains information about the */
+ /* actual length of the received packet. */
+ if( lp->mode==2 ) /* memory mapped mode */
{
- if ( lp -> mem_ptr_virt )
- header = *(__u32 *)lp -> mem_ptr_virt;
- else
- header = readl( lp -> mem_ptr_phys );
+ if ( lp->mem_ptr_virt ) /* if memory was remapped */
+ header = *(__u32 *)lp->mem_ptr_virt;
+ else
+ header = readl( lp->mem_ptr_phys );
}
- else
+ else /* programmed i/o */
header = hp100_inl( DATA32 );
+
pkt_len = header & HP100_PKT_LEN_MASK;
+
#ifdef HP100_DEBUG_RX
- printk( "hp100_rx: new packet - length = %d, errors = 0x%x, dest = 0x%x\n",
- header & HP100_PKT_LEN_MASK, ( header >> 16 ) & 0xfff8, ( header >> 16 ) & 7 );
+ printk( "hp100_rx: new packet - length=%d, errors=0x%x, dest=0x%x\n",
+ header & HP100_PKT_LEN_MASK, (header>>16)&0xfff8,
+ (header>>16)&7);
#endif
- /*
- * NOTE! This (and the skb_put() below) depends on the skb-functions
+
+ /* Now we allocate the skb and transfer the data into it. */
+ /* NOTE! This (and the skb_put() below) depends on the skb-functions
* allocating more than asked (notably, aligning the request up to
* the next 16-byte length).
*/
skb = dev_alloc_skb( pkt_len );
- if ( skb == NULL )
- {
+ if ( skb == NULL ) /* Not enough memory->drop packet */
+ {
#ifdef HP100_DEBUG
- printk( "hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len );
+ printk( "hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len );
#endif
- lp -> stats.rx_dropped++;
- }
- else
- {
- u_char *ptr;
-
- skb -> dev = dev;
- ptr = (u_char *)skb_put( skb, pkt_len );
- if ( lp -> mem_mapped )
+ lp->stats.rx_dropped++;
+ }
+ else /* skb successfully allocated */
+ {
+ u_char *ptr;
+
+ skb->dev = dev;
+
+ /* ptr to start of the sk_buff data area */
+ ptr = (u_char *)skb_put( skb, pkt_len );
+
+ /* Now transfer the data from the card into that area */
+ if ( lp->mode==2 )
{
- if ( lp -> mem_ptr_virt )
- memcpy( ptr, lp -> mem_ptr_virt, ( pkt_len + 3 ) & ~3 );
- else
- memcpy_fromio( ptr, lp -> mem_ptr_phys, ( pkt_len + 3 ) & ~3 );
+ if ( lp->mem_ptr_virt )
+ memcpy( ptr, lp->mem_ptr_virt, ( pkt_len + 3 ) & ~3 );
+ /* Note alignment to 32bit transfers */
+ else
+ memcpy_fromio( ptr, lp->mem_ptr_phys, ( pkt_len + 3 ) & ~3 );
}
- else
- insl( ioaddr + HP100_REG_DATA32, ptr, ( pkt_len + 3 ) >> 2 );
- skb -> protocol = eth_type_trans( skb, dev );
- netif_rx( skb );
- lp -> stats.rx_packets++;
+ else /* io mapped */
+ insl( ioaddr + HP100_REG_DATA32, ptr, ( pkt_len + 3 ) >> 2 );
+
+ skb->protocol = eth_type_trans( skb, dev );
+
+ netif_rx( skb );
+ lp->stats.rx_packets++;
+#ifdef LINUX_2_1
+ lp->stats.rx_bytes += skb->len;
+#endif
+
#ifdef HP100_DEBUG_RX
- printk( "rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ],
- ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] );
+ printk( "rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ],
+ ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] );
#endif
- }
- hp100_outw( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW );
+ }
+
+ /* Indicate the card that we have got the packet */
+ hp100_outb( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW );
+
switch ( header & 0x00070000 ) {
- case (HP100_MULTI_ADDR_HASH<<16):
- case (HP100_MULTI_ADDR_NO_HASH<<16):
- lp -> stats.multicast++; break;
+ case (HP100_MULTI_ADDR_HASH<<16):
+ case (HP100_MULTI_ADDR_NO_HASH<<16):
+ lp->stats.multicast++; break;
}
- }
+ } /* end of while(there are packets) loop */
#ifdef HP100_DEBUG_RX
- printk( "hp100_rx: end\n" );
+ printk( "hp100_rx: end\n" );
+#endif
+}
+
+
+/*
+ * Receive Function for Busmaster Mode
+ */
+static void hp100_rx_bm( struct device *dev )
+{
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ hp100_ring_t *ptr;
+ u_int header;
+ int pkt_len;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4214, TRACE );
+ printk("hp100: rx_bm\n");
+#endif
+
+#ifdef HP100_DEBUG
+ if(0==lp->rxrcommit)
+ {
+ printk("hp100: rx_bm called although no PDLs were committed to adapter?\n");
+ return;
+ }
+ else
+
+ /* RX_PKT_CNT states how many PDLs are currently formatted and available to
+ * the cards BM engine */
+ if( (hp100_inw(RX_PKT_CNT)&0x00ff) >= lp->rxrcommit)
+ {
+ printk("hp100: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n", hp100_inw(RX_PKT_CNT)&0x00ff, lp->rxrcommit);
+ return;
+ }
+#endif
+
+ while( (lp->rxrcommit > hp100_inb(RX_PDL)) )
+ {
+ /*
+ * The packet was received into the pdl pointed to by lp->rxrhead (
+ * the oldest pdl in the ring
+ */
+
+ /* First we get the header, which contains information about the */
+ /* actual length of the received packet. */
+
+ ptr=lp->rxrhead;
+
+ header = *(ptr->pdl-1);
+ pkt_len = (header & HP100_PKT_LEN_MASK);
+
+#ifdef HP100_DEBUG_BM
+ printk( "hp100: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n",
+ (u_int) (ptr->pdl-1),(u_int) header,
+ pkt_len,
+ (header>>16)&0xfff8,
+ (header>>16)&7);
+ printk( "hp100: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n",
+ hp100_inb( RX_PDL ),
+ hp100_inb( TX_PDL ),
+ hp100_inb( RX_PKT_CNT ),
+ (u_int) *(ptr->pdl),
+ (u_int) *(ptr->pdl+3),
+ (u_int) *(ptr->pdl+4));
+#endif
+
+ if( (pkt_len>=MIN_ETHER_SIZE) &&
+ (pkt_len<=MAX_ETHER_SIZE) )
+ {
+ if(ptr->skb==NULL)
+ {
+ printk("hp100: rx_bm: skb null\n");
+ /* can happen if we only allocated room for the pdh due to memory shortage. */
+ lp->stats.rx_dropped++;
+ }
+ else
+ {
+ skb_trim( ptr->skb, pkt_len ); /* Shorten it */
+ ptr->skb->protocol = eth_type_trans( ptr->skb, dev );
+
+ netif_rx( ptr->skb ); /* Up and away... */
+
+ lp->stats.rx_packets++;
+#ifdef LINUX_2_1
+ lp->stats.rx_bytes += ptr->skb->len;
+#endif
+ }
+
+ switch ( header & 0x00070000 ) {
+ case (HP100_MULTI_ADDR_HASH<<16):
+ case (HP100_MULTI_ADDR_NO_HASH<<16):
+ lp->stats.multicast++; break;
+ }
+ }
+ else
+ {
+#ifdef HP100_DEBUG
+ printk("hp100: rx_bm: Received bad packet (length=%d)\n",pkt_len);
+#endif
+ if(ptr->skb!=NULL)
+ dev_kfree_skb( ptr->skb, FREE_READ );
+ lp->stats.rx_errors++;
+ }
+
+ lp->rxrhead=lp->rxrhead->next;
+
+ /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */
+ if (0 == hp100_build_rx_pdl( lp->rxrtail, dev ))
+ {
+ /* No space for skb, header can still be received. */
+#ifdef HP100_DEBUG
+ printk("hp100: rx_bm: No space for new PDL.\n");
#endif
+ return;
+ }
+ else
+ { /* successfully allocated new PDL - put it in ringlist at tail. */
+ hp100_outl((u32)lp->rxrtail->pdl_paddr, RX_PDA);
+ lp->rxrtail=lp->rxrtail->next;
+ }
+
+ }
}
+
+
/*
* statistics
*/
-
-static struct net_device_stats *hp100_get_stats( struct device *dev )
+static hp100_stats_t *hp100_get_stats( struct device *dev )
{
- int ioaddr = dev -> base_addr;
+ int ioaddr = dev->base_addr;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4215, TRACE );
+#endif
hp100_ints_off();
hp100_update_stats( dev );
hp100_ints_on();
- return &((struct hp100_private *)dev -> priv) -> stats;
+ return &((struct hp100_private *)dev->priv)->stats;
}
static void hp100_update_stats( struct device *dev )
{
- int ioaddr = dev -> base_addr;
+ int ioaddr = dev->base_addr;
u_short val;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4216, TRACE );
+ printk("hp100: update-stats\n");
+#endif
- hp100_page( MAC_CTRL ); /* get all statistics bytes */
+ /* Note: Statistics counters clear when read. */
+ hp100_page( MAC_CTRL );
val = hp100_inw( DROPPED ) & 0x0fff;
- lp -> stats.rx_errors += val;
- lp -> stats.rx_over_errors += val;
+ lp->stats.rx_errors += val;
+ lp->stats.rx_over_errors += val;
val = hp100_inb( CRC );
- lp -> stats.rx_errors += val;
- lp -> stats.rx_crc_errors += val;
+ lp->stats.rx_errors += val;
+ lp->stats.rx_crc_errors += val;
val = hp100_inb( ABORT );
- lp -> stats.tx_errors += val;
- lp -> stats.tx_aborted_errors += val;
+ lp->stats.tx_errors += val;
+ lp->stats.tx_aborted_errors += val;
hp100_page( PERFORMANCE );
}
static void hp100_clear_stats( int ioaddr )
{
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4217, TRACE );
+ printk("hp100: clear_stats\n");
+#endif
+
cli();
- hp100_page( MAC_CTRL ); /* get all statistics bytes */
+ hp100_page( MAC_CTRL ); /* get all statistics bytes */
hp100_inw( DROPPED );
hp100_inb( CRC );
hp100_inb( ABORT );
@@ -831,54 +2031,73 @@ static void hp100_clear_stats( int ioaddr )
sti();
}
+
/*
* multicast setup
*/
/*
* Set or clear the multicast filter for this adapter.
+ * TODO: Currently when in multicast mode, card accepts all multicast packets
+ * for all MC addresses. Should better use the list on the card.
*/
-
+
static void hp100_set_multicast_list( struct device *dev)
{
- int ioaddr = dev -> base_addr;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
-#ifdef HP100_DEBUG_MULTI
- printk( "hp100_set_multicast_list: num_addrs = %d\n", dev->mc_count);
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4218, TRACE );
+ printk("hp100: set_mc_list\n");
#endif
+
cli();
hp100_ints_off();
hp100_page( MAC_CTRL );
- hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */
+ hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */
- if ( dev->flags&IFF_PROMISC)
+ if ( dev->flags & IFF_PROMISC )
{
- lp -> mac2_mode = HP100_MAC2MODE6; /* promiscuous mode, all good */
- lp -> mac1_mode = HP100_MAC1MODE6; /* packets on the net */
+ lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */
+ lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */
}
- else
- if ( dev->mc_count || dev->flags&IFF_ALLMULTI )
+ else if ( dev->mc_count || (dev->flags&IFF_ALLMULTI) )
{
- lp -> mac2_mode = HP100_MAC2MODE5; /* multicast mode, packets for me */
- lp -> mac1_mode = HP100_MAC1MODE5; /* broadcasts and all multicasts */
+ lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */
+ lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */
}
- else
+ else
{
- lp -> mac2_mode = HP100_MAC2MODE3; /* normal mode, packets for me */
- lp -> mac1_mode = HP100_MAC1MODE3; /* and broadcasts */
+ lp->mac2_mode = HP100_MAC2MODE3; /* normal mode = get packets for me */
+ lp->mac1_mode = HP100_MAC1MODE3; /* and broadcasts */
}
- hp100_outb( lp -> mac2_mode, MAC_CFG_2 );
- hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 );
- hp100_orb( lp -> mac1_mode |
- HP100_RX_EN | HP100_RX_IDLE | /* enable rx */
- HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 ); /* enable tx */
+ if ( ( (hp100_inb(MAC_CFG_1) & 0x0f)!=lp->mac1_mode ) ||
+ ( hp100_inb(MAC_CFG_2)!=lp->mac2_mode ) ) {
+ hp100_outb( lp->mac2_mode, MAC_CFG_2 );
+ hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 ); /* clear mac1 mode bits */
+ hp100_orb( lp->mac1_mode, MAC_CFG_1 ); /* and set the new mode */
+
+ if(lp->lan_type==HP100_LAN_100)
+ {
+#ifdef HP100_DEBUG
+ printk("hp100: 100VG MAC settings have changed - relogin.\n");
+#endif
+ lp->hub_status=hp100_login_to_vg_hub( dev, TRUE ); /* force a relogin to the hub */
+ }
+ }
+
+ hp100_page( MAC_CTRL );
+ hp100_orb( HP100_RX_EN | HP100_RX_IDLE | /* enable rx */
+ HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 ); /* enable tx */
+
hp100_page( PERFORMANCE );
hp100_ints_on();
sti();
}
+
/*
* hardware interrupt handling
*/
@@ -886,249 +2105,747 @@ static void hp100_set_multicast_list( struct device *dev)
static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs )
{
struct device *dev = (struct device *)irq2dev_map[ irq ];
- struct hp100_private *lp;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
int ioaddr;
- u_short val;
+ u_int val;
if ( dev == NULL ) return;
- ioaddr = dev -> base_addr;
- if ( dev -> interrupt )
- printk( "%s: re-entering the interrupt handler\n", dev -> name );
+ ioaddr = dev->base_addr;
+
+ if ( dev->interrupt )
+ printk( "%s: re-entering the interrupt handler\n", dev->name );
hp100_ints_off();
- dev -> interrupt = 1;
- hp100_page( PERFORMANCE );
+ dev->interrupt = 1; /* mark that we are inside the handler */
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4219, TRACE );
+#endif
+
+ /* hp100_page( PERFORMANCE ); */
val = hp100_inw( IRQ_STATUS );
#ifdef HP100_DEBUG_IRQ
- printk( "hp100_interrupt: irq_status = 0x%x\n", val );
+ printk( "hp100: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n",
+ lp->mode,
+ (u_int)val,
+ hp100_inb( RX_PKT_CNT ),
+ hp100_inb( RX_PDL ),
+ hp100_inb( TX_PKT_CNT ),
+ hp100_inb( TX_PDL )
+ );
#endif
- if ( val & HP100_RX_PACKET )
+
+ if(val==0) /* might be a shared interrupt */
{
- hp100_rx( dev );
- hp100_outw( HP100_RX_PACKET, IRQ_STATUS );
+ dev->interrupt=0;
+ hp100_ints_on();
+ return;
}
- if ( val & (HP100_TX_SPACE_AVAIL | HP100_TX_COMPLETE) )
+ /* We're only interested in those interrupts we really enabled. */
+ /* val &= hp100_inw( IRQ_MASK ); */
+
+ /*
+ * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL
+ * is considered executed whenever the RX_PDL data structure is no longer
+ * needed.
+ */
+ if ( val & HP100_RX_PDL_FILL_COMPL )
{
- hp100_outw( val & (HP100_TX_SPACE_AVAIL | HP100_TX_COMPLETE), IRQ_STATUS );
+ if(lp->mode==1)
+ hp100_rx_bm( dev );
+ else
+ printk("hp100: rx_pdl_fill_compl interrupt although not busmaster?\n");
}
- if ( val & ( HP100_TX_ERROR | HP100_RX_ERROR ) )
+
+ /*
+ * The RX_PACKET interrupt is set, when the receive packet counter is
+ * non zero. We use this interrupt for receiving in slave mode. In
+ * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill
+ * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then
+ * we somehow have missed a rx_pdl_fill_compl interrupt.
+ */
+
+ if ( val & HP100_RX_PACKET ) /* Receive Packet Counter is non zero */
{
- lp = (struct hp100_private *)dev -> priv;
- hp100_update_stats( dev );
- hp100_outw( val & (HP100_TX_ERROR | HP100_RX_ERROR), IRQ_STATUS );
+ if(lp->mode!=1) /* non busmaster */
+ hp100_rx( dev );
+ else if ( !(val & HP100_RX_PDL_FILL_COMPL ))
+ {
+ /* Shouldnt happen - maybe we missed a RX_PDL_FILL Interrupt? */
+ hp100_rx_bm( dev );
+ }
}
+
+ /*
+ * Ack. that we have noticed the interrupt and thereby allow next one.
+ * Note that this is now done after the slave rx function, since first
+ * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt
+ * on the J2573.
+ */
+ hp100_outw( val, IRQ_STATUS );
+
+ /*
+ * RX_ERROR is set when a packet is dropped due to no memory resources on
+ * the card or when a RCV_ERR occurs.
+ * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists
+ * only in the 802.3 MAC and happens when 16 collisions occur during a TX
+ */
+ if ( val & ( HP100_TX_ERROR | HP100_RX_ERROR ) )
+ {
#ifdef HP100_DEBUG_IRQ
- printk( "hp100_interrupt: end\n" );
+ printk("hp100: TX/RX Error IRQ\n");
#endif
- dev -> interrupt = 0;
+ hp100_update_stats( dev );
+ if(lp->mode==1)
+ {
+ hp100_rxfill( dev );
+ hp100_clean_txring( dev );
+ }
+ }
+
+ /*
+ * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero.
+ */
+ if ( (lp->mode==1)&&(val &(HP100_RX_PDA_ZERO)) )
+ hp100_rxfill( dev );
+
+ /*
+ * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire
+ * is completed
+ */
+ if ( (lp->mode==1) && ( val & ( HP100_TX_COMPLETE )) )
+ hp100_clean_txring( dev );
+
+ /*
+ * MISC_ERROR is set when either the LAN link goes down or a detected
+ * bus error occurs.
+ */
+ if ( val & HP100_MISC_ERROR ) /* New for J2585B */
+ {
+ printk("hp100: Misc. Error Interrupt - Check cabling.\n");
+ if(lp->mode==1)
+ {
+ hp100_clean_txring( dev );
+ hp100_rxfill( dev );
+ }
+ }
+
+ dev->interrupt = 0;
hp100_ints_on();
}
+
/*
* some misc functions
*/
static void hp100_start_interface( struct device *dev )
{
- int ioaddr = dev -> base_addr;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4220, TRACE );
+ printk("hp100: hp100_start_interface %s\n",dev->name);
+#endif
cli();
- hp100_unreset_card();
- hp100_page( MAC_CTRL );
- hp100_outb( lp -> mac2_mode, MAC_CFG_2 );
- hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 );
- hp100_orb( lp -> mac1_mode |
- HP100_RX_EN | HP100_RX_IDLE |
- HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 );
+
+ /* Ensure the adapter does not want to request an interrupt when */
+ /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */
hp100_page( PERFORMANCE );
- hp100_outw( HP100_INT_EN | HP100_SET_LB, OPTION_LSW );
- hp100_outw( HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW );
- if ( lp -> mem_mapped )
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* ack all IRQs */
+ hp100_outw( HP100_FAKE_INT|HP100_INT_EN|HP100_RESET_LB, OPTION_LSW);
+ /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */
+ hp100_outw( HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW );
+
+ if(lp->mode==1)
+ {
+ /* Make sure BM bit is set... */
+ hp100_page(HW_MAP);
+ hp100_orb( HP100_BM_MASTER, BM );
+ hp100_rxfill( dev );
+ }
+ else if(lp->mode==2)
{
- /* enable memory mapping */
+ /* Enable memory mapping. Note: Don't do this when busmaster. */
hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW );
}
- sti();
+
+ hp100_page(PERFORMANCE);
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */
+
+ /* enable a few interrupts: */
+ if(lp->mode==1) /* busmaster mode */
+ {
+ hp100_outw( HP100_RX_PDL_FILL_COMPL |
+ HP100_RX_PDA_ZERO |
+ HP100_RX_ERROR |
+ /* HP100_RX_PACKET | */
+ /* HP100_RX_EARLY_INT | */ HP100_SET_HB |
+ /* HP100_TX_PDA_ZERO | */
+ HP100_TX_COMPLETE |
+ /* HP100_MISC_ERROR | */
+ HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK );
+ }
+ else
+ {
+ hp100_outw( HP100_RX_PACKET |
+ HP100_RX_ERROR | HP100_SET_HB |
+ HP100_TX_ERROR | HP100_SET_LB , IRQ_MASK );
+ }
+
+ /* Enable MAC Tx and RX, set MAC modes, ... */
+ /* Note: This function also turns on the interrupts. */
+ hp100_set_multicast_list( dev );
}
+
static void hp100_stop_interface( struct device *dev )
{
- int ioaddr = dev -> base_addr;
- u_short val;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ u_int val;
- hp100_outw( HP100_INT_EN | HP100_RESET_LB |
- HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
- val = hp100_inw( OPTION_LSW );
- hp100_page( HW_MAP );
- hp100_andb( HP100_BM_SLAVE, BM );
- hp100_page( MAC_CTRL );
- hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 );
- if ( !(val & HP100_HW_RST) ) return;
- for ( val = 0; val < 6000; val++ )
- if ( ( hp100_inb( MAC_CFG_1 ) & (HP100_TX_IDLE | HP100_RX_IDLE) ) ==
- (HP100_TX_IDLE | HP100_RX_IDLE) )
- return;
- printk( "%s: hp100_stop_interface - timeout\n", dev -> name );
+#ifdef HP100_DEBUG_B
+ printk("hp100: hp100_stop_interface %s\n",dev->name);
+ hp100_outw( 0x4221, TRACE );
+#endif
+
+ if (lp->mode==1)
+ hp100_BM_shutdown( dev );
+ else
+ {
+ /* Note: MMAP_DIS will be reenabled by start_interface */
+ hp100_outw( HP100_INT_EN | HP100_RESET_LB |
+ HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
+ val = hp100_inw( OPTION_LSW );
+
+ hp100_page( MAC_CTRL );
+ hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 );
+
+ if ( !(val & HP100_HW_RST) ) return; /* If reset, imm. return ... */
+ /* ... else: busy wait until idle */
+ for ( val = 0; val < 6000; val++ )
+ if ( ( hp100_inb( MAC_CFG_1 ) & (HP100_TX_IDLE | HP100_RX_IDLE) ) ==
+ (HP100_TX_IDLE | HP100_RX_IDLE) )
+ {
+ hp100_page(PERFORMANCE);
+ return;
+ }
+ printk( "%s: hp100_stop_interface - timeout\n", dev->name );
+ hp100_page(PERFORMANCE);
+ }
}
+
static void hp100_load_eeprom( struct device *dev )
{
int i;
- int ioaddr = dev -> base_addr;
+ int ioaddr = dev->base_addr;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4222, TRACE );
+#endif
hp100_page( EEPROM_CTRL );
hp100_andw( ~HP100_EEPROM_LOAD, EEPROM_CTRL );
hp100_orw( HP100_EEPROM_LOAD, EEPROM_CTRL );
- for ( i = 0; i < 6000; i++ )
- if ( !( hp100_inw( OPTION_MSW ) & HP100_EE_LOAD ) ) return;
- printk( "%s: hp100_load_eeprom - timeout\n", dev -> name );
+ for ( i = 0; i < 10000; i++ )
+ if ( !( hp100_inb( OPTION_MSW ) & HP100_EE_LOAD ) ) return;
+ printk( "%s: hp100_load_eeprom - timeout\n", dev->name );
}
-/* return values: LAN_10, LAN_100 or LAN_ERR (not connected or hub is down)... */
-
+
+/* Sense connection status.
+ * return values: LAN_10 - Connected to 10Mbit/s network
+ * LAN_100 - Connected to 100Mbit/s network
+ * LAN_ERR - not connected or 100Mbit/s Hub down
+ */
static int hp100_sense_lan( struct device *dev )
{
- int i;
- int ioaddr = dev -> base_addr;
+ int ioaddr = dev->base_addr;
u_short val_VG, val_10;
- struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4223, TRACE );
+#endif
hp100_page( MAC_CTRL );
- hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
- val_10 = hp100_inw( LAN_CFG_10 );
- val_VG = hp100_inw( LAN_CFG_VG );
-#ifdef HP100_DEBUG_SENSE
+ /* Enable Auto Selection */
+ /* hp100_orb( HP100_VG_RESET|HP100_LINK_CMD|HP100_VG_SEL, VG_LAN_CFG_1 ); */
+ /* hp100_orb( HP100_DOT3_MAC,10_LAN_CFG_2); */
+ /* hp100_orb( HP100_AUTO_MODE,MAC_CFG_3); */
+ /* Now we have to wait a while... */
+ /* for(i=0; i<5000; i++) */
+ /* { */
+ val_10 = hp100_inb( 10_LAN_CFG_1 );
+ val_VG = hp100_inb( VG_LAN_CFG_1 );
+ /* } */
+#ifdef HP100_DEBUG
printk( "hp100_sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", val_VG, val_10 );
#endif
if ( val_10 & HP100_LINK_BEAT_ST ) return HP100_LAN_10;
- if ( lp -> id -> id == 0x02019F022 ) /* HP J27248B doesn't have 100Mb/s interface */
- return HP100_LAN_ERR;
- for ( i = 0; i < 2500; i++ )
- {
- val_VG = hp100_inw( LAN_CFG_VG );
- if ( val_VG & HP100_LINK_CABLE_ST ) return HP100_LAN_100;
+ if ( (lp->id->id == 0x02019F022) ||
+ (lp->id->id == 0x01042103c) ||
+ (lp->id->id == 0x01040103c) )
+ {
+ hp100_page(PERFORMANCE);
+ return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */
}
+ /* for ( i = 0; i < 2500; i++ ) */
+ /* { */
+ val_VG = hp100_inb( VG_LAN_CFG_1 );
+ hp100_page(PERFORMANCE);
+
+ if ( val_VG & HP100_LINK_CABLE_ST ) /* Can hear the HUBs tone. */
+ return HP100_LAN_100;
+ /* } */
return HP100_LAN_ERR;
}
+
+
static int hp100_down_vg_link( struct device *dev )
{
- int ioaddr = dev -> base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ int ioaddr = dev->base_addr;
unsigned long time;
- int i;
+ long savelan, newlan;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4224, TRACE );
+ printk("hp100: down_vg_link\n");
+#endif
hp100_page( MAC_CTRL );
- for ( i = 2500; i > 0; i-- )
- if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
- if ( i <= 0 ) /* not signal - not logout */
+ time=jiffies+(HZ/4);
+ do{
+ if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break;
+ } while (time>jiffies);
+
+ if ( jiffies >= time ) /* no signal->no logout */
return 0;
- hp100_andw( ~HP100_LINK_CMD, LAN_CFG_VG );
- time = jiffies + 10*HZ/100;
- while ( time > jiffies )
- if ( !( hp100_inw( LAN_CFG_VG ) & ( HP100_LINK_UP_ST |
- HP100_LINK_CABLE_ST |
- HP100_LINK_GOOD_ST ) ) )
- return 0;
+
+ /* Drop the VG Link by clearing the link up cmd and load addr.*/
+
+ hp100_andb( ~( HP100_LOAD_ADDR| HP100_LINK_CMD), VG_LAN_CFG_1);
+ hp100_orb( HP100_VG_SEL, VG_LAN_CFG_1);
+
+ /* Conditionally stall for >250ms on Link-Up Status (to go down) */
+ time=jiffies+(HZ/2);
+ do{
+ if ( !(hp100_inb( VG_LAN_CFG_1) & HP100_LINK_UP_ST) ) break;
+ } while(time>jiffies);
+
#ifdef HP100_DEBUG
- printk( "hp100_down_vg_link: timeout\n" );
+ if (jiffies>=time)
+ printk("hp100_down_vg_link: Link does not go down?\n");
#endif
- return -EIO;
-}
-static int hp100_login_to_vg_hub( struct device *dev )
-{
- int i;
- int ioaddr = dev -> base_addr;
- u_short val;
- unsigned long time;
+ /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */
+ /* logout under traffic (even though all the status bits are cleared), */
+ /* do this workaround to get the Rev 1 MAC in its idle state */
+ if ( lp->chip==HP100_CHIPID_LASSEN )
+ {
+ /* Reset VG MAC to insure it leaves the logoff state even if */
+ /* the Hub is still emitting tones */
+ hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1);
+ udelay(1500); /* wait for >1ms */
+ hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); /* Release Reset */
+ udelay(1500);
+ }
- hp100_page( MAC_CTRL );
- hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
- time = jiffies + ( HZ / 2 );
+ /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */
+ /* to get the VG mac to full reset. This is not req.d with later chips */
+ /* Note: It will take the between 1 and 2 seconds for the VG mac to be */
+ /* selected again! This will be left to the connect hub function to */
+ /* perform if desired. */
+ if (lp->chip==HP100_CHIPID_LASSEN)
+ {
+ /* Have to write to 10 and 100VG control registers simultaneously */
+ savelan=newlan=hp100_inl(10_LAN_CFG_1); /* read 10+100 LAN_CFG regs */
+ newlan &= ~(HP100_VG_SEL<<16);
+ newlan |= (HP100_DOT3_MAC)<<8;
+ hp100_andb( ~HP100_AUTO_MODE, MAC_CFG_3); /* Autosel off */
+ hp100_outl(newlan, 10_LAN_CFG_1);
+
+ /* Conditionally stall for 5sec on VG selected. */
+ time=jiffies+(HZ*5);
+ do{
+ if( !(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST) ) break;
+ } while(time>jiffies);
+
+ hp100_orb( HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */
+ hp100_outl(savelan, 10_LAN_CFG_1);
+ }
+
+ time=jiffies+(3*HZ); /* Timeout 3s */
do {
- if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
- } while ( time > jiffies );
- if ( time <= jiffies )
+ if ( (hp100_inb( VG_LAN_CFG_1 )&HP100_LINK_CABLE_ST) == 0) break;
+ } while (time>jiffies);
+
+ if(time<=jiffies)
{
#ifdef HP100_DEBUG
- printk( "hp100_login_to_vg_hub: timeout for link\n" );
+ printk( "hp100_down_vg_link: timeout\n" );
#endif
return -EIO;
}
+
+ time=jiffies+(2*HZ); /* This seems to take a while.... */
+ do {} while (time>jiffies);
+
+ return 0;
+}
+
+
+static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin )
+{
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ u_short val=0;
+ unsigned long time;
+ int startst;
- if ( hp100_down_vg_link( dev ) < 0 ) /* if fail, try reset VG link */
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4225, TRACE );
+ printk("hp100: login_to_vg_hub\n");
+#endif
+
+ /* Initiate a login sequence iff VG MAC is enabled and either Load Address
+ * bit is zero or the force relogin flag is set (e.g. due to MAC address or
+ * promiscuous mode change)
+ */
+ hp100_page( MAC_CTRL );
+ startst=hp100_inb( VG_LAN_CFG_1 );
+ if((force_relogin==TRUE)||(hp100_inb( MAC_CFG_4 )&HP100_MAC_SEL_ST))
{
- hp100_andw( ~HP100_VG_RESET, LAN_CFG_VG );
- hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
+#ifdef HP100_DEBUG_TRAINING
+ printk("hp100: Start training\n");
+#endif
+
+ /* Ensure VG Reset bit is 1 (i.e., do not reset)*/
+ hp100_orb( HP100_VG_RESET , VG_LAN_CFG_1 );
+
+ /* If Lassen AND auto-select-mode AND VG tones were sensed on */
+ /* entry then temporarily put them into force 100Mbit mode */
+ if((lp->chip==HP100_CHIPID_LASSEN)&&( startst & HP100_LINK_CABLE_ST ) )
+ hp100_andb( ~HP100_DOT3_MAC, 10_LAN_CFG_2 );
+
+ /* Drop the VG link by zeroing Link Up Command and Load Address */
+ hp100_andb( ~(HP100_LINK_CMD/* |HP100_LOAD_ADDR */), VG_LAN_CFG_1);
+
+#ifdef HP100_DEBUG_TRAINING
+ printk("hp100: Bring down the link\n");
+#endif
+
+ /* Wait for link to drop */
+ time = jiffies + (HZ/10);
+ do {
+ if (~(hp100_inb( VG_LAN_CFG_1 )& HP100_LINK_UP_ST) ) break;
+ } while (time>jiffies);
+
+ /* Start an addressed training and optionally request promiscuous port */
+ if ( (dev->flags) & IFF_PROMISC )
+ {
+ hp100_orb( HP100_PROM_MODE, VG_LAN_CFG_2);
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ hp100_orw( HP100_MACRQ_PROMSC, TRAIN_REQUEST );
+ }
+ else
+ {
+ hp100_andb( ~HP100_PROM_MODE, VG_LAN_CFG_2);
+ /* For ETR parts we need to reset the prom. bit in the training
+ * register, otherwise promiscious mode won't be disabled.
+ */
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ {
+ hp100_andw( ~HP100_MACRQ_PROMSC, TRAIN_REQUEST );
+ }
+ }
+
+ /* With ETR parts, frame format request bits can be set. */
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ hp100_orb( HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST);
+
+ hp100_orb( HP100_LINK_CMD|HP100_LOAD_ADDR|HP100_VG_RESET, VG_LAN_CFG_1);
+
+ /* Note: Next wait could be omitted for Hood and earlier chips under */
+ /* certain circumstances */
+ /* TODO: check if hood/earlier and skip wait. */
+
+ /* Wait for either short timeout for VG tones or long for login */
+ /* Wait for the card hardware to signalise link cable status ok... */
+ hp100_page( MAC_CTRL );
+ time = jiffies + ( 1*HZ ); /* 1 sec timeout for cable st */
+ do {
+ if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break;
+ } while ( jiffies < time );
+
+ if ( jiffies >= time )
+ {
+#ifdef HP100_DEBUG_TRAINING
+ printk( "hp100: Link cable status not ok? Training aborted.\n" );
+#endif
+ }
+ else
+ {
+#ifdef HP100_DEBUG_TRAINING
+ printk( "hp100: HUB tones detected. Trying to train.\n");
+#endif
+
+ time = jiffies + ( 2*HZ ); /* again a timeout */
+ do {
+ val = hp100_inb( VG_LAN_CFG_1 );
+ if ( (val & ( HP100_LINK_UP_ST )) )
+ {
+#ifdef HP100_DEBUG_TRAINING
+ printk( "hp100: Passed training.\n");
+#endif
+ break;
+ }
+ } while ( time > jiffies );
+ }
+
+ /* If LINK_UP_ST is set, then we are logged into the hub. */
+ if ( (jiffies<=time) && (val & HP100_LINK_UP_ST) )
+ {
+#ifdef HP100_DEBUG_TRAINING
+ printk( "hp100: Successfully logged into the HUB.\n");
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ {
+ val = hp100_inw(TRAIN_ALLOW);
+ printk( "hp100: Card supports 100VG MAC Version \"%s\" ",
+ (hp100_inw(TRAIN_REQUEST)&HP100_CARD_MACVER) ? "802.12" : "Pre");
+ printk( "Driver will use MAC Version \"%s\"\n",
+ ( val & HP100_HUB_MACVER) ? "802.12" : "Pre" );
+ printk( "hp100: Frame format is %s.\n",(val&HP100_MALLOW_FRAMEFMT)?"802.5":"802.3");
+ }
+#endif
+ }
+ else
+ {
+ /* If LINK_UP_ST is not set, login was not successful */
+ printk("hp100/%s: Problem logging into the HUB.\n",dev->name);
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ {
+ /* Check allowed Register to find out why there is a problem. */
+ val = hp100_inw( TRAIN_ALLOW ); /* wont work on non-ETR card */
+#ifdef HP100_DEBUG_TRAINING
+ printk("hp100: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", hp100_inw(TRAIN_REQUEST), val);
+#endif
+ if ( val & HP100_MALLOW_ACCDENIED )
+ printk("hp100: HUB access denied.\n");
+ if ( val & HP100_MALLOW_CONFIGURE )
+ printk("hp100: MAC Configuration is incompatible with the Network.\n");
+ if ( val & HP100_MALLOW_DUPADDR )
+ printk("hp100: Duplicate MAC Address on the Network.\n");
+ }
+ }
+
+ /* If we have put the chip into forced 100 Mbit mode earlier, go back */
+ /* to auto-select mode */
+
+ if( (lp->chip==HP100_CHIPID_LASSEN)&&(startst & HP100_LINK_CABLE_ST) )
+ {
+ hp100_page( MAC_CTRL );
+ hp100_orb( HP100_DOT3_MAC, 10_LAN_CFG_2 );
+ }
+
+ val=hp100_inb(VG_LAN_CFG_1);
+
+ /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */
+ hp100_page(PERFORMANCE);
+ hp100_outw( HP100_MISC_ERROR, IRQ_STATUS);
+
+ if (val&HP100_LINK_UP_ST)
+ return(0); /* login was ok */
+ else
+ {
+ printk("hp100: Training failed.\n");
+ hp100_down_vg_link( dev );
+ return -EIO;
+ }
}
- /* bring up link */
- hp100_orw( HP100_LOAD_ADDR | HP100_LINK_CMD, LAN_CFG_VG );
- for ( i = 2500; i > 0; i-- )
- if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
- if ( i <= 0 )
- {
-#ifdef HP100_DEBUG
- printk( "hp100_login_to_vg_hub: timeout for link (bring up)\n" );
+ /* no forced relogin & already link there->no training. */
+ return -EIO;
+}
+
+
+static void hp100_cascade_reset( struct device *dev, u_short enable )
+{
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ int i;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4226, TRACE );
+ printk("hp100: cascade_reset\n");
#endif
- goto down_link;
+
+ if (enable==TRUE)
+ {
+ hp100_outw( HP100_HW_RST | HP100_RESET_LB, OPTION_LSW );
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ {
+ /* Lassen requires a PCI transmit fifo reset */
+ hp100_page( HW_MAP );
+ hp100_andb( ~HP100_PCI_RESET, PCICTRL2 );
+ hp100_orb( HP100_PCI_RESET, PCICTRL2 );
+ /* Wait for min. 300 ns */
+ /* we cant use jiffies here, because it may be */
+ /* that we have disabled the timer... */
+ for (i=0; i<0xffff; i++);
+ hp100_andb( ~HP100_PCI_RESET, PCICTRL2 );
+ hp100_page( PERFORMANCE );
+ }
+ }
+ else
+ { /* bring out of reset */
+ hp100_outw(HP100_HW_RST|HP100_SET_LB, OPTION_LSW);
+ for (i=0; i<0xffff; i++ );
+ hp100_page(PERFORMANCE);
}
+}
- time = jiffies + ( HZ / 2 );
- do {
- val = hp100_inw( LAN_CFG_VG );
- if ( ( val & ( HP100_LINK_UP_ST | HP100_LINK_GOOD_ST ) ) ==
- ( HP100_LINK_UP_ST | HP100_LINK_GOOD_ST ) )
- return 0; /* success */
- } while ( time > jiffies );
- if ( val & HP100_LINK_GOOD_ST )
- printk( "%s: 100Mb cable training failed, check cable.\n", dev -> name );
- else
- printk( "%s: 100Mb node not accepted by hub, check frame type or security.\n", dev -> name );
-
-down_link:
- hp100_down_vg_link( dev );
- hp100_page( MAC_CTRL );
- hp100_andw( ~( HP100_LOAD_ADDR | HP100_PROM_MODE ), LAN_CFG_VG );
- hp100_orw( HP100_LINK_CMD, LAN_CFG_VG );
- return -EIO;
+#ifdef HP100_DEBUG
+void hp100_RegisterDump( struct device *dev )
+{
+ int ioaddr=dev->base_addr;
+ int Page;
+ int Register;
+
+ /* Dump common registers */
+ printk("hp100: Cascade Register Dump\n");
+ printk("hardware id #1: 0x%.2x\n",hp100_inb(HW_ID));
+ printk("hardware id #2/paging: 0x%.2x\n",hp100_inb(PAGING));
+ printk("option #1: 0x%.4x\n",hp100_inw(OPTION_LSW));
+ printk("option #2: 0x%.4x\n",hp100_inw(OPTION_MSW));
+
+ /* Dump paged registers */
+ for (Page = 0; Page < 8; Page++)
+ {
+ /* Dump registers */
+ printk("page: 0x%.2x\n",Page);
+ outw( Page, ioaddr+0x02);
+ for (Register = 0x8; Register < 0x22; Register += 2)
+ {
+ /* Display Register contents except data port */
+ if (((Register != 0x10) && (Register != 0x12)) || (Page > 0))
+ {
+ printk("0x%.2x = 0x%.4x\n",Register,inw(ioaddr+Register));
+ }
+ }
+ }
+ hp100_page(PERFORMANCE);
}
+#endif
+
+
/*
* module section
*/
-
+
#ifdef MODULE
-static int hp100_port = -1;
-MODULE_PARM(hp100_port, "i");
+/* Parameters set by insmod */
+int hp100_port[5] = { 0, -1, -1, -1, -1 };
+#ifdef LINUX_2_1
+MODULE_PARM(hp100_port, "1-5i");
+#endif
-static char devicename[9] = { 0, };
-static struct device dev_hp100 = {
- devicename, /* device name is inserted by linux/drivers/net/net_init.c */
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, NULL, hp100_probe
-};
+#ifdef LINUX_2_1
+char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" };
+MODULE_PARM(hp100_name, "1-5c" __MODULE_STRING(IFNAMSIZ));
+#else
+static char devname[5][IFNAMSIZ] = { "", "", "", "", "" };
+static char *hp100_name[5] = { devname[0], devname[1],
+ devname[2], devname[3],
+ devname[4] };
+#endif
+
+/* List of devices */
+static struct device *hp100_devlist[5] = { NULL, NULL, NULL, NULL, NULL };
+
+/*
+ * Note: if you have more than five 100vg cards in your pc, feel free to
+ * increase this value
+ */
+
+/*
+ * Note: to register three eisa or pci devices, use:
+ * option hp100 hp100_port=0,0,0
+ * to register one card at io 0x280 as eth239, use:
+ * option hp100 hp100_port=0x280 hp100_name=eth239
+ */
int init_module( void )
{
- if (hp100_port == 0 && !EISA_bus)
+ int i;
+ int ret = 0;
+
+ if (hp100_port == 0 && !EISA_bus && !pcibios_present())
printk("HP100: You should not use auto-probing with insmod!\n");
- if ( hp100_port > 0 )
- dev_hp100.base_addr = hp100_port;
- if ( register_netdev( &dev_hp100 ) != 0 )
- return -EIO;
- return 0;
+
+ /* Loop on all possible base addresses */
+ i = -1;
+ while((hp100_port[++i] != -1) && (i < 5))
+ {
+ /* Create device and set basics args */
+ hp100_devlist[i] = kmalloc(sizeof(struct device), GFP_KERNEL);
+ memset(hp100_devlist[i], 0x00, sizeof(struct device));
+ hp100_devlist[i]->name = hp100_name[i];
+ hp100_devlist[i]->base_addr = hp100_port[i];
+ hp100_devlist[i]->init = &hp100_probe;
+
+ /* Try to create the device */
+ if(register_netdev(hp100_devlist[i]) != 0)
+ {
+ /* DeAllocate everything */
+ /* Note: if dev->priv is mallocated, there is no way to fail */
+ kfree_s(hp100_devlist[i], sizeof(struct device));
+ hp100_devlist[i] = (struct device *) NULL;
+ ret = -EIO;
+ }
+ } /* Loop over all devices */
+
+ return ret;
}
void cleanup_module( void )
{
- unregister_netdev( &dev_hp100 );
- release_region( dev_hp100.base_addr, HP100_REGION_SIZE );
- if ( ((struct hp100_private *)dev_hp100.priv) -> mem_ptr_virt )
- iounmap( ((struct hp100_private *)dev_hp100.priv) -> mem_ptr_virt );
- kfree_s( dev_hp100.priv, sizeof( struct hp100_private ) );
- dev_hp100.priv = NULL;
+ int i;
+
+ /* TODO: Check if all skb's are released/freed. */
+ for(i = 0; i < 5; i++)
+ if(hp100_devlist[i] != (struct device *) NULL)
+ {
+ unregister_netdev( hp100_devlist[i] );
+ release_region( hp100_devlist[i]->base_addr, HP100_REGION_SIZE );
+ if( ((struct hp100_private *)hp100_devlist[i]->priv)->mode==1 ) /* busmaster */
+ kfree_s( ((struct hp100_private *)hp100_devlist[i]->priv)->page_vaddr, MAX_RINGSIZE+0x0f);
+ if ( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt )
+ iounmap( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt );
+ kfree_s( hp100_devlist[i]->priv, sizeof( struct hp100_private ) );
+ hp100_devlist[i]->priv = NULL;
+ kfree_s(hp100_devlist[i], sizeof(struct device));
+ hp100_devlist[i] = (struct device *) NULL;
+ }
}
-#endif
+#endif /* MODULE */
+
+
+
+/*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp100.c"
+ * c-indent-level: 2
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/net/hp100.h b/drivers/net/hp100.h
index 1ebca564d..436dd3700 100644
--- a/drivers/net/hp100.h
+++ b/drivers/net/hp100.h
@@ -1,9 +1,10 @@
/*
* hp100.h: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux.
*
- * Author: Jaroslav Kysela, <perex@pf.jcu.cz>
+ * $Id: hp100.h,v 1.51 1997/04/08 14:26:42 floeff Exp floeff $
*
- * Header file...
+ * Authors: Jaroslav Kysela, <perex@pf.jcu.cz>
+ * Siegfried Loeffler <floeff@tunix.mathematik.uni-stuttgart.de>
*
* This driver is based on the 'hpfepkt' crynwr packet driver.
*
@@ -16,9 +17,10 @@
/****************************************************************************
* Hardware Constants
****************************************************************************/
-
-/*
- * ATT2MD01 Register Page Constants
+
+/*
+ * Page Identifiers
+ * (Swap Paging Register, PAGING, bits 3:0, Offset 0x02)
*/
#define HP100_PAGE_PERFORMANCE 0x0 /* Page 0 */
@@ -30,11 +32,8 @@
#define HP100_PAGE_ID_MAC_ADDR 0x6 /* Page 6 */
#define HP100_PAGE_MMU_POINTER 0x7 /* Page 7 */
-/*
- * ATT2MD01 Register Addresses
- */
-/* Present on all pages */
+/* Registers that are present on all pages */
#define HP100_REG_HW_ID 0x00 /* R: (16) Unique card ID */
#define HP100_REG_TRACE 0x00 /* W: (16) Used for debug output */
@@ -47,14 +46,29 @@
#define HP100_REG_IRQ_STATUS 0x08 /* RW: (16) Which ints are pending */
#define HP100_REG_IRQ_MASK 0x0a /* RW: (16) Select ints to allow */
-#define HP100_REG_FRAGMENT_LEN 0x0c /* RW: (16)12:0 Current fragment len */
+#define HP100_REG_FRAGMENT_LEN 0x0c /* W: (16)12:0 Current fragment len */
+/* Note: For 32 bit systems, fragment len and offset registers are available */
+/* at offset 0x28 and 0x2c, where they can be written as 32bit values. */
#define HP100_REG_OFFSET 0x0e /* RW: (16)12:0 Offset to start read */
#define HP100_REG_DATA32 0x10 /* RW: (32) I/O mode data port */
#define HP100_REG_DATA16 0x12 /* RW: WORDs must be read from here */
#define HP100_REG_TX_MEM_FREE 0x14 /* RD: (32) Amount of free Tx mem */
+#define HP100_REG_TX_PDA_L 0x14 /* W: (32) BM: Ptr to PDL, Low Pri */
+#define HP100_REG_TX_PDA_H 0x1c /* W: (32) BM: Ptr to PDL, High Pri */
#define HP100_REG_RX_PKT_CNT 0x18 /* RD: (8) Rx count of pkts on card */
#define HP100_REG_TX_PKT_CNT 0x19 /* RD: (8) Tx count of pkts on card */
-
+#define HP100_REG_RX_PDL 0x1a /* R: (8) BM: # rx pdl not executed */
+#define HP100_REG_TX_PDL 0x1b /* R: (8) BM: # tx pdl not executed */
+#define HP100_REG_RX_PDA 0x18 /* W: (32) BM: Up to 31 addresses */
+ /* which point to a PDL */
+#define HP100_REG_SL_EARLY 0x1c /* (32) Enhanced Slave Early Rx */
+#define HP100_REG_STAT_DROPPED 0x20 /* R (12) Dropped Packet Counter */
+#define HP100_REG_STAT_ERRORED 0x22 /* R (8) Errored Packet Counter */
+#define HP100_REG_STAT_ABORT 0x23 /* R (8) Abort Counter/OW Coll. Flag */
+#define HP100_REG_RX_RING 0x24 /* W (32) Slave: RX Ring Pointers */
+#define HP100_REG_32_FRAGMENT_LEN 0x28 /* W (13) Slave: Fragment Length Reg */
+#define HP100_REG_32_OFFSET 0x2c /* W (16) Slave: Offset Register */
+
/* Page 1 - MAC Address/Hash Table */
#define HP100_REG_MAC_ADDR 0x08 /* RW: (8) Cards MAC address */
@@ -68,27 +82,46 @@
#define HP100_REG_IRQ_CHANNEL 0x0d /* RW: (8) IRQ and edge/level int */
#define HP100_REG_SRAM 0x0e /* RW: (8) How much RAM on card */
#define HP100_REG_BM 0x0f /* RW: (8) Controls BM functions */
+
+/* New on Page 2 for ETR chips: */
+#define HP100_REG_MODECTRL1 0x10 /* RW: (8) Mode Control 1 */
+#define HP100_REG_MODECTRL2 0x11 /* RW: (8) Mode Control 2 */
+#define HP100_REG_PCICTRL1 0x12 /* RW: (8) PCI Cfg 1 */
+#define HP100_REG_PCICTRL2 0x13 /* RW: (8) PCI Cfg 2 */
+#define HP100_REG_PCIBUSMLAT 0x15 /* RW: (8) PCI Bus Master Latency */
+#define HP100_REG_EARLYTXCFG 0x16 /* RW: (16) Early TX Cfg/Cntrl Reg */
+#define HP100_REG_EARLYRXCFG 0x18 /* RW: (8) Early RX Cfg/Cntrl Reg */
+#define HP100_REG_ISAPNPCFG1 0x1a /* RW: (8) ISA PnP Cfg/Cntrl Reg 1 */
+#define HP100_REG_ISAPNPCFG2 0x1b /* RW: (8) ISA PnP Cfg/Cntrl Reg 2 */
/* Page 3 - EEPROM/Boot ROM */
#define HP100_REG_EEPROM_CTRL 0x08 /* RW: (16) Used to load EEPROM */
+#define HP100_REG_BOOTROM_CTRL 0x0a
-/* Page 4 - LAN Configuration */
+/* Page 4 - LAN Configuration (MAC_CTRL) */
-#define HP100_REG_LAN_CFG_10 0x08 /* RW: (16) Set 10M XCVR functions */
-#define HP100_REG_LAN_CFG_VG 0x0a /* RW: (16) Set 100M XCVR functions */
+#define HP100_REG_10_LAN_CFG_1 0x08 /* RW: (8) Set 10M XCVR functions */
+#define HP100_REG_10_LAN_CFG_2 0x09 /* RW: (8) 10M XCVR functions */
+#define HP100_REG_VG_LAN_CFG_1 0x0a /* RW: (8) Set 100M XCVR functions */
+#define HP100_REG_VG_LAN_CFG_2 0x0b /* RW: (8) 100M LAN Training cfgregs */
#define HP100_REG_MAC_CFG_1 0x0c /* RW: (8) Types of pkts to accept */
#define HP100_REG_MAC_CFG_2 0x0d /* RW: (8) Misc MAC functions */
-/* The follow clear when read: */
+#define HP100_REG_MAC_CFG_3 0x0e /* RW: (8) Misc MAC functions */
+#define HP100_REG_MAC_CFG_4 0x0f /* R: (8) Misc MAC states */
#define HP100_REG_DROPPED 0x10 /* R: (16),11:0 Pkts cant fit in mem*/
#define HP100_REG_CRC 0x12 /* R: (8) Pkts with CRC */
#define HP100_REG_ABORT 0x13 /* R: (8) Aborted Tx pkts */
-
+#define HP100_REG_TRAIN_REQUEST 0x14 /* RW: (16) Endnode MAC register.*/
+#define HP100_REG_TRAIN_ALLOW 0x16 /* R: (16) Hub allowed register */
+
/* Page 5 - MMU */
#define HP100_REG_RX_MEM_STOP 0x0c /* RW: (16) End of Rx ring addr */
#define HP100_REG_TX_MEM_STOP 0x0e /* RW: (16) End of Tx ring addr */
-
+#define HP100_REG_PDL_MEM_STOP 0x10 /* Not used by 802.12 devices */
+#define HP100_REG_ECB_MEM_STOP 0x14 /* I've no idea what this is */
+
/* Page 6 - Card ID/Physical LAN Address */
#define HP100_REG_BOARD_ID 0x08 /* R: (8) EISA/ISA card ID */
@@ -99,32 +132,46 @@
/* Page 7 - MMU Current Pointers */
-#define HP100_REG_RX_MEM_BR 0x08 /* R: (16) Current begin of Rx ring */
-#define HP100_REG_RX_MEM_ER 0x0a /* R: (16) Current end of Rx ring */
-#define HP100_REG_TX_MEM_BR 0x0c /* R: (16) Current begin of Tx ring */
-#define HP100_REG_TX_MEM_ER 0x0e /* R: (16) Current end of Rx ring */
-#define HP100_REG_MEM_DEBUG 0x1a /* RW: (16) Used for memory tests */
-
-/*
- * HardwareIDReg bits/masks
+#define HP100_REG_PTR_RXSTART 0x08 /* R: (16) Current begin of Rx ring */
+#define HP100_REG_PTR_RXEND 0x0a /* R: (16) Current end of Rx ring */
+#define HP100_REG_PTR_TXSTART 0x0c /* R: (16) Current begin of Tx ring */
+#define HP100_REG_PTR_TXEND 0x0e /* R: (16) Current end of Rx ring */
+#define HP100_REG_PTR_RPDLSTART 0x10
+#define HP100_REG_PTR_RPDLEND 0x12
+#define HP100_REG_PTR_RINGPTRS 0x14
+#define HP100_REG_PTR_MEMDEBUG 0x1a
+/* ------------------------------------------------------------------------ */
+
+
+/*
+ * Hardware ID Register I (Always available, HW_ID, Offset 0x00)
*/
+#define HP100_HW_ID_CASCADE 0x4850 /* Identifies Cascade Chip */
-#define HP100_HW_ID_0 0x50 /* Hardware ID bytes. */
-#define HP100_HW_ID_1 0x48
-#define HP100_HW_ID_2_REVA 0x50 /* Rev. A ID. NOTE: lower nibble not used */
-#define HP100_HW_ID_3 0x53
+/*
+ * Hardware ID Register 2 & Paging Register
+ * (Always available, PAGING, Offset 0x02)
+ * Bits 15:4 are for the Chip ID
+ */
+#define HP100_CHIPID_MASK 0xFFF0
+#define HP100_CHIPID_SHASTA 0x5350 /* Not 802.12 compliant */
+ /* EISA BM/SL, MCA16/32 SL, ISA SL */
+#define HP100_CHIPID_RAINIER 0x5360 /* Not 802.12 compliant EISA BM,*/
+ /* PCI SL, MCA16/32 SL, ISA SL */
+#define HP100_CHIPID_LASSEN 0x5370 /* 802.12 compliant PCI BM, PCI SL */
+ /* LRF supported */
/*
- * OptionLSWReg bits/masks
+ * Option Registers I and II
+ * (Always available, OPTION_LSW, Offset 0x04-0x05)
*/
-
-#define HP100_DEBUG_EN 0x8000 /* 0:Disable, 1:Enable Debug Dump Pointer */
-#define HP100_RX_HDR 0x4000 /* 0:Disable, 1:Enable putting pkt into */
- /* system memory before Rx interrupt */
-#define HP100_MMAP_DIS 0x2000 /* 0:Enable, 1:Disable memory mapping. */
- /* MMAP_DIS must be 0 and MEM_EN must */
- /* be 1 for memory-mapped mode to be */
- /* enabled */
+#define HP100_DEBUG_EN 0x8000 /* 0:Dis., 1:Enable Debug Dump Ptr. */
+#define HP100_RX_HDR 0x4000 /* 0:Dis., 1:Enable putting pkt into */
+ /* system mem. before Rx interrupt */
+#define HP100_MMAP_DIS 0x2000 /* 0:Enable, 1:Disable mem.mapping. */
+ /* MMAP_DIS must be 0 and MEM_EN */
+ /* must be 1 for memory-mapped */
+ /* mode to be enabled */
#define HP100_EE_EN 0x1000 /* 0:Disable,1:Enable EEPROM writing */
#define HP100_BM_WRITE 0x0800 /* 0:Slave, 1:Bus Master for Tx data */
#define HP100_BM_READ 0x0400 /* 0:Slave, 1:Bus Master for Rx data */
@@ -132,121 +179,236 @@
#define HP100_MEM_EN 0x0040 /* Config program set this to */
/* 0:Disable, 1:Enable mem map. */
/* See MMAP_DIS. */
-#define HP100_IO_EN 0x0020 /* 0:Disable, 1:Enable I/O transfers */
-#define HP100_BOOT_EN 0x0010 /* 0:Disable, 1:Enable boot ROM access */
-#define HP100_FAKE_INT 0x0008 /* 0:No int, 1:int */
-#define HP100_INT_EN 0x0004 /* 0:Disable, 1:Enable ints from card */
+#define HP100_IO_EN 0x0020 /* 1:Enable I/O transfers */
+#define HP100_BOOT_EN 0x0010 /* 1:Enable boot ROM access */
+#define HP100_FAKE_INT 0x0008 /* 1:int */
+#define HP100_INT_EN 0x0004 /* 1:Enable ints from card */
#define HP100_HW_RST 0x0002 /* 0:Reset, 1:Out of reset */
+ /* NIC reset on 0 to 1 transition */
/*
- * OptionMSWReg bits/masks
+ * Option Register III
+ * (Always available, OPTION_MSW, Offset 0x06)
*/
-#define HP100_PRIORITY_TX 0x0080 /* 0:Don't, 1:Do all Tx pkts as priority */
+#define HP100_PRIORITY_TX 0x0080 /* 1:Do all Tx pkts as priority */
#define HP100_EE_LOAD 0x0040 /* 1:EEPROM loading, 0 when done */
-#define HP100_ADV_NXT_PKT 0x0004 /* 1:Advance to next pkt in Rx queue, */
+#define HP100_ADV_NXT_PKT 0x0004 /* 1:Advance to next pkt in Rx queue */
/* h/w will set to 0 when done */
-#define HP100_TX_CMD 0x0002 /* 1:Tell h/w download done, h/w will set */
- /* to 0 when done */
+#define HP100_TX_CMD 0x0002 /* 1:Tell h/w download done, h/w */
+ /* will set to 0 when done */
/*
- * InterruptStatusReg/InterruptMaskReg bits/masks. These bits will 0 when a 1
- * is written to them.
+ * Interrupt Status Registers I and II
+ * (Page PERFORMANCE, IRQ_STATUS, Offset 0x08-0x09)
+ * Note: With old chips, these Registers will clear when 1 is written to them
+ * with new chips this depends on setting of CLR_ISMODE
*/
+#define HP100_RX_EARLY_INT 0x2000
+#define HP100_RX_PDA_ZERO 0x1000
+#define HP100_RX_PDL_FILL_COMPL 0x0800
#define HP100_RX_PACKET 0x0400 /* 0:No, 1:Yes pkt has been Rx */
#define HP100_RX_ERROR 0x0200 /* 0:No, 1:Yes Rx pkt had error */
+#define HP100_TX_PDA_ZERO 0x0020 /* 1 when PDA count goes to zero */
#define HP100_TX_SPACE_AVAIL 0x0010 /* 0:<8192, 1:>=8192 Tx free bytes */
#define HP100_TX_COMPLETE 0x0008 /* 0:No, 1:Yes a Tx has completed */
+#define HP100_MISC_ERROR 0x0004 /* 0:No, 1:Lan Link down or bus error*/
#define HP100_TX_ERROR 0x0002 /* 0:No, 1:Yes Tx pkt had error */
-
+
/*
- * TxMemoryFreeCountReg bits/masks.
+ * Xmit Memory Free Count
+ * (Page PERFORMANCE, TX_MEM_FREE, Offset 0x14) (Read only, 32bit)
*/
-#define HP100_AUTO_COMPARE 0x8000 /* Says at least 8k is available for Tx. */
- /* NOTE: This mask is for the upper */
- /* word of the register. */
+#define HP100_AUTO_COMPARE 0x80000000 /* Tx Space avail & pkts<255 */
+#define HP100_FREE_SPACE 0x7fffffe0 /* Tx free memory */
/*
- * IRQChannelReg bits/masks.
+ * IRQ Channel
+ * (Page HW_MAP, IRQ_CHANNEL, Offset 0x0d)
*/
#define HP100_ZERO_WAIT_EN 0x80 /* 0:No, 1:Yes asserts NOWS signal */
+#define HP100_IRQ_SCRAMBLE 0x40
+#define HP100_BOND_HP 0x20
#define HP100_LEVEL_IRQ 0x10 /* 0:Edge, 1:Level type interrupts. */
- /* Only valid on EISA cards. */
-#define HP100_IRQ_MASK 0x0F /* Isolate the IRQ bits */
+ /* (Only valid on EISA cards) */
+#define HP100_IRQMASK 0x0F /* Isolate the IRQ bits */
/*
- * SRAMReg bits/masks.
+ * SRAM Parameters
+ * (Page HW_MAP, SRAM, Offset 0x0e)
*/
#define HP100_RAM_SIZE_MASK 0xe0 /* AND to get SRAM size index */
-#define HP100_RAM_SIZE_SHIFT 0x05 /* Shift count to put index in lower bits */
+#define HP100_RAM_SIZE_SHIFT 0x05 /* Shift count(put index in lwr bits)*/
+
+/*
+ * Bus Master Register
+ * (Page HW_MAP, BM, Offset 0x0f)
+ */
+#define HP100_BM_BURST_RD 0x01 /* EISA only: 1=Use burst trans. fm system */
+ /* memory to chip (tx) */
+#define HP100_BM_BURST_WR 0x02 /* EISA only: 1=Use burst trans. fm system */
+ /* memory to chip (rx) */
+#define HP100_BM_MASTER 0x04 /* 0:Slave, 1:BM mode */
+#define HP100_BM_PAGE_CK 0x08 /* This bit should be set whenever in*/
+ /* an EISA system */
+#define HP100_BM_PCI_8CLK 0x40 /* ... cycles 8 clocks apart */
+
+
+/*
+ * Mode Control Register I
+ * (Page HW_MAP, MODECTRL1, Offset0x10)
+ */
+#define HP100_TX_DUALQ 0x10
+ /* If set and BM -> dual tx pda queues*/
+#define HP100_ISR_CLRMODE 0x02 /* If set ISR will clear all pending */
+ /* interrupts on read (etr only?) */
+#define HP100_EE_NOLOAD 0x04 /* Status whether res will be loaded */
+ /* from the eeprom */
+#define HP100_TX_CNT_FLG 0x08 /* Controls Early TX Reg Cnt Field */
+#define HP100_PDL_USE3 0x10 /* If set BM engine will read only */
+ /* first three data elements of a PDL */
+ /* on the first access. */
+#define HP100_BUSTYPE_MASK 0xe0 /* Three bit bus type info */
+
+/*
+ * Mode Control Register II
+ * (Page HW_MAP, MODECTRL2, Offset0x11)
+ */
+#define HP100_EE_MASK 0x0f /* Tell EEPROM circuit not to load */
+ /* certain resources */
+#define HP100_DIS_CANCEL 0x20 /* For tx dualq mode operation */
+#define HP100_EN_PDL_WB 0x40 /* 1: Status of PDL completion may be */
+ /* written back to system mem */
+#define HP100_EN_BUS_FAIL 0x80 /* Enables bus-fail portion of misc */
+ /* interrupt */
+
+/*
+ * PCI Configuration and Control Register I
+ * (Page HW_MAP, PCICTRL1, Offset 0x12)
+ */
+#define HP100_LO_MEM 0x01 /* 1: Mapped Mem requested below 1MB */
+#define HP100_NO_MEM 0x02 /* 1: Disables Req for sysmem to PCI */
+ /* bios */
+#define HP100_USE_ISA 0x04 /* 1: isa type decodes will occur */
+ /* simultaneously with PCI decodes */
+#define HP100_IRQ_HI_MASK 0xf0 /* pgmed by pci bios */
+#define HP100_PCI_IRQ_HI_MASK 0x78 /* Isolate 4 bits for PCI IRQ */
+
+/*
+ * PCI Configuration and Control Register II
+ * (Page HW_MAP, PCICTRL2, Offset 0x13)
+ */
+#define HP100_RD_LINE_PDL 0x01 /* 1: PCI command Memory Read Line en */
+#define HP100_RD_TX_DATA_MASK 0x06 /* choose PCI memread cmds for TX */
+#define HP100_MWI 0x08 /* 1: en. PCI memory write invalidate */
+#define HP100_ARB_MODE 0x10 /* Select PCI arbitor type */
+#define HP100_STOP_EN 0x20 /* Enables PCI state machine to issue */
+ /* pci stop if cascade not ready */
+#define HP100_IGNORE_PAR 0x40 /* 1: PCI state machine ignores parity*/
+#define HP100_PCI_RESET 0x80 /* 0->1: Reset PCI block */
/*
- * BMReg bits/masks.
+ * Early TX Configuration and Control Register
+ * (Page HW_MAP, EARLYTXCFG, Offset 0x16)
*/
-#define HP100_BM_SLAVE 0x04 /* 0:Slave, 1:BM mode */
+#define HP100_EN_EARLY_TX 0x8000 /* 1=Enable Early TX */
+#define HP100_EN_ADAPTIVE 0x4000 /* 1=Enable adaptive mode */
+#define HP100_EN_TX_UR_IRQ 0x2000 /* reserved, must be 0 */
+#define HP100_EN_LOW_TX 0x1000 /* reserved, must be 0 */
+#define HP100_ET_CNT_MASK 0x0fff /* bits 11..0: ET counters */
/*
- * EEPROMControlReg bits/masks.
+ * Early RX Configuration and Control Register
+ * (Page HW_MAP, EARLYRXCFG, Offset 0x18)
*/
-#define HP100_EEPROM_LOAD 0x0001 /* 0->1 loads the EEPROM into registers. */
- /* When it goes back to 0, load is */
- /* complete. This should take ~600us. */
+#define HP100_EN_EARLY_RX 0x80 /* 1=Enable Early RX */
+#define HP100_EN_LOW_RX 0x40 /* reserved, must be 0 */
+#define HP100_RX_TRIP_MASK 0x1f /* bits 4..0: threshold at which the
+ * early rx circuit will start the
+ * dma of received packet into system
+ * memory for BM */
/*
- * LANCntrCfg10Reg bits/masks.
- */
-#define HP100_SQU_ST 0x0100 /* 0:No, 1:Yes collision signal sent */
- /* after Tx. Only used for AUI. */
-#define HP100_MAC10_SEL 0x00c0 /* Get bits to indicate MAC */
-#define HP100_AUI_SEL 0x0020 /* Status of AUI selection */
-#define HP100_LOW_TH 0x0010 /* 0:No, 1:Yes allow better cabling */
-#define HP100_LINK_BEAT_DIS 0x0008 /* 0:Enable, 1:Disable link beat */
-#define HP100_LINK_BEAT_ST 0x0004 /* 0:No, 1:Yes link beat being Rx */
-#define HP100_R_ROL_ST 0x0002 /* 0:No, 1:Yes Rx twisted pair has been */
- /* reversed */
-#define HP100_AUI_ST 0x0001 /* 0:No, 1:Yes use AUI on TP card */
-
-/* MAC Selection, use with MAC10_SEL bits */
+ * Serial Devices Control Register
+ * (Page EEPROM_CTRL, EEPROM_CTRL, Offset 0x08)
+ */
+#define HP100_EEPROM_LOAD 0x0001 /* 0->1 loads EEPROM into registers. */
+ /* When it goes back to 0, load is */
+ /* complete. This should take ~600us.*/
+
+/*
+ * 10MB LAN Control and Configuration Register I
+ * (Page MAC_CTRL, 10_LAN_CFG_1, Offset 0x08)
+ */
+#define HP100_MAC10_SEL 0xc0 /* Get bits to indicate MAC */
+#define HP100_AUI_SEL 0x20 /* Status of AUI selection */
+#define HP100_LOW_TH 0x10 /* 0:No, 1:Yes allow better cabling */
+#define HP100_LINK_BEAT_DIS 0x08 /* 0:Enable, 1:Disable link beat */
+#define HP100_LINK_BEAT_ST 0x04 /* 0:No, 1:Yes link beat being Rx */
+#define HP100_R_ROL_ST 0x02 /* 0:No, 1:Yes Rx twisted pair has */
+ /* been reversed */
+#define HP100_AUI_ST 0x01 /* 0:No, 1:Yes use AUI on TP card */
+
+/*
+ * 10 MB LAN Control and Configuration Register II
+ * (Page MAC_CTRL, 10_LAN_CFG_2, Offset 0x09)
+ */
+#define HP100_SQU_ST 0x01 /* 0:No, 1:Yes collision signal sent */
+ /* after Tx.Only used for AUI. */
+#define HP100_FULLDUP 0x02 /* 1: LXT901 XCVR fullduplx enabled */
+#define HP100_DOT3_MAC 0x04 /* 1: DOT 3 Mac sel. unless Autosel */
+
+/*
+ * MAC Selection, use with MAC10_SEL bits
+ */
#define HP100_AUTO_SEL_10 0x0 /* Auto select */
#define HP100_XCVR_LXT901_10 0x1 /* LXT901 10BaseT transceiver */
#define HP100_XCVR_7213 0x2 /* 7213 transceiver */
#define HP100_XCVR_82503 0x3 /* 82503 transceiver */
+/*
+ * 100MB LAN Training Register
+ * (Page MAC_CTRL, VG_LAN_CFG_2, Offset 0x0b) (old, pre 802.12)
+ */
+#define HP100_FRAME_FORMAT 0x08 /* 0:802.3, 1:802.5 frames */
+#define HP100_BRIDGE 0x04 /* 0:No, 1:Yes tell hub i am a bridge */
+#define HP100_PROM_MODE 0x02 /* 0:No, 1:Yes tell hub card is */
+ /* promiscuous */
+#define HP100_REPEATER 0x01 /* 0:No, 1:Yes tell hub MAC wants to */
+ /* be a cascaded repeater */
/*
- * LANCntrCfgVGReg bits/masks.
- */
-#define HP100_FRAME_FORMAT 0x0800 /* 0:802.3, 1:802.5 frames */
-#define HP100_BRIDGE 0x0400 /* 0:No, 1:Yes tell hub it's a bridge */
-#define HP100_PROM_MODE 0x0200 /* 0:No, 1:Yes tell hub card is */
- /* promiscuous */
-#define HP100_REPEATER 0x0100 /* 0:No, 1:Yes tell hub MAC wants to be */
- /* a cascaded repeater */
-#define HP100_MAC100_SEL 0x0080 /* 0:No, 1:Yes use 100 Mbit MAC */
-#define HP100_LINK_UP_ST 0x0040 /* 0:No, 1:Yes endnode logged in */
-#define HP100_LINK_CABLE_ST 0x0020 /* 0:No, 1:Yes cable can hear tones from */
- /* hub */
-#define HP100_LOAD_ADDR 0x0010 /* 0->1 card addr will be sent to hub. */
- /* 100ms later the link status bits are */
- /* valid */
-#define HP100_LINK_CMD 0x0008 /* 0->1 link will attempt to log in. */
- /* 100ms later the link status bits are */
- /* valid */
-#define HP100_LINK_GOOD_ST 0x0002 /* 0:No, 1:Yes cable passed training */
-#define HP100_VG_RESET 0x0001 /* 0:Yes, 1:No reset the 100VG MAC */
+ * 100MB LAN Control and Configuration Register
+ * (Page MAC_CTRL, VG_LAN_CFG_1, Offset 0x0a)
+ */
+#define HP100_VG_SEL 0x80 /* 0:No, 1:Yes use 100 Mbit MAC */
+#define HP100_LINK_UP_ST 0x40 /* 0:No, 1:Yes endnode logged in */
+#define HP100_LINK_CABLE_ST 0x20 /* 0:No, 1:Yes cable can hear tones */
+ /* from hub */
+#define HP100_LOAD_ADDR 0x10 /* 0->1 card addr will be sent */
+ /* 100ms later the link status */
+ /* bits are valid */
+#define HP100_LINK_CMD 0x08 /* 0->1 link will attempt to log in. */
+ /* 100ms later the link status */
+ /* bits are valid */
+#define HP100_TRN_DONE 0x04 /* NEW ETR-Chips only: Will be reset */
+ /* after LinkUp Cmd is given and set */
+ /* when training has completed. */
+#define HP100_LINK_GOOD_ST 0x02 /* 0:No, 1:Yes cable passed training */
+#define HP100_VG_RESET 0x01 /* 0:Yes, 1:No reset the 100VG MAC */
/*
- * MACConfiguration1Reg bits/masks.
+ * MAC Configuration Register I
+ * (Page MAC_CTRL, MAC_CFG_1, Offset 0x0c)
*/
#define HP100_RX_IDLE 0x80 /* 0:Yes, 1:No currently receiving pkts */
#define HP100_TX_IDLE 0x40 /* 0:Yes, 1:No currently Txing pkts */
-#define HP100_RX_EN 0x20 /* 0:No, 1:Yes allow receiving of pkts */
-#define HP100_TX_EN 0x10 /* 0:No, 1:Yes allow transmitting of pkts */
+#define HP100_RX_EN 0x20 /* 1: allow receiving of pkts */
+#define HP100_TX_EN 0x10 /* 1: allow transmitting of pkts */
#define HP100_ACC_ERRORED 0x08 /* 0:No, 1:Yes allow Rx of errored pkts */
#define HP100_ACC_MC 0x04 /* 0:No, 1:Yes allow Rx of multicast pkts */
#define HP100_ACC_BC 0x02 /* 0:No, 1:Yes allow Rx of broadcast pkts */
-#define HP100_ACC_PHY 0x01 /* 0:No, 1:Yes allow Rx of ALL physical pkts */
-
+#define HP100_ACC_PHY 0x01 /* 0:No, 1:Yes allow Rx of ALL phys. pkts */
#define HP100_MAC1MODEMASK 0xf0 /* Hide ACC bits */
#define HP100_MAC1MODE1 0x00 /* Receive nothing, must also disable RX */
#define HP100_MAC1MODE2 0x00
@@ -254,15 +416,14 @@
#define HP100_MAC1MODE4 HP100_MAC1MODE3 | HP100_ACC_MC
#define HP100_MAC1MODE5 HP100_MAC1MODE4 /* set mc hash to all ones also */
#define HP100_MAC1MODE6 HP100_MAC1MODE5 | HP100_ACC_PHY /* Promiscuous */
-
/* Note MODE6 will receive all GOOD packets on the LAN. This really needs
a mode 7 defined to be LAN Analyzer mode, which will receive errored and
runt packets, and keep the CRC bytes. */
-
-#define HP100_MAC1MODE7 MAC1MODE6 OR ACC_ERRORED
+#define HP100_MAC1MODE7 HP100_MAC1MODE6 | HP100_ACC_ERRORED
/*
- * MACConfiguration2Reg bits/masks.
+ * MAC Configuration Register II
+ * (Page MAC_CTRL, MAC_CFG_2, Offset 0x0d)
*/
#define HP100_TR_MODE 0x80 /* 0:No, 1:Yes support Token Ring formats */
#define HP100_TX_SAME 0x40 /* 0:No, 1:Yes Tx same packet continuous */
@@ -270,9 +431,12 @@
/* transceiver */
#define HP100_LBK_MAC 0x10 /* 0:No, 1:Yes loopback through MAC */
#define HP100_CRC_I 0x08 /* 0:No, 1:Yes inhibit CRC on Tx packets */
+#define HP100_ACCNA 0x04 /* 1: For 802.5: Accept only token ring
+ * group addr that maches NA mask */
#define HP100_KEEP_CRC 0x02 /* 0:No, 1:Yes keep CRC on Rx packets. */
/* The length will reflect this. */
-
+#define HP100_ACCFA 0x01 /* 1: For 802.5: Accept only functional
+ * addrs that match FA mask (page1) */
#define HP100_MAC2MODEMASK 0x02
#define HP100_MAC2MODE1 0x00
#define HP100_MAC2MODE2 0x00
@@ -283,6 +447,65 @@
#define HP100_MAC2MODE7 KEEP_CRC
/*
+ * MAC Configuration Register III
+ * (Page MAC_CTRL, MAC_CFG_3, Offset 0x0e)
+ */
+#define HP100_PACKET_PACE 0x03 /* Packet Pacing:
+ * 00: No packet pacing
+ * 01: 8 to 16 uS delay
+ * 10: 16 to 32 uS delay
+ * 11: 32 to 64 uS delay
+ */
+#define HP100_LRF_EN 0x04 /* 1: External LAN Rcv Filter and
+ * TCP/IP Checksumming enabled. */
+#define HP100_AUTO_MODE 0x10 /* 1: AutoSelect between 10/100 */
+
+/*
+ * MAC Configuration Register IV
+ * (Page MAC_CTRL, MAC_CFG_4, Offset 0x0f)
+ */
+#define HP100_MAC_SEL_ST 0x01 /* (R): Status of external VGSEL
+ * Signal, 1=100VG, 0=10Mbit sel. */
+#define HP100_LINK_FAIL_ST 0x02 /* (R): Status of Link Fail portion
+ * of the Misc. Interrupt */
+
+/*
+ * 100 MB LAN Training Request/Allowed Registers
+ * (Page MAC_CTRL, TRAIN_REQUEST and TRAIN_ALLOW, Offset 0x14-0x16)(ETR parts only)
+ */
+#define HP100_MACRQ_REPEATER 0x0001 /* 1: MAC tells HUB it wants to be
+ * a cascaded repeater
+ * 0: ... wants to be a DTE */
+#define HP100_MACRQ_PROMSC 0x0006 /* 2 bits: Promiscious mode
+ * 00: Rcv only unicast packets
+ * specifically addr to this
+ * endnode
+ * 10: Rcv all pckts fwded by
+ * the local repeater */
+#define HP100_MACRQ_FRAMEFMT_EITHER 0x0018 /* 11: either format allowed */
+#define HP100_MACRQ_FRAMEFMT_802_3 0x0000 /* 00: 802.3 is requested */
+#define HP100_MACRQ_FRAMEFMT_802_5 0x0010 /* 10: 802.5 format is requested */
+#define HP100_CARD_MACVER 0xe000 /* R: 3 bit Cards 100VG MAC version */
+#define HP100_MALLOW_REPEATER 0x0001 /* If reset, requested access as an
+ * end node is allowed */
+#define HP100_MALLOW_PROMSC 0x0004 /* 2 bits: Promiscious mode
+ * 00: Rcv only unicast packets
+ * specifically addr to this
+ * endnode
+ * 10: Rcv all pckts fwded by
+ * the local repeater */
+#define HP100_MALLOW_FRAMEFMT 0x00e0 /* 2 bits: Frame Format
+ * 00: 802.3 format will be used
+ * 10: 802.5 format will be used */
+#define HP100_MALLOW_ACCDENIED 0x0400 /* N bit */
+#define HP100_MALLOW_CONFIGURE 0x0f00 /* C bit */
+#define HP100_MALLOW_DUPADDR 0x1000 /* D bit */
+#define HP100_HUB_MACVER 0xe000 /* R: 3 bit 802.12 MAC/RMAC training */
+ /* protocol of repeater */
+
+/* ****************************************************************************** */
+
+/*
* Set/Reset bits
*/
#define HP100_SET_HB 0x0100 /* 0:Set fields to 0 whose mask is 1 */
@@ -297,20 +520,45 @@
#define HP100_LAN_10 10 /* lan_type value for 10BaseT */
#define HP100_LAN_ERR (-1) /* lan_type value for link down */
-/*
- * Receive Header Definition.
+#define TRUE 1
+#define FALSE 0
+
+
+/*
+ * Bus Master Data Structures ----------------------------------------------
*/
-struct hp100_rx_header {
- u_short rx_length; /* Pkt length is bits 12:0 */
- u_short rx_status; /* status of the packet */
-};
+#define MAX_RX_PDL 30 /* Card limit = 31 */
+#define MAX_RX_FRAG 2 /* Dont need more... */
+#define MAX_TX_PDL 29
+#define MAX_TX_FRAG 2 /* Limit = 31 */
+
+/* Define total PDL area size in bytes (should be 4096) */
+/* This is the size of kernel (dma) memory that will be allocated. */
+#define MAX_RINGSIZE ((MAX_RX_FRAG*8+4+4)*MAX_RX_PDL+(MAX_TX_FRAG*8+4+4)*MAX_TX_PDL)+16
+
+/* Ethernet Packet Sizes */
+#define MIN_ETHER_SIZE 60
+#define MAX_ETHER_SIZE 1514 /* Needed for preallocation of */
+ /* skb buffer when busmastering */
+
+/* Tx or Rx Ring Entry */
+typedef struct hp100_ring {
+ u_int *pdl; /* Address of PDLs PDH, dword before
+ * this address is used for rx hdr */
+ u_int pdl_paddr; /* Physical address of PDL */
+ struct sk_buff *skb;
+ struct hp100_ring *next;
+} hp100_ring_t;
+
+
+
+/* Mask for Header Descriptor */
+#define HP100_PKT_LEN_MASK 0x1FFF /* AND with RxLength to get length */
-#define HP100_PKT_LEN_MASK 0x1FFF /* AND with RxLength to get length bits */
/* Receive Packet Status. Note, the error bits are only valid if ACC_ERRORED
bit in the MAC Configuration Register 1 is set. */
-
#define HP100_RX_PRI 0x8000 /* 0:No, 1:Yes packet is priority */
#define HP100_SDF_ERR 0x4000 /* 0:No, 1:Yes start of frame error */
#define HP100_SKEW_ERR 0x2000 /* 0:No, 1:Yes skew out of range */
@@ -368,7 +616,11 @@ struct hp100_rx_header {
outw( HP100_MMAP_DIS | HP100_RESET_HB, ioaddr + HP100_REG_OPTION_LSW )
#define hp100_mem_map_disable() \
outw( HP100_MMAP_DIS | HP100_SET_HB, ioaddr + HP100_REG_OPTION_LSW )
-#define hp100_reset_card() \
- outw( HP100_HW_RST | HP100_RESET_LB, ioaddr + HP100_REG_OPTION_LSW )
-#define hp100_unreset_card() \
- outw( HP100_HW_RST | HP100_SET_LB, ioaddr + HP100_REG_OPTION_LSW )
+
+
+/*
+ * Local variables:
+ * c-indent-level: 2
+ * tab-width: 8
+ * End:
+*/
diff --git a/drivers/net/ibmtr.c b/drivers/net/ibmtr.c
index faedd45fa..e0d71b202 100644
--- a/drivers/net/ibmtr.c
+++ b/drivers/net/ibmtr.c
@@ -84,7 +84,7 @@
/* version and credits */
static char *version =
"ibmtr.c: v1.3.57 8/ 7/94 Peter De Schrijver and Mark Swanson\n"
-" v2.1.29 3/15/97 Paul Norton <pnorton@cts.com>\n";
+" v2.1.35 5/ 1/97 Paul Norton <pnorton@cts.com>\n";
static char pcchannelid[] = {
0x05, 0x00, 0x04, 0x09,
@@ -1013,14 +1013,15 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
} /* ARB response */
if (status & SSB_RESP_INT) { /* SSB response */
-
+ unsigned char retcode;
switch (readb(ti->ssb)) { /* SSB command check */
-
+
case XMIT_DIR_FRAME:
case XMIT_UI_FRAME:
- if (readb(ti->ssb+2)) /* checks ret_code */
+ retcode = readb(ti->ssb+2);
+ if (retcode && (retcode != 0x22)) /* checks ret_code */
DPRINTK("xmit ret_code: %02X xmit error code: %02X\n",
- (int)readb(ti->ssb+2), (int)readb(ti->ssb+6));
+ (int)retcode, (int)readb(ti->ssb+6));
else ti->tr_stats.tx_packets++;
break;
@@ -1321,12 +1322,12 @@ static void tr_rx(struct device *dev)
__u32 rbuffer, rbufdata;
__u32 llc;
unsigned char *data;
- unsigned int rbuffer_len, lan_hdr_len, hdr_len;
- unsigned int arb_frame_len;
+ unsigned int rbuffer_len, lan_hdr_len, hdr_len, ip_len, length;
struct sk_buff *skb;
unsigned int skb_size = 0;
int is8022 = 0;
unsigned int chksum = 0;
+ struct iphdr *iph;
rbuffer=(ti->sram
+ntohs(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr))))+2;
@@ -1400,8 +1401,8 @@ static void tr_rx(struct device *dev)
}
#endif
- arb_frame_len=ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len)));
- skb_size = arb_frame_len-lan_hdr_len+sizeof(struct trh_hdr);
+ length = ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len)));
+ skb_size = length-lan_hdr_len+sizeof(struct trh_hdr);
if (is8022) {
skb_size += sizeof(struct trllc);
}
@@ -1429,30 +1430,42 @@ static void tr_rx(struct device *dev)
rbuffer_len=ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)))-lan_hdr_len;
if (is8022) {
- /* create whitewashed LLC header in skb buffer (why not the real one?) */
+ /* create whitewashed LLC header in sk buffer */
struct trllc *local_llc = (struct trllc *)data;
memset(local_llc, 0, sizeof(*local_llc));
local_llc->ethertype = htons(ETH_P_TR_802_2);
hdr_len = sizeof(struct trllc);
+ /* copy the real LLC header to the sk buffer */
+ data += hdr_len;
+ memcpy_fromio(data, rbuffer+offsetof(struct rec_buf, data)+lan_hdr_len,hdr_len);
} else {
/* Copy the LLC header and the IPv4 header */
hdr_len = sizeof(struct trllc) + sizeof(struct iphdr);
memcpy_fromio(data, rbuffer+offsetof(struct rec_buf, data)+lan_hdr_len,hdr_len);
+
+ /* Watch for padded packets and bogons */
+ iph=(struct iphdr*)(data+sizeof(struct trllc));
+ ip_len = ntohs(iph->tot_len) - sizeof(struct iphdr);
+ length -= lan_hdr_len + hdr_len;
+ if ((ip_len <= length) && (ip_len > 7))
+ length = ip_len;
}
data += hdr_len;
- lan_hdr_len += hdr_len;
rbuffer_len -= hdr_len;
- rbufdata = rbuffer + offsetof(struct rec_buf,data) + lan_hdr_len;
+ rbufdata = rbuffer + offsetof(struct rec_buf,data) + lan_hdr_len + hdr_len;
/* Copy the payload... */
for (;;) {
if (is8022)
memcpy_fromio(data, rbufdata, rbuffer_len);
else
- chksum = csum_partial_copy(bus_to_virt(rbufdata), data, rbuffer_len, chksum);
+ chksum = csum_partial_copy(bus_to_virt(rbufdata), data,
+ length < rbuffer_len ? length : rbuffer_len,
+ chksum);
rbuffer = ntohs(readw(rbuffer));
if (!rbuffer)
break;
+ length -= rbuffer_len;
data += rbuffer_len;
rbuffer += ti->sram;
rbuffer_len = ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)));
@@ -1495,7 +1508,7 @@ static int tok_send_packet(struct sk_buff *skb, struct device *dev)
return 0;
}
- if (set_bit(0,(void *)&dev->tbusy)!=0)
+ if (test_and_set_bit(0,(void *)&dev->tbusy)!=0)
DPRINTK("Transmitter access conflict\n");
else {
/* Save skb; we'll need it when the adapter asks for the data */
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index c1aa556d6..bf4061b05 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -858,12 +858,12 @@ static int lance_start_xmit(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
- if (set_bit(0, (void*)&lp->lock) != 0) {
+ if (test_and_set_bit(0, (void*)&lp->lock) != 0) {
if (lance_debug > 0)
printk("%s: tx queue lock!.\n", dev->name);
/* don't clear dev->tbusy flag. */
diff --git a/drivers/net/ltpc.c b/drivers/net/ltpc.c
index 8a4fae560..1da2ee64f 100644
--- a/drivers/net/ltpc.c
+++ b/drivers/net/ltpc.c
@@ -1259,7 +1259,7 @@ void cleanup_module(void)
if(debug&DEBUG_VERBOSE) printk("waiting\n");
/* if it's in process, wait a bit for it to finish */
timeout = jiffies+HZ;
- add_timer(&ltpc_timer)
+ add_timer(&ltpc_timer);
while(del_timer(&ltpc_timer) && (timeout > jiffies))
{
add_timer(&ltpc_timer);
diff --git a/drivers/net/mkiss.c b/drivers/net/mkiss.c
index 6f772fd68..13ebbd9b4 100644
--- a/drivers/net/mkiss.c
+++ b/drivers/net/mkiss.c
@@ -109,7 +109,7 @@ static inline struct ax_disp *ax_alloc(void)
break;
/* Not in use ? */
- if (!set_bit(AXF_INUSE, &axp->ctrl.flags))
+ if (!test_and_set_bit(AXF_INUSE, &axp->ctrl.flags))
break;
}
@@ -165,7 +165,7 @@ static inline void ax_free(struct ax_disp *ax)
if (ax->xbuff)
kfree(ax->xbuff);
ax->xbuff = NULL;
- if (!clear_bit(AXF_INUSE, &ax->flags))
+ if (!test_and_clear_bit(AXF_INUSE, &ax->flags))
printk(KERN_ERR "%s: ax_free for already free unit.\n", ax->dev->name);
}
@@ -244,7 +244,7 @@ static void ax_changedmtu(struct ax_disp *ax)
/* Set the "sending" flag. This must be atomic, hence the ASM. */
static inline void ax_lock(struct ax_disp *ax)
{
- if (set_bit(0, (void *)&ax->dev->tbusy))
+ if (test_and_set_bit(0, (void *)&ax->dev->tbusy))
printk(KERN_ERR "%s: trying to lock already locked device!\n", ax->dev->name);
}
@@ -252,7 +252,7 @@ static inline void ax_lock(struct ax_disp *ax)
/* Clear the "sending" flag. This must be atomic, hence the ASM. */
static inline void ax_unlock(struct ax_disp *ax)
{
- if (!clear_bit(0, (void *)&ax->dev->tbusy))
+ if (!test_and_clear_bit(0, (void *)&ax->dev->tbusy))
printk(KERN_ERR "%s: trying to unlock already unlocked device!\n", ax->dev->name);
}
@@ -551,7 +551,7 @@ static void ax25_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch
/* Read the characters out of the buffer */
while (count--) {
if (fp != NULL && *fp++) {
- if (!set_bit(AXF_ERROR, &ax->flags))
+ if (!test_and_set_bit(AXF_ERROR, &ax->flags))
ax->rx_errors++;
cp++;
continue;
@@ -709,7 +709,7 @@ static void kiss_unesc(struct ax_disp *ax, unsigned char s)
if (test_bit(AXF_KEEPTEST, &ax->flags))
clear_bit(AXF_KEEPTEST, &ax->flags);
- if (!clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2))
+ if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2))
ax_bump(ax);
clear_bit(AXF_ESCAPE, &ax->flags);
@@ -720,11 +720,11 @@ static void kiss_unesc(struct ax_disp *ax, unsigned char s)
set_bit(AXF_ESCAPE, &ax->flags);
return;
case ESC_ESC:
- if (clear_bit(AXF_ESCAPE, &ax->flags))
+ if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
s = ESC;
break;
case ESC_END:
- if (clear_bit(AXF_ESCAPE, &ax->flags))
+ if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
s = END;
break;
}
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 3d7a2587a..4ae7aa069 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -584,7 +584,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct device *dev)
return 0;
}
- if(set_bit(0, (void *) &dev->tbusy) != 0) {
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
DTX(("tbusy, maybe a race? returning 1\n"));
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 746037adf..0935f4f0b 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -1171,12 +1171,12 @@ static int ni52_send_packet(struct sk_buff *skb, struct device *dev)
return 0;
}
- if (set_bit(0, (void*)&dev->tbusy)) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy)) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
#if(NUM_XMIT_BUFFS > 1)
- else if(set_bit(0,(void *) &p->lock)) {
+ else if(test_and_set_bit(0,(void *) &p->lock)) {
printk("%s: Queue was locked\n",dev->name);
return 1;
}
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index 07a946d3b..a008a3ea7 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -804,7 +804,7 @@ static void ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs)
return;
}
- if(set_bit(0,(int *) &dev->interrupt)) {
+ if(test_and_set_bit(0,(int *) &dev->interrupt)) {
printk("ni65: oops .. interrupt while proceeding interrupt\n");
return;
}
@@ -1087,11 +1087,11 @@ static int ni65_send_packet(struct sk_buff *skb, struct device *dev)
dev->trans_start = jiffies;
}
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
return 1;
}
- if (set_bit(0, (void*)&p->lock)) {
+ if (test_and_set_bit(0, (void*)&p->lock)) {
printk(KERN_ERR "%s: Queue was locked.\n", dev->name);
return 1;
}
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 3f34e690c..d10663ff5 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -613,12 +613,12 @@ pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
- if (set_bit(0, (void*)&lp->lock) != 0) {
+ if (test_and_set_bit(0, (void*)&lp->lock) != 0) {
if (pcnet32_debug > 0)
printk("%s: tx queue lock!.\n", dev->name);
/* don't clear dev->tbusy flag. */
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 25c33ab1a..f06a66afc 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -910,7 +910,7 @@ plip_tx_packet(struct sk_buff *skb, struct device *dev)
return 0;
}
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c
index a1dbb5020..e3615534d 100644
--- a/drivers/net/ppp.c
+++ b/drivers/net/ppp.c
@@ -1291,7 +1291,7 @@ rcv_proto_unknown (struct ppp *ppp, __u16 proto,
* The total length includes the protocol data.
* Lock the user information buffer.
*/
- if (set_bit (0, &ppp->ubuf->locked)) {
+ if (test_and_set_bit (0, &ppp->ubuf->locked)) {
if (ppp->flags & SC_DEBUG)
printk (KERN_DEBUG
"ppp_us_queue: can't get lock\n");
@@ -1698,7 +1698,7 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
return 0;
- if (set_bit (0, &ppp->ubuf->locked) != 0) {
+ if (test_and_set_bit (0, &ppp->ubuf->locked) != 0) {
if (ppp->flags & SC_DEBUG)
printk (KERN_DEBUG
"ppp_tty_read: sleeping(ubuf)\n");
@@ -2584,7 +2584,7 @@ ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait)
poll_wait(&ppp->write_wait, wait);
/* Must lock the user buffer area while checking. */
- if(set_bit(0, &ppp->ubuf->locked) == 0) {
+ if(test_and_set_bit(0, &ppp->ubuf->locked) == 0) {
if(ppp->ubuf->head != ppp->ubuf->tail)
mask |= POLLIN | POLLRDNORM;
clear_bit(0, &ppp->ubuf->locked);
@@ -3130,7 +3130,7 @@ ppp_find (int pid_value)
while (ctl) {
ppp = ctl2ppp (ctl);
- if (!set_bit(0, &ppp->inuse)) {
+ if (!test_and_set_bit(0, &ppp->inuse)) {
if (ppp->sc_xfer == pid_value) {
ppp->sc_xfer = 0;
return (ppp);
@@ -3160,7 +3160,7 @@ ppp_alloc (void)
while (ctl) {
ppp = ctl2ppp (ctl);
- if (!set_bit(0, &ppp->inuse))
+ if (!test_and_set_bit(0, &ppp->inuse))
return (ppp);
ctl = ctl->next;
if (++if_num == max_dev)
diff --git a/drivers/net/sdla.c b/drivers/net/sdla.c
index f2762eef1..feaeef4cc 100644
--- a/drivers/net/sdla.c
+++ b/drivers/net/sdla.c
@@ -657,7 +657,7 @@ static int sdla_transmit(struct sk_buff *skb, struct device *dev)
if (skb == NULL)
return(0);
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
else
{
diff --git a/drivers/net/sdla_fr.c b/drivers/net/sdla_fr.c
index 79a493c2c..d2dc0eb90 100644
--- a/drivers/net/sdla_fr.c
+++ b/drivers/net/sdla_fr.c
@@ -440,7 +440,7 @@ static int if_open (struct device* dev)
if (dev->start)
return -EBUSY /* only one open is allowed */
;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
;
if (!card->open_cnt)
@@ -489,7 +489,7 @@ static int if_close (struct device* dev)
fr_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
;
dev->start = 0;
@@ -574,7 +574,7 @@ static int if_send (struct sk_buff* skb, struct device* dev)
sdla_t* card = chan->card;
int retry = 0;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
{
#ifdef _DEBUG_
printk(KERN_INFO "%s: if_send() hit critical section!\n",
@@ -584,7 +584,7 @@ static int if_send (struct sk_buff* skb, struct device* dev)
return 1;
}
- if (set_bit(0, (void*)&dev->tbusy))
+ if (test_and_set_bit(0, (void*)&dev->tbusy))
{
#ifdef _DEBUG_
printk(KERN_INFO "%s: Tx collision on interface %s!\n",
diff --git a/drivers/net/sdla_ppp.c b/drivers/net/sdla_ppp.c
index c6b1ce945..c5c5ecc55 100644
--- a/drivers/net/sdla_ppp.c
+++ b/drivers/net/sdla_ppp.c
@@ -286,7 +286,7 @@ static int if_open (struct device* dev)
if (dev->start)
return -EBUSY /* only one open is allowed */
;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
;
if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card))
@@ -365,7 +365,7 @@ static int if_close (struct device* dev)
{
sdla_t* card = dev->priv;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
;
dev->start = 0;
@@ -441,7 +441,7 @@ static int if_send (struct sk_buff* skb, struct device* dev)
sdla_t* card = dev->priv;
int retry = 0;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
{
#ifdef _DEBUG_
printk(KERN_INFO "%s: if_send() hit critical section!\n",
@@ -451,7 +451,7 @@ static int if_send (struct sk_buff* skb, struct device* dev)
return 1;
}
- if (set_bit(0, (void*)&dev->tbusy))
+ if (test_and_set_bit(0, (void*)&dev->tbusy))
{
#ifdef _DEBUG_
printk(KERN_INFO "%s: Tx collision on interface %s!\n",
diff --git a/drivers/net/sdla_x25.c b/drivers/net/sdla_x25.c
index f6f540709..3296c2819 100644
--- a/drivers/net/sdla_x25.c
+++ b/drivers/net/sdla_x25.c
@@ -476,7 +476,7 @@ static int if_open (struct device* dev)
if (dev->start)
return -EBUSY /* only one open is allowed */
;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
;
@@ -503,7 +503,7 @@ static int if_close (struct device* dev)
x25_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
;
dev->start = 0;
@@ -590,7 +590,7 @@ static int if_send (struct sk_buff* skb, struct device* dev)
sdla_t* card = chan->card;
int retry = 0, queued = 0;
- if (set_bit(0, (void*)&card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
{
#ifdef _DEBUG_
printk(KERN_INFO "%s: if_send() hit critical section!\n",
@@ -600,7 +600,7 @@ static int if_send (struct sk_buff* skb, struct device* dev)
return 1;
}
- if (set_bit(0, (void*)&dev->tbusy))
+ if (test_and_set_bit(0, (void*)&dev->tbusy))
{
#ifdef _DEBUG_
printk(KERN_INFO "%s: Tx collision on interface %s!\n",
diff --git a/drivers/net/sdlamain.c b/drivers/net/sdlamain.c
index 2ff8a4605..75d7df944 100644
--- a/drivers/net/sdlamain.c
+++ b/drivers/net/sdlamain.c
@@ -332,7 +332,7 @@ static int shutdown (wan_device_t* wandev)
if (wandev->state == WAN_UNCONFIGURED)
return 0
;
- if (set_bit(0, (void*)&wandev->critical))
+ if (test_and_set_bit(0, (void*)&wandev->critical))
return -EAGAIN
;
card = wandev->private;
@@ -364,7 +364,7 @@ static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg)
if (wandev->state == WAN_UNCONFIGURED)
return -ENODEV
;
- if (set_bit(0, (void*)&wandev->critical))
+ if (test_and_set_bit(0, (void*)&wandev->critical))
return -EAGAIN
;
switch (cmd)
@@ -514,7 +514,7 @@ STATIC void sdla_poll (void* data)
sdla_t* card = &card_array[i];
if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll &&
- !set_bit(0, (void*)&card->wandev.critical))
+ !test_and_set_bit(0, (void*)&card->wandev.critical))
{
card->poll(card);
card->wandev.critical = 0;
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index 397228647..1a41960c4 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -392,7 +392,7 @@ seeq8005_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 3022e8a0b..bf85e014a 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -519,7 +519,7 @@ static inline int verify_tx(struct sgiseeq_private *sp,
return -1;
}
/* Are we getting in someone else's way? */
- if(set_bit(0, (void *) &dev->tbusy) != 0) {
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return -1;
}
diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c
index 1421356e3..51e8fe8ba 100644
--- a/drivers/net/sk_g16.c
+++ b/drivers/net/sk_g16.c
@@ -68,6 +68,7 @@ static const char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $";
#include <asm/io.h>
#include <asm/bitops.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -532,7 +533,7 @@ void SK_print_ram(struct device *dev);
* (detachable devices only).
*/
-int SK_init(struct device *dev)
+__initfunc(int SK_init(struct device *dev))
{
int ioaddr = 0; /* I/O port address used for POS regs */
int *port, ports[] = SK_IO_PORTS; /* SK_G16 supported ports */
@@ -616,7 +617,7 @@ int SK_init(struct device *dev)
* 94/06/30 pwe SK_ADDR now checked and at the correct place
-*/
-int SK_probe(struct device *dev, short ioaddr)
+__initfunc(int SK_probe(struct device *dev, short ioaddr))
{
int i,j; /* Counters */
int sk_addr_flag = 0; /* SK ADDR correct? 1 - no, 0 - yes */
@@ -1210,7 +1211,7 @@ static int SK_send_packet(struct sk_buff *skb, struct device *dev)
* This means check if we are already in.
*/
- if (set_bit(0, (void *) &dev->tbusy) != 0) /* dev->tbusy already set ? */
+ if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) /* dev->tbusy already set ? */
{
printk("%s: Transmitter access conflict.\n", dev->name);
}
@@ -1740,7 +1741,7 @@ static void set_multicast_list(struct device *dev)
* YY/MM/DD uid Description
-*/
-unsigned int SK_rom_addr(void)
+__initfunc(unsigned int SK_rom_addr(void))
{
int i,j;
int rom_found = 0;
diff --git a/drivers/net/skeleton.c b/drivers/net/skeleton.c
index 115d419c9..0df5feaae 100644
--- a/drivers/net/skeleton.c
+++ b/drivers/net/skeleton.c
@@ -56,6 +56,7 @@ static const char *version =
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -70,7 +71,7 @@ static const char* cardname = "netcard";
/* First, a few definitions that the brave might change. */
/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int netcard_portlist[] =
+static unsigned int netcard_portlist[] __initdata =
{ 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0};
/* use 0 for production, 1 for verification, >2 for debug */
@@ -126,8 +127,8 @@ extern void chipset_init(struct device *dev, int startp);
struct netdev_entry netcard_drv =
{cardname, netcard_probe1, NETCARD_IO_EXTENT, netcard_portlist};
#else
-int
-netcard_probe(struct device *dev)
+__initfunc(int
+netcard_probe(struct device *dev))
{
int i;
int base_addr = dev ? dev->base_addr : 0;
@@ -154,7 +155,7 @@ netcard_probe(struct device *dev)
* probes on the ISA bus. A good device probes avoids doing writes, and
* verifies that the correct device exists and functions.
*/
-static int netcard_probe1(struct device *dev, int ioaddr)
+__initfunc(static int netcard_probe1(struct device *dev, int ioaddr))
{
static unsigned version_printed = 0;
int i;
@@ -365,7 +366,7 @@ static int net_send_packet(struct sk_buff *skb, struct device *dev)
* Block a timer-based transmit from overlapping. This could better be
* done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
*/
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index f091e38a4..057d3c9d2 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -123,7 +123,7 @@ sl_alloc(void)
if (slp == NULL)
break;
/* Not in use ? */
- if (!set_bit(SLF_INUSE, &slp->ctrl.flags))
+ if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags))
break;
}
/* SLP is set.. */
@@ -207,7 +207,7 @@ sl_free(struct slip *sl)
sl->slcomp = NULL;
#endif
- if (!clear_bit(SLF_INUSE, &sl->flags)) {
+ if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {
printk("%s: sl_free for already free unit.\n", sl->dev->name);
}
}
@@ -317,7 +317,7 @@ static void sl_changedmtu(struct slip *sl)
static inline void
sl_lock(struct slip *sl)
{
- if (set_bit(0, (void *) &sl->dev->tbusy)) {
+ if (test_and_set_bit(0, (void *) &sl->dev->tbusy)) {
printk("%s: trying to lock already locked device!\n", sl->dev->name);
}
}
@@ -327,7 +327,7 @@ sl_lock(struct slip *sl)
static inline void
sl_unlock(struct slip *sl)
{
- if (!clear_bit(0, (void *)&sl->dev->tbusy)) {
+ if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy)) {
printk("%s: trying to unlock already unlocked device!\n", sl->dev->name);
}
}
@@ -661,7 +661,7 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch
/* Read the characters out of the buffer */
while (count--) {
if (fp && *fp++) {
- if (!set_bit(SLF_ERROR, &sl->flags)) {
+ if (!test_and_set_bit(SLF_ERROR, &sl->flags)) {
sl->rx_errors++;
}
cp++;
@@ -843,7 +843,7 @@ static void slip_unesc(struct slip *sl, unsigned char s)
if (test_bit(SLF_KEEPTEST, &sl->flags))
clear_bit(SLF_KEEPTEST, &sl->flags);
- if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) {
+ if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) {
sl_bump(sl);
}
clear_bit(SLF_ESCAPE, &sl->flags);
@@ -854,12 +854,12 @@ static void slip_unesc(struct slip *sl, unsigned char s)
set_bit(SLF_ESCAPE, &sl->flags);
return;
case ESC_ESC:
- if (clear_bit(SLF_ESCAPE, &sl->flags)) {
+ if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) {
s = ESC;
}
break;
case ESC_END:
- if (clear_bit(SLF_ESCAPE, &sl->flags)) {
+ if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) {
s = END;
}
break;
@@ -928,7 +928,7 @@ slip_unesc6(struct slip *sl, unsigned char s)
if (test_bit(SLF_KEEPTEST, &sl->flags))
clear_bit(SLF_KEEPTEST, &sl->flags);
- if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) {
+ if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) {
sl_bump(sl);
}
sl->rcount = 0;
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 5b3e9b73c..55f04121f 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -1245,7 +1245,7 @@ static int smc_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk(KERN_WARNING CARDNAME": Transmitter access conflict.\n");
dev_kfree_skb (skb, FREE_WRITE);
} else {
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
index dfa5b272c..c42450a44 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -28,6 +28,7 @@ static const char *version =
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
+#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/malloc.h>
@@ -127,7 +128,7 @@ static int sonic_init(struct device *dev);
* Probe for a SONIC ethernet controller on a Mips Jazz board.
* Actually probing is superfluous but we're paranoid.
*/
-int sonic_probe(struct device *dev)
+__initfunc(int sonic_probe(struct device *dev))
{
unsigned int base_addr = dev ? dev->base_addr : 0;
int i;
@@ -152,8 +153,8 @@ int sonic_probe(struct device *dev)
return -ENODEV;
}
-static int
-sonic_probe1(struct device *dev, unsigned int base_addr, unsigned int irq)
+__initfunc(static int sonic_probe1(struct device *dev,
+ unsigned int base_addr, unsigned int irq))
{
static unsigned version_printed = 0;
unsigned int silicon_revision;
@@ -403,7 +404,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct device *dev)
* Block a timer-based transmit from overlapping. This could better be
* done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
*/
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
@@ -719,8 +720,7 @@ sonic_multicast_list(struct device *dev)
/*
* Initialize the SONIC ethernet controller.
*/
-static int
-sonic_init(struct device *dev)
+static int sonic_init(struct device *dev)
{
unsigned int base_addr = dev->base_addr;
unsigned int cmd;
diff --git a/drivers/net/soundmodem/sm.c b/drivers/net/soundmodem/sm.c
index 777b5142f..7d57dd692 100644
--- a/drivers/net/soundmodem/sm.c
+++ b/drivers/net/soundmodem/sm.c
@@ -56,6 +56,7 @@
#include <asm/bitops.h>
#include <linux/delay.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include "sm.h"
/* --------------------------------------------------------------------- */
@@ -662,10 +663,7 @@ static int sm_ioctl(struct device *dev, struct ifreq *ifr,
/* --------------------------------------------------------------------- */
-#ifdef MODULE
-static
-#endif /* MODULE */
-int sm_init(void)
+__initfunc(int sm_init(void))
{
int i, j, found = 0;
char set_hw = 1;
@@ -800,7 +798,7 @@ void cleanup_module(void)
* modem: afsk1200, fsk9600
*/
-void sm_setup(char *str, int *ints)
+__initfunc(void sm_setup(char *str, int *ints))
{
int i;
diff --git a/drivers/net/strip.c b/drivers/net/strip.c
index 862a13370..32c02b4f0 100644
--- a/drivers/net/strip.c
+++ b/drivers/net/strip.c
@@ -891,7 +891,7 @@ static void strip_unlock(struct strip *strip_info)
*/
strip_info->idle_timer.expires = jiffies + HZ;
add_timer(&strip_info->idle_timer);
- if (!clear_bit(0, (void *)&strip_info->dev.tbusy))
+ if (!test_and_clear_bit(0, (void *)&strip_info->dev.tbusy))
printk(KERN_ERR "%s: trying to unlock already unlocked device!\n",
strip_info->dev.name);
}
@@ -1745,7 +1745,7 @@ static int strip_xmit(struct sk_buff *skb, struct device *dev)
printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name);
return(1);
}
- if (set_bit(0, (void *) &strip_info->dev.tbusy)) return(1);
+ if (test_and_set_bit(0, (void *) &strip_info->dev.tbusy)) return(1);
del_timer(&strip_info->idle_timer);
/* See if someone has been ifconfigging */
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 66e3b0b68..7299b0f4b 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -1673,6 +1673,7 @@ static inline void happy_meal_rx(struct happy_meal *hp, struct device *dev,
netif_rx(skb);
hp->net_stats.rx_packets++;
+ hp->net_stats.rx_bytes+=len;
next:
elem = NEXT_RX(elem);
this = &rxbase[elem];
@@ -1729,6 +1730,7 @@ static inline void sun4c_happy_meal_rx(struct happy_meal *hp, struct device *dev
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
hp->net_stats.rx_packets++;
+ hp->net_stats.rx_bytes+=len;
}
}
/* Return the buffer to the Happy Meal. */
@@ -1898,7 +1900,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
}
}
- if(set_bit(0, (void *) &dev->tbusy) != 0) {
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
printk("happy meal: Transmitter access conflict.\n");
return 1;
}
@@ -1955,7 +1957,7 @@ static int sun4c_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
return 0;
}
- if(set_bit(0, (void *) &dev->tbusy) != 0) {
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
printk("happy meal: Transmitter access conflict.\n");
return 1;
}
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 0485aa2d1..4e7325016 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.62 1997/04/16 10:27:25 jj Exp $
+/* $Id: sunlance.c,v 1.64 1997/05/14 20:46:40 davem Exp $
* lance.c: Linux/Sparc/Lance driver
*
* Written 1995, 1996 by Miguel de Icaza
@@ -673,8 +673,7 @@ static int lance_open (struct device *dev)
/* On the 4m, setup the ledma to provide the upper bits for buffers */
if (lp->ledma)
- lp->ledma->regs->dma_test = ((unsigned long) lp->init_block)
- & 0xff000000;
+ lp->ledma->regs->dma_test = ((__u32) lp->init_block_dvma) & 0xff000000;
lance_init_ring (dev);
load_csrs (lp);
@@ -758,8 +757,7 @@ static inline int lance_reset (struct device *dev)
lp->ledma->regs->cond_reg |= DMA_RST_ENET;
udelay (200);
lp->ledma->regs->cond_reg &= ~DMA_RST_ENET;
- lp->ledma->regs->dma_test = ((unsigned long) lp->init_block)
- & 0xff000000;
+ lp->ledma->regs->dma_test = ((__u32) lp->init_block_dvma) & 0xff000000;
}
lance_init_ring (dev);
load_csrs (lp);
@@ -800,7 +798,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
}
/* Block a timer-based transmit from overlapping. */
- if (set_bit (0, (void *) &dev->tbusy) != 0) {
+ if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) {
printk ("Transmitter access conflict.\n");
return -1;
}
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index c987c5e9f..18e758c80 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -720,7 +720,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct device *dev)
if(dev->tbusy)
return 1;
- if(set_bit(0, (void *) &dev->tbusy) != 0) {
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
@@ -762,7 +762,7 @@ static int sun4c_qe_start_xmit(struct sk_buff *skb, struct device *dev)
if(dev->tbusy)
return 1;
- if(set_bit(0, (void *) &dev->tbusy) != 0) {
+ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c
index fe4cf2662..f87beba00 100644
--- a/drivers/net/tulip.c
+++ b/drivers/net/tulip.c
@@ -863,7 +863,7 @@ tulip_start_xmit(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
If this ever occurs the queue layer is doing something evil! */
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
diff --git a/drivers/net/wavelan.c b/drivers/net/wavelan.c
index 0b18de7d9..336283df0 100644
--- a/drivers/net/wavelan.c
+++ b/drivers/net/wavelan.c
@@ -64,8 +64,8 @@ wv_irq_to_psa(int irq)
/*
* Translate PSA irq parameter to irq number
*/
-static int
-wv_psa_to_irq(u_char irqval)
+__initfunc(static int
+wv_psa_to_irq(u_char irqval))
{
int irq;
@@ -895,7 +895,7 @@ wv_82586_reconfig(device * dev)
net_local * lp = (net_local *)dev->priv;
/* Check if we can do it now ! */
- if(!(dev->start) || (set_bit(0, (void *)&dev->tbusy) != 0))
+ if(!(dev->start) || (test_and_set_bit(0, (void *)&dev->tbusy) != 0))
{
lp->reconfig_82586 = 1;
#ifdef DEBUG_CONFIG_INFO
@@ -2799,7 +2799,7 @@ wavelan_packet_xmit(struct sk_buff * skb,
* Block a timer-based transmit from overlapping.
* In other words, prevent reentering this routine.
*/
- if(set_bit(0, (void *)&dev->tbusy) != 0)
+ if(test_and_set_bit(0, (void *)&dev->tbusy) != 0)
#ifdef DEBUG_TX_ERROR
printk(KERN_INFO "%s: Transmitter access conflict.\n", dev->name);
#endif
@@ -3999,8 +3999,8 @@ wavelan_close(device * dev)
* device structure
* (called by wavelan_probe() & via init_module())
*/
-static int
-wavelan_config(device * dev)
+__initfunc(static int
+wavelan_config(device * dev))
{
u_long ioaddr = dev->base_addr;
u_char irq_mask;
@@ -4112,11 +4112,9 @@ wavelan_config(device * dev)
* the initial value of dev->base_addr.
* We follow the example in drivers/net/ne.c.)
* (called in "Space.c")
- * As this function is called outside the wavelan module, it should be
- * declared extern, but it seem to cause troubles...
*/
-/* extern */ int
-wavelan_probe(device * dev)
+__initfunc(int
+wavelan_probe(device * dev))
{
short base_addr;
mac_addr mac; /* Mac address (check wavelan existence) */
diff --git a/drivers/net/wavelan.p.h b/drivers/net/wavelan.p.h
index 338ef1f6f..18320dcc4 100644
--- a/drivers/net/wavelan.p.h
+++ b/drivers/net/wavelan.p.h
@@ -305,6 +305,7 @@
#include <linux/skbuff.h>
#include <linux/malloc.h>
#include <linux/timer.h>
+#include <linux/init.h>
#include <linux/wireless.h> /* Wireless extensions */
diff --git a/drivers/net/x25_asy.c b/drivers/net/x25_asy.c
index 21963477c..f6f953201 100644
--- a/drivers/net/x25_asy.c
+++ b/drivers/net/x25_asy.c
@@ -59,7 +59,7 @@ static inline struct x25_asy *x25_asy_alloc(void)
if (slp == NULL)
break;
/* Not in use ? */
- if (!set_bit(SLF_INUSE, &slp->ctrl.flags))
+ if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags))
break;
}
/* SLP is set.. */
@@ -124,7 +124,7 @@ static inline void x25_asy_free(struct x25_asy *sl)
}
sl->xbuff = NULL;
- if (!clear_bit(SLF_INUSE, &sl->flags)) {
+ if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {
printk("%s: x25_asy_free for already free unit.\n", sl->dev->name);
}
}
@@ -201,7 +201,7 @@ static void x25_asy_changed_mtu(struct x25_asy *sl)
static inline void x25_asy_lock(struct x25_asy *sl)
{
- if (set_bit(0, (void *) &sl->dev->tbusy))
+ if (test_and_set_bit(0, (void *) &sl->dev->tbusy))
printk("%s: trying to lock already locked device!\n", sl->dev->name);
}
@@ -210,7 +210,7 @@ static inline void x25_asy_lock(struct x25_asy *sl)
static inline void x25_asy_unlock(struct x25_asy *sl)
{
- if (!clear_bit(0, (void *)&sl->dev->tbusy))
+ if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy))
printk("%s: trying to unlock already unlocked device!\n", sl->dev->name);
}
@@ -587,7 +587,7 @@ static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp,
/* Read the characters out of the buffer */
while (count--) {
if (fp && *fp++) {
- if (!set_bit(SLF_ERROR, &sl->flags)) {
+ if (!test_and_set_bit(SLF_ERROR, &sl->flags)) {
sl->rx_errors++;
}
cp++;
@@ -736,7 +736,7 @@ static void x25_asy_unesc(struct x25_asy *sl, unsigned char s)
switch(s)
{
case X25_END:
- if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))
+ if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))
{
x25_asy_bump(sl);
}
@@ -750,7 +750,7 @@ static void x25_asy_unesc(struct x25_asy *sl, unsigned char s)
case X25_ESCAPE(X25_ESC):
case X25_ESCAPE(X25_END):
- if (clear_bit(SLF_ESCAPE, &sl->flags))
+ if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
s = X25_UNESCAPE(s);
break;
}
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index eb198bc78..cb53120a2 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -351,7 +351,7 @@ static int znet_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8baf90212..2aae7a2db 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -13,6 +13,7 @@
#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/string.h>
+#include <linux/init.h>
#include <asm/page.h>
@@ -149,6 +150,7 @@ struct pci_dev_info dev_info[] = {
DEVICE( CMD, CMD_646, "646"),
DEVICE( VISION, VISION_QD8500, "QD-8500"),
DEVICE( VISION, VISION_QD8580, "QD-8580"),
+ DEVICE( BROOKTREE, BT848, "Brooktree 848"),
DEVICE( SIERRA, SIERRA_STB, "STB Horizon 64"),
DEVICE( ACC, ACC_2056, "2056"),
DEVICE( WINBOND, WINBOND_83769, "W83769F"),
@@ -263,6 +265,7 @@ struct pci_dev_info dev_info[] = {
DEVICE( INTEL, INTEL_82437VX, "82437VX Triton II"),
DEVICE( INTEL, INTEL_82371AB, "82371AB 430TX PIIX4"),
DEVICE( INTEL, INTEL_P6, "Orion P6"),
+ DEVICE( INTEL, INTEL_P6_2, "82450GX Orion P6"),
DEVICE( KTI, KTI_ET32P2, "ET32P2"),
DEVICE( ADAPTEC, ADAPTEC_7850, "AIC-7850"),
DEVICE( ADAPTEC, ADAPTEC_7855, "AIC-7855"),
@@ -517,6 +520,7 @@ const char *pci_strvendor(unsigned int vendor)
case PCI_VENDOR_ID_OLICOM: return "Olicom";
case PCI_VENDOR_ID_CMD: return "CMD";
case PCI_VENDOR_ID_VISION: return "Vision";
+ case PCI_VENDOR_ID_BROOKTREE: return "Brooktree";
case PCI_VENDOR_ID_SIERRA: return "Sierra";
case PCI_VENDOR_ID_ACC: return "ACC MICROELECTRONICS";
case PCI_VENDOR_ID_WINBOND: return "Winbond";
@@ -576,8 +580,8 @@ const char *pci_strdev(unsigned int vendor, unsigned int device)
/*
* Turn on/off PCI bridge optimization. This should allow benchmarking.
*/
-static void burst_bridge(unsigned char bus, unsigned char devfn,
- unsigned char pos, int turn_on)
+__initfunc(static void burst_bridge(unsigned char bus, unsigned char devfn,
+ unsigned char pos, int turn_on))
{
#ifdef CONFIG_PCI_OPTIMIZE
struct bridge_mapping_type *bmap;
@@ -791,7 +795,7 @@ int get_pci_list(char *buf)
* pci_malloc() returns initialized memory of size SIZE. Can be
* used only while pci_init() is active.
*/
-static void *pci_malloc(long size, unsigned long *mem_startp)
+__initfunc(static void *pci_malloc(long size, unsigned long *mem_startp))
{
void *mem;
@@ -805,7 +809,7 @@ static void *pci_malloc(long size, unsigned long *mem_startp)
}
-static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
+__initfunc(static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp))
{
unsigned int devfn, l, max;
unsigned char cmd, tmp, hdr_type = 0;
@@ -980,12 +984,12 @@ static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
}
-unsigned long pci_init (unsigned long mem_start, unsigned long mem_end)
+__initfunc(unsigned long pci_init (unsigned long mem_start, unsigned long mem_end))
{
mem_start = pcibios_init(mem_start, mem_end);
if (!pcibios_present()) {
- printk("pci_init: no BIOS32 detected\n");
+ printk("pci_init: no PCI BIOS detected\n");
return mem_start;
}
diff --git a/drivers/pnp/.cvsignore b/drivers/pnp/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/drivers/pnp/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/drivers/sbus/audio/amd7930.c b/drivers/sbus/audio/amd7930.c
index 388949d21..1134eb74e 100644
--- a/drivers/sbus/audio/amd7930.c
+++ b/drivers/sbus/audio/amd7930.c
@@ -16,6 +16,7 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/system.h>
diff --git a/drivers/sbus/audio/cs4231.c b/drivers/sbus/audio/cs4231.c
index ecb09a4d7..5c361a0b0 100644
--- a/drivers/sbus/audio/cs4231.c
+++ b/drivers/sbus/audio/cs4231.c
@@ -15,6 +15,7 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/system.h>
diff --git a/drivers/sbus/char/creator.c b/drivers/sbus/char/creator.c
index 193a26190..9bf72a3b9 100644
--- a/drivers/sbus/char/creator.c
+++ b/drivers/sbus/char/creator.c
@@ -47,52 +47,3 @@ __initfunc(void creator_setup (fbinfo_t *fb, int slot, int con_node, unsigned lo
fb->unblank = 0;
fb->type.fb_depth = 8;
}
-/*
- * creator.c: Linux/Sun Ultra Creator console support.
- *
- * Copyright (C) 1997 MIguel de Icaza (miguel@nuclecu.unam.mx)
- *
- */
-#include <linux/kd.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/proc_fs.h>
-
-#include <asm/sbus.h>
-#include <asm/io.h>
-#include <asm/fbio.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
-#include "fb.h"
-
-__initfunc(void creator_setup (fbinfo_t *fb, int slot, int con_node, unsigned long creator, int creator_io))
-{
- uint bases [2];
- unsigned long *p;
-
- if (!creator) {
- prom_getproperty (con_node, "address", (char *) &bases[0], 4);
- prom_printf ("Bases: %x %x\n", bases [0], bases [1]);
- p = (unsigned long *) creator = bases[0];
- fb->base = creator;
- fb->base = 0xff168000;
- }
-
- fb->type.fb_cmsize = 256;
- fb->mmap = 0;
- fb->loadcmap = 0;
- fb->setcursor = 0;
- fb->setcursormap = 0;
- fb->setcurshape = 0;
- fb->ioctl = 0;
- fb->switch_from_graph = 0;
- fb->postsetup = sun_cg_postsetup;
- fb->reset = 0;
- fb->blank = 0;
- fb->unblank = 0;
- fb->type.fb_depth = 8;
-}
diff --git a/drivers/sbus/char/suncons.c b/drivers/sbus/char/suncons.c
index 20b65c658..d1a2dfd45 100644
--- a/drivers/sbus/char/suncons.c
+++ b/drivers/sbus/char/suncons.c
@@ -1,4 +1,4 @@
-/* $Id: suncons.c,v 1.61 1997/04/17 02:29:36 miguel Exp $
+/* $Id: suncons.c,v 1.62 1997/05/02 22:32:32 davem Exp $
*
* suncons.c: Sun SparcStation console support.
*
@@ -387,12 +387,12 @@ render_screen(void)
sun_blitc (*contents, (unsigned long) contents);
}
-__initfunc(void serial_finish_init(void (*printfunc)(const char *)))
+__initfunc(void serial_finish_init(void (*printfunc)(const char *, int)))
{
char buffer[2048];
sprintf (buffer, linux_serial_image, UTS_RELEASE);
- (*printfunc)(buffer);
+ (*printfunc)(buffer, strlen(buffer));
}
__initfunc(void con_type_init_finish(void))
diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c
index 87fb0fea4..8e398f345 100644
--- a/drivers/sbus/char/sunkbd.c
+++ b/drivers/sbus/char/sunkbd.c
@@ -487,7 +487,7 @@ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
add_timer (&auto_repeat_timer);
}
}
- rep = set_bit(keycode, key_down);
+ rep = test_and_set_bit(keycode, key_down);
}
if(raw_mode)
diff --git a/drivers/sbus/char/sunserial.c b/drivers/sbus/char/sunserial.c
index cd4fe4ee3..2fa29da26 100644
--- a/drivers/sbus/char/sunserial.c
+++ b/drivers/sbus/char/sunserial.c
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.38 1997/04/14 17:05:00 jj Exp $
+/* $Id: sunserial.c,v 1.41 1997/05/14 20:46:51 davem Exp $
* serial.c: Serial port driver for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -19,6 +19,8 @@
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/kernel.h>
+#include <linux/keyboard.h>
+#include <linux/console.h>
#include <linux/init.h>
#include <asm/io.h>
@@ -39,8 +41,6 @@ static int num_serial = 2; /* sun4/sun4c/sun4m - Two chips on board. */
#define KEYBOARD_LINE 0x2
#define MOUSE_LINE 0x3
-extern struct wait_queue * keypress_wait;
-
struct sun_zslayout **zs_chips;
struct sun_zschannel **zs_channels;
struct sun_zschannel *zs_conschan;
@@ -687,7 +687,7 @@ static void do_softint(void *private_)
if (!tty)
return;
- if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
@@ -866,10 +866,10 @@ static void change_speed(struct sun_serial *info)
i = cflag & CBAUD;
if (cflag & CBAUDEX) {
i &= ~CBAUDEX;
- if (i != 1)
+ if (i != 5)
info->tty->termios->c_cflag &= ~CBAUDEX;
else
- i += 15;
+ i = 16;
}
if (i == 15) {
if ((info->flags & ZILOG_SPD_MASK) == ZILOG_SPD_HI)
@@ -1062,20 +1062,30 @@ static void rs_fair_output(void)
/*
* zs_console_print is registered for printk.
*/
-static void zs_console_print(const char *p)
+static void zs_console_print(const char *s, int count)
{
- char c;
+ int i;
- while((c=*(p++)) != 0) {
- if(c == '\n')
+ for (i = 0; i < count; i++, s++) {
+ if(*s == '\n')
rs_put_char('\r');
- rs_put_char(c);
+ rs_put_char(*s);
}
/* Comment this if you want to have a strict interrupt-driven output */
rs_fair_output();
+}
- return;
+static void zs_console_wait_key(void)
+{
+ sleep_on(&keypress_wait);
+}
+
+static int zs_console_device(void)
+{
+ extern int serial_console;
+
+ return MKDEV(TTYAUX_MAJOR, 64 + serial_console - 1);
}
static void rs_flush_chars(struct tty_struct *tty)
@@ -1857,7 +1867,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
static void show_serial_version(void)
{
- char *revision = "$Revision: 1.38 $";
+ char *revision = "$Revision: 1.41 $";
char *version, *p;
version = strchr(revision, ' ');
@@ -2164,14 +2174,15 @@ no_options:
termios->c_cflag = cflag;
}
-extern void register_console(void (*proc)(const char *));
-
static inline void
rs_cons_check(struct sun_serial *ss, int channel)
{
int i, o, io;
static int consout_registered = 0;
static int msg_printed = 0;
+ static struct console console = {
+ zs_console_print, 0,
+ zs_console_wait_key, zs_console_device };
i = o = io = 0;
@@ -2187,10 +2198,10 @@ rs_cons_check(struct sun_serial *ss, int channel)
o = 1;
/* double whee.. */
if(!consout_registered) {
- extern void serial_finish_init (void (*)(const char *));
+ extern void serial_finish_init (void (*)(const char *, int count));
serial_finish_init (zs_console_print);
- register_console(zs_console_print);
+ register_console(&console);
consout_registered = 1;
}
}
diff --git a/drivers/sbus/char/vfc.h b/drivers/sbus/char/vfc.h
index 752bf748c..72a883cfc 100644
--- a/drivers/sbus/char/vfc.h
+++ b/drivers/sbus/char/vfc.h
@@ -157,10 +157,16 @@ void vfc_unlock_device(struct vfc_dev *);
#define VFC_STATUS_CAPTURE 0x08000000
-#ifdef VFC_DEBUG
-#define VFC_DEBUG_PRINTK(a) printk a
+#ifdef VFC_IOCTL_DEBUG
+#define VFC_IOCTL_DEBUG_PRINTK(a) printk a
#else
-#define VFC_DEBUG_PRINTK(a)
+#define VFC_IOCTL_DEBUG_PRINTK(a)
+#endif
+
+#ifdef VFC_I2C_DEBUG
+#define VFC_I2C_DEBUG_PRINTK(a) printk a
+#else
+#define VFC_I2C_DEBUG_PRINTK(a)
#endif
#endif /* _LINUX_VFC_H_ */
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index 556d06e9f..20e04258b 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -3,11 +3,11 @@
*
* Driver for the Videopix Frame Grabber.
*
- * In order to use the VFC you need to progeam the video controller
+ * In order to use the VFC you need to program the video controller
* chip. This chip is the Phillips SAA9051. You need to call their
* documentation ordering line to get the docs.
*
- * Their is very little documentation on the VFC itself. There is
+ * There is very little documentation on the VFC itself. There is
* some useful info that can be found in the manuals that come with
* the card. I will hopefully write some better docs at a later date.
*
@@ -21,6 +21,7 @@
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/fs.h>
+#include <linux/uaccess.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
@@ -30,12 +31,11 @@
#include <asm/delay.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#include <asm/uaccess.h>
#define VFC_MAJOR (60)
#if 0
-#define VFC_DEBUG
+#define VFC_IOCTL_DEBUG
#endif
#include "vfc.h"
@@ -133,30 +133,27 @@ int init_vfc_devstruct(struct vfc_dev *dev, int instance)
dev->control_reg=0;
dev->poll_wait=NULL;
dev->busy=0;
- /* initialize the timer struct */
return 0;
}
int init_vfc_device(struct linux_sbus_device *sdev,struct vfc_dev *dev,
int instance) {
- struct linux_prom_registers reg;
if(!dev) {
printk(KERN_ERR "VFC: Bogus pointer passed\n");
return -ENOMEM;
}
printk("Initializing vfc%d\n",instance);
dev->regs=NULL;
- memcpy(&reg,&sdev->reg_addrs[0],sizeof(struct linux_prom_registers));
- prom_apply_sbus_ranges(sdev->my_bus, &reg, sdev->num_registers, sdev);
- dev->regs=sparc_alloc_io(reg.phys_addr, 0,
+ prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], sdev->num_registers, sdev);
+ dev->regs=sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
sizeof(struct vfc_regs), vfcstr,
- reg.which_io, 0x0);
- dev->which_io=reg.which_io;
- dev->phys_regs=(struct vfc_regs *)reg.phys_addr;
+ sdev->reg_addrs[0].which_io, 0x0);
+ dev->which_io=sdev->reg_addrs[0].which_io;
+ dev->phys_regs=(struct vfc_regs *)sdev->reg_addrs[0].phys_addr;
if(!dev->regs) return -EIO;
printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n",
- instance,(unsigned long)reg.phys_addr,(unsigned long)dev->regs);
+ instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs);
if(init_vfc_devstruct(dev,instance)) return -EINVAL;
if(init_vfc_hw(dev)) return -EIO;
@@ -191,52 +188,58 @@ static int vfc_open(struct inode *inode, struct file *file)
return 0;
}
-static int vfc_release(struct inode *inode,struct file *file)
+static void vfc_release(struct inode *inode,struct file *file)
{
struct vfc_dev *dev;
dev=vfc_get_dev_ptr(MINOR(inode->i_rdev));
- if(!dev) return -EINVAL;
- if(!dev->busy) return 0;
+ if(!dev) return;
+ if(!dev->busy) return;
dev->busy=0;
MOD_DEC_USE_COUNT;
- return 0;
+ return;
}
static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg)
{
struct vfc_debug_inout inout;
unsigned char *buffer;
+ int ret;
+
+ if(!suser()) return -EPERM;
switch(cmd) {
case VFC_I2C_SEND:
- if(copy_from_user(&inout, (void *)arg, sizeof(inout)))
+ if(copy_from_user(&inout, (void *)arg, sizeof(inout))) {
return -EFAULT;
+ }
buffer = kmalloc(inout.len*sizeof(char), GFP_KERNEL);
if (!buffer)
return -ENOMEM;
- if(copy_from_user(buffer, inout.buffer, inout.len*sizeof(char))) {
- kfree_s(buffer,inout.len);
+
+ if(copy_from_user(buffer, inout.buffer,
+ inout.len*sizeof(char));) {
+ kfree_s(buffer,inout.len*sizeof(char));
return -EFAULT;
}
+
vfc_lock_device(dev);
inout.ret=
vfc_i2c_sendbuf(dev,inout.addr & 0xff,
inout.buffer,inout.len);
- if(copy_to_user((void *)arg,&inout,sizeof(inout))) {
- kfree_s(buffer,inout.len);
+
+ if (copy_to_user((void *)arg,&inout,sizeof(inout))) {
+ kfree_s(buffer, inout.len);
return -EFAULT;
}
vfc_unlock_device(dev);
- kfree_s(buffer, inout.len);
-
break;
case VFC_I2C_RECV:
-
- if(copy_from_user(&inout, (void *)arg, sizeof(inout)))
+ if (copy_from_user(&inout, (void *)arg, sizeof(inout))) {
return -EFAULT;
+ }
buffer = kmalloc(inout.len, GFP_KERNEL);
if (!buffer)
@@ -248,11 +251,11 @@ static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg)
,buffer,inout.len);
vfc_unlock_device(dev);
- if(copy_to_user(inout.buffer, buffer, inout.len)) {
+ if (copy_to_user(inout.buffer, buffer, inout.len)) {
kfree_s(buffer,inout.len);
return -EFAULT;
}
- if(copy_to_user((void *)arg,&inout,sizeof(inout))) {
+ if (copy_to_user((void *)arg,&inout,sizeof(inout))) {
kfree_s(buffer,inout.len);
return -EFAULT;
}
@@ -306,12 +309,10 @@ static int vfc_set_control_ioctl(struct inode *inode, struct file *file,
struct vfc_dev *dev, unsigned long arg)
{
int setcmd,ret=0;
- if(copy_from_user(&setcmd,(void *)arg,sizeof(unsigned int)))
+ if (copy_from_user(&setcmd,(void *)arg,sizeof(unsigned int)))
return -EFAULT;
-#if 0
- VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n",
- dev->instance,setcmd));
-#endif
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n",
+ dev->instance,setcmd));
switch(setcmd) {
case MEMPRST:
vfc_lock_device(dev);
@@ -359,13 +360,14 @@ int vfc_port_change_ioctl(struct inode *inode, struct file *file,
{
int ret=0;
int cmd;
+
if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) {
- VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
"vfc_port_change_ioctl\n",dev->instance));
return -EFAULT;
}
- VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n",
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n",
dev->instance,cmd));
switch(cmd) {
@@ -424,12 +426,12 @@ int vfc_set_video_ioctl(struct inode *inode, struct file *file,
int ret=0;
int cmd;
if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) {
- VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
"vfc_set_video_ioctl\n",dev->instance));
- return -EFAULT;
+ return ret;
}
- VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n",
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n",
dev->instance,cmd));
switch(cmd) {
@@ -490,12 +492,12 @@ int vfc_get_video_ioctl(struct inode *inode, struct file *file,
else
status=PAL_NOCOLOR;
}
- VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; buf[0]=%x\n",dev->instance,
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; buf[0]=%x\n",dev->instance,
status,buf[0]));
- if(copy_to_user((void *)arg,&status,sizeof(unsigned int))) {
- VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+ if (copy_to_user((void *)arg,&status,sizeof(unsigned int))) {
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
"vfc_get_video_ioctl\n",dev->instance));
- return -EFAULT;
+ return ret;
}
return ret;
}
@@ -513,11 +515,13 @@ static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
switch(cmd & 0x0000ffff) {
case VFCGCTRL:
#if 0
- VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n",dev->instance));
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n",dev->instance));
#endif
tmp=dev->regs->control;
- if(copy_to_user((void *)arg,&tmp,sizeof(unsigned int)))
- return -EFAULT;
+ if(copy_to_user((void *)arg,&tmp, sizeof(unsigned int))) {
+ ret=-EFAULT;
+ break;
+ }
ret=0;
break;
case VFCSCTRL:
@@ -530,12 +534,9 @@ static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret=vfc_set_video_ioctl(inode,file,dev,arg);
break;
case VFCHUE:
-#if 0
- VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n",dev->instance));
-#endif
-
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n",dev->instance));
if(copy_from_user(&tmp,(void *)arg,sizeof(unsigned int))) {
- VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer "
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer "
"to IOCTL(VFCHUE)",dev->instance));
ret=-EFAULT;
} else {
@@ -549,7 +550,7 @@ static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break;
case VFCRDINFO:
ret=-EINVAL;
- VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n",dev->instance));
+ VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n",dev->instance));
break;
default:
ret=vfc_debug(vfc_get_dev_ptr(MINOR(inode->i_rdev)),
@@ -584,8 +585,9 @@ static int vfc_mmap(struct inode *inode, struct file *file,
return 0;
}
-static long long vfc_lseek(struct inode *inode, struct file *file,
- long long offset, int origin)
+
+static int vfc_lseek(struct inode *inode, struct file *file,
+ off_t offset, int origin)
{
return -ESPIPE;
}
@@ -595,14 +597,13 @@ static struct file_operations vfc_fops = {
NULL, /* vfc_write */
NULL, /* vfc_read */
NULL, /* vfc_readdir */
- NULL, /* vfc_poll */
+ NULL, /* vfc_select */
vfc_ioctl,
vfc_mmap,
vfc_open,
vfc_release,
};
-
static int vfc_probe(void)
{
struct linux_sbus *bus;
diff --git a/drivers/sbus/char/vfc_i2c.c b/drivers/sbus/char/vfc_i2c.c
index 952eb9875..68cfc4405 100644
--- a/drivers/sbus/char/vfc_i2c.c
+++ b/drivers/sbus/char/vfc_i2c.c
@@ -31,8 +31,8 @@ fairly certain that the flowcharts in the phillips docs are wrong. */
#include <asm/system.h>
#include <asm/sbus.h>
-#if 0
-#define VFC_DEBUG
+#if 0
+#define VFC_I2C_DEBUG
#endif
#include "vfc.h"
@@ -72,6 +72,8 @@ int vfc_pcf8584_init(struct vfc_dev *dev)
void vfc_i2c_delay_wakeup(struct vfc_dev *dev)
{
+ /* Used to profile code and eliminate too many delays */
+ VFC_I2C_DEBUG_PRINTK(("vfc%d: Delaying\n",dev->instance));
wake_up(&dev->poll_wait);
}
@@ -95,14 +97,14 @@ void inline vfc_i2c_delay(struct vfc_dev *dev)
int vfc_init_i2c_bus(struct vfc_dev *dev)
{
- dev->regs->i2c_s1= ENABLE_SERIAL | ACK;
+ dev->regs->i2c_s1= ENABLE_SERIAL | SELECT(S0) | ACK;
vfc_i2c_reset_bus(dev);
return 0;
}
int vfc_i2c_reset_bus(struct vfc_dev *dev)
{
- VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n",
+ VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n",
dev->instance));
if(!dev) return -EINVAL;
if(!dev->regs) return -EINVAL;
@@ -110,7 +112,7 @@ int vfc_i2c_reset_bus(struct vfc_dev *dev)
dev->regs->i2c_s1=SEND_I2C_STOP | ACK;
vfc_i2c_delay(dev);
dev->regs->i2c_s1=CLEAR_I2C_BUS;
- VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n",
+ VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n",
dev->instance, dev->regs->i2c_s1));
return 0;
}
@@ -146,7 +148,7 @@ int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr, char mode)
{
int ret,raddr;
#if 1
- dev->regs->i2c_s1=SEND_I2C_STOP;
+ dev->regs->i2c_s1=SEND_I2C_STOP | ACK;
dev->regs->i2c_s1=SELECT(S0) | ENABLE_SERIAL;
vfc_i2c_delay(dev);
#endif
@@ -154,12 +156,12 @@ int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr, char mode)
switch(mode) {
case VFC_I2C_READ:
dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr | 0x1);
- VFC_DEBUG_PRINTK(("vfc%d: recieving from i2c addr 0x%x\n",
+ VFC_I2C_DEBUG_PRINTK(("vfc%d: recieving from i2c addr 0x%x\n",
dev->instance,addr | 0x1));
break;
case VFC_I2C_WRITE:
dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr & ~0x1);
- VFC_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n",
+ VFC_I2C_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n",
dev->instance,addr & ~0x1));
break;
default:
@@ -215,7 +217,7 @@ int vfc_i2c_recv_byte(struct vfc_dev *dev, unsigned char *byte, int last)
int ret;
if(last) {
dev->regs->i2c_reg=NEGATIVE_ACK;
- VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: sending negative ack\n",
+ VFC_I2C_DEBUG_PRINTK(("vfc%d: sending negative ack\n",
dev->instance));
} else {
dev->regs->i2c_s1=ACK;
@@ -255,6 +257,8 @@ int vfc_i2c_recvbuf(struct vfc_dev *dev, unsigned char addr,
printk(KERN_ERR "vfc%d: "
"VFC error while recieving byte\n",
dev->instance);
+ dev->regs->i2c_s1=SEND_I2C_STOP;
+ ret=-EINVAL;
}
buf++;
}
@@ -286,7 +290,7 @@ int vfc_i2c_sendbuf(struct vfc_dev *dev, unsigned char addr,
ret=vfc_i2c_xmit_byte(dev,buf);
switch(ret) {
case XMIT_LAST_BYTE:
- VFC_DEBUG_PRINTK(("vfc%d: "
+ VFC_I2C_DEBUG_PRINTK(("vfc%d: "
"Reciever ended transmission with "
" %d bytes remaining\n",
dev->instance,count));
diff --git a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c
index 3691108e6..44a78b12c 100644
--- a/drivers/scsi/53c7,8xx.c
+++ b/drivers/scsi/53c7,8xx.c
@@ -254,7 +254,6 @@ typedef unsigned int u32;
#include <linux/time.h>
#include <linux/blk.h>
#include <linux/init.h>
-#undef current
#include "scsi.h"
#include "hosts.h"
@@ -783,7 +782,7 @@ NCR53c7x0_driver_init (struct Scsi_Host *host) {
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
int i, j;
- u32 *current;
+ u32 *curr;
for (i = 0; i < 16; ++i) {
hostdata->request_sense[i] = 0;
for (j = 0; j < 8; ++j)
@@ -792,14 +791,14 @@ NCR53c7x0_driver_init (struct Scsi_Host *host) {
}
hostdata->issue_queue = NULL;
hostdata->running_list = hostdata->finished_queue =
- hostdata->current = NULL;
- for (i = 0, current = (u32 *) hostdata->schedule;
- i < host->can_queue; ++i, current += 2) {
- current[0] = hostdata->NOP_insn;
- current[1] = 0xdeadbeef;
+ hostdata->curr = NULL;
+ for (i = 0, curr = (u32 *) hostdata->schedule;
+ i < host->can_queue; ++i, curr += 2) {
+ curr[0] = hostdata->NOP_insn;
+ curr[1] = 0xdeadbeef;
}
- current[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
- current[1] = (u32) virt_to_bus (hostdata->script) +
+ curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
+ curr[1] = (u32) virt_to_bus (hostdata->script) +
hostdata->E_wait_reselect;
hostdata->reconnect_dsa_head = 0;
hostdata->addr_reconnect_dsa_head = (u32)
@@ -2104,7 +2103,7 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
int left, found;
volatile struct NCR53c7x0_cmd * linux_search;
volatile struct NCR53c7x0_cmd * volatile *linux_prev;
- volatile u32 *ncr_prev, *current, ncr_search;
+ volatile u32 *ncr_prev, *curr, ncr_search;
#if 0
printk ("scsi%d: abnormal finished\n", host->host_no);
@@ -2120,13 +2119,13 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
*/
- for (found = 0, left = host->can_queue, current = hostdata->schedule;
- left > 0; --left, current += 2)
+ for (found = 0, left = host->can_queue, curr = hostdata->schedule;
+ left > 0; --left, curr += 2)
{
- if (issue_to_cmd (host, hostdata, (u32 *) current) == cmd)
+ if (issue_to_cmd (host, hostdata, (u32 *) curr) == cmd)
{
- current[0] = hostdata->NOP_insn;
- current[1] = 0xdeadbeef;
+ curr[0] = hostdata->NOP_insn;
+ curr[1] = 0xdeadbeef;
++found;
break;
}
@@ -3964,7 +3963,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
Scsi_Cmnd *tmp = cmd->cmd;
unsigned long flags;
/* dsa start is negative, so subtraction is used */
- volatile u32 *current;
+ volatile u32 *curr;
int i;
NCR53c7x0_local_setup(host);
@@ -3991,9 +3990,9 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
return;
}
- for (i = host->can_queue, current = hostdata->schedule;
- i > 0 && current[0] != hostdata->NOP_insn;
- --i, current += 2 /* JUMP instructions are two words */);
+ for (i = host->can_queue, curr = hostdata->schedule;
+ i > 0 && curr[0] != hostdata->NOP_insn;
+ --i, curr += 2 /* JUMP instructions are two words */);
if (i > 0) {
++hostdata->busy[tmp->target][tmp->lun];
@@ -4002,13 +4001,13 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
/* Restore this instruction to a NOP once the command starts */
cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) /
- sizeof(u32)] = (u32) virt_to_bus ((void *)current);
+ sizeof(u32)] = (u32) virt_to_bus ((void *)curr);
/* Replace the current jump operand. */
- current[1] =
+ curr[1] =
virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
hostdata->E_dsa_code_template;
/* Replace the NOP instruction with a JUMP */
- current[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
+ curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
DBC_TCI_TRUE;
} else {
printk ("scsi%d: no free slot\n", host->host_no);
@@ -4510,8 +4509,8 @@ restart:
/*
* NCR53c700 and NCR53c700-66 change the current SCSI
- * process, hostdata->current, in the Linux driver so
- * cmd = hostdata->current.
+ * process, hostdata->curr, in the Linux driver so
+ * cmd = hostdata->curr.
*
* With other chips, we must look through the commands
* executing and find the command structure which
@@ -4519,7 +4518,7 @@ restart:
*/
if (hostdata->options & OPTION_700) {
- cmd = (struct NCR53c7x0_cmd *) hostdata->current;
+ cmd = (struct NCR53c7x0_cmd *) hostdata->curr;
} else {
dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
for (cmd = (struct NCR53c7x0_cmd *)
@@ -5872,7 +5871,7 @@ print_queues (struct Scsi_Host *host) {
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
u32 *dsa, *next_dsa;
- volatile u32 *current;
+ volatile u32 *curr;
int left;
Scsi_Cmnd *cmd, *next_cmd;
unsigned long flags;
@@ -5914,11 +5913,11 @@ print_queues (struct Scsi_Host *host) {
*/
printk ("scsi%d : schedule dsa array :\n", host->host_no);
- for (left = host->can_queue, current = hostdata->schedule;
- left > 0; current += 2, --left)
- if (current[0] != hostdata->NOP_insn)
+ for (left = host->can_queue, curr = hostdata->schedule;
+ left > 0; curr += 2, --left)
+ if (curr[0] != hostdata->NOP_insn)
/* FIXME : convert pointer to dsa_begin to pointer to dsa. */
- print_dsa (host, bus_to_virt (current[1] -
+ print_dsa (host, bus_to_virt (curr[1] -
(hostdata->E_dsa_code_begin -
hostdata->E_dsa_code_template)), "");
printk ("scsi%d : end schedule dsa array\n", host->host_no);
@@ -6108,7 +6107,7 @@ return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
host->hostdata;
struct NCR53c7x0_cmd *c;
int i;
- u32 *current;
+ u32 *curr;
Scsi_Cmnd *list = NULL, *tmp;
for (c = (struct NCR53c7x0_cmd *) hostdata->running_list; c;
c = (struct NCR53c7x0_cmd *) c->next) {
@@ -6129,12 +6128,12 @@ return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
}
if (free) {
- for (i = 0, current = (u32 *) hostdata->schedule;
- i < host->can_queue; ++i, current += 2) {
- current[0] = hostdata->NOP_insn;
- current[1] = 0xdeadbeef;
+ for (i = 0, curr = (u32 *) hostdata->schedule;
+ i < host->can_queue; ++i, curr += 2) {
+ curr[0] = hostdata->NOP_insn;
+ curr[1] = 0xdeadbeef;
}
- hostdata->current = NULL;
+ hostdata->curr = NULL;
}
if (issue) {
diff --git a/drivers/scsi/53c7,8xx.h b/drivers/scsi/53c7,8xx.h
index 80fbad3b5..cfddfa681 100644
--- a/drivers/scsi/53c7,8xx.h
+++ b/drivers/scsi/53c7,8xx.h
@@ -1394,7 +1394,7 @@ struct NCR53c7x0_hostdata {
/* commands running, maintained
by Linux driver */
- volatile struct NCR53c7x0_cmd *current; /* currently connected
+ volatile struct NCR53c7x0_cmd *curr; /* currently connected
nexus, ONLY valid for
NCR53c700/NCR53c700-66
*/
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
new file mode 100644
index 000000000..a8cd93828
--- /dev/null
+++ b/drivers/scsi/53c7xx.c
@@ -0,0 +1,6107 @@
+/*
+ * 53c710 driver. Modified from Drew Eckhardts driver
+ * for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
+ * Check out PERM_OPTIONS and EXPECTED_CLOCK, which may be defined in the
+ * relevant machine specific file (eg. mvme166.[ch], amiga7xx.[ch]).
+ * There are also currently some defines at the top of 53c7xx.scr.
+ * The chip type is #defined in script_asm.pl, as well as the Makefile.
+ * Host scsi ID expected to be 7 - see NCR53c7x0_init().
+ *
+ * I have removed the PCI code and some of the 53c8xx specific code -
+ * simply to make this file smaller and easier to manage.
+ *
+ * MVME166 issues:
+ * Problems trying to read any chip registers in NCR53c7x0_init(), as they
+ * may never have been set by 166Bug (eg. If kernel has come in over tftp).
+ */
+
+/*
+ * Adapted for Linux/m68k Amiga platforms for the A4000T/A4091 and
+ * WarpEngine SCSI controllers.
+ * By Alan Hourihane <alanh@fairlite.demon.co.uk>
+ * Thanks to Richard Hirst for making it possible with the MVME additions
+ */
+
+/*
+ * 53c710 rev 0 doesn't support add with carry. Rev 1 and 2 does. To
+ * overcome this problem you can define FORCE_DSA_ALIGNMENT, which ensures
+ * that the DSA address is always xxxxxx00. If disconnection is not allowed,
+ * then the script only ever tries to add small (< 256) positive offsets to
+ * DSA, so lack of carry isn't a problem. FORCE_DSA_ALIGNMENT can, of course,
+ * be defined for all chip revisions at a small cost in memory usage.
+ */
+
+#define FORCE_DSA_ALIGNMENT
+
+/*
+ * Selection timer does not always work on the 53c710, depending on the
+ * timing at the last disconnect, if this is a problem for you, try
+ * using validids as detailed below.
+ *
+ * Options for the NCR7xx driver
+ *
+ * nosync:0 - disables synchronous negotiation
+ * nodisconnect:0 - disables disconnection
+ * validids:0x?? - Bitmask field that disallows certain ID's.
+ * - e.g. 0x03 allows ID 0,1
+ * - 0x1F allows ID 0,1,2,3,4
+ */
+
+/*
+ * PERM_OPTIONS are driver options which will be enabled for all NCR boards
+ * in the system at driver initialization time.
+ *
+ * Don't THINK about touching these in PERM_OPTIONS :
+ * OPTION_MEMORY_MAPPED
+ * 680x0 doesn't have an IO map!
+ *
+ * OPTION_DEBUG_TEST1
+ * Test 1 does bus mastering and interrupt tests, which will help weed
+ * out brain damaged main boards.
+ *
+ * Other PERM_OPTIONS settings are listed below. Note the actual options
+ * required are set in the relevant file (mvme166.c, amiga7xx.c, etc):
+ *
+ * OPTION_NO_ASYNC
+ * Don't negotiate for asynchronous transfers on the first command
+ * when OPTION_ALWAYS_SYNCHRONOUS is set. Useful for dain bramaged
+ * devices which do something bad rather than sending a MESSAGE
+ * REJECT back to us like they should if they can't cope.
+ *
+ * OPTION_SYNCHRONOUS
+ * Enable support for synchronous transfers. Target negotiated
+ * synchronous transfers will be responded to. To initiate
+ * a synchronous transfer request, call
+ *
+ * request_synchronous (hostno, target)
+ *
+ * from within KGDB.
+ *
+ * OPTION_ALWAYS_SYNCHRONOUS
+ * Negotiate for synchronous transfers with every target after
+ * driver initialization or a SCSI bus reset. This is a bit dangerous,
+ * since there are some dain bramaged SCSI devices which will accept
+ * SDTR messages but keep talking asynchronously.
+ *
+ * OPTION_DISCONNECT
+ * Enable support for disconnect/reconnect. To change the
+ * default setting on a given host adapter, call
+ *
+ * request_disconnect (hostno, allow)
+ *
+ * where allow is non-zero to allow, 0 to disallow.
+ *
+ * If you really want to run 10MHz FAST SCSI-II transfers, you should
+ * know that the NCR driver currently ignores parity information. Most
+ * systems do 5MHz SCSI fine. I've seen a lot that have problems faster
+ * than 8MHz. To play it safe, we only request 5MHz transfers.
+ *
+ * If you'd rather get 10MHz transfers, edit sdtr_message and change
+ * the fourth byte from 50 to 25.
+ */
+
+#include <linux/config.h>
+
+/*
+ * Sponsored by
+ * iX Multiuser Multitasking Magazine
+ * Hannover, Germany
+ * hm@ix.de
+ *
+ * Copyright 1993, 1994, 1995 Drew Eckhardt
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@PoohSticks.ORG
+ * +1 (303) 786-7975
+ *
+ * TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
+ *
+ * For more information, please consult
+ *
+ * NCR53C810
+ * SCSI I/O Processor
+ * Programmer's Guide
+ *
+ * NCR 53C810
+ * PCI-SCSI I/O Processor
+ * Data Manual
+ *
+ * NCR 53C810/53C820
+ * PCI-SCSI I/O Processor Design In Guide
+ *
+ * For literature on Symbios Logic Inc. formerly NCR, SCSI,
+ * and Communication products please call (800) 334-5454 or
+ * (719) 536-3300.
+ *
+ * PCI BIOS Specification Revision
+ * PCI Local Bus Specification
+ * PCI System Design Guide
+ *
+ * PCI Special Interest Group
+ * M/S HF3-15A
+ * 5200 N.E. Elam Young Parkway
+ * Hillsboro, Oregon 97124-6497
+ * +1 (503) 696-2000
+ * +1 (800) 433-5177
+ */
+
+/*
+ * Design issues :
+ * The cumulative latency needed to propagate a read/write request
+ * through the file system, buffer cache, driver stacks, SCSI host, and
+ * SCSI device is ultimately the limiting factor in throughput once we
+ * have a sufficiently fast host adapter.
+ *
+ * So, to maximize performance we want to keep the ratio of latency to data
+ * transfer time to a minimum by
+ * 1. Minimizing the total number of commands sent (typical command latency
+ * including drive and bus mastering host overhead is as high as 4.5ms)
+ * to transfer a given amount of data.
+ *
+ * This is accomplished by placing no arbitrary limit on the number
+ * of scatter/gather buffers supported, since we can transfer 1K
+ * per scatter/gather buffer without Eric's cluster patches,
+ * 4K with.
+ *
+ * 2. Minimizing the number of fatal interrupts serviced, since
+ * fatal interrupts halt the SCSI I/O processor. Basically,
+ * this means offloading the practical maximum amount of processing
+ * to the SCSI chip.
+ *
+ * On the NCR53c810/820/720, this is accomplished by using
+ * interrupt-on-the-fly signals when commands complete,
+ * and only handling fatal errors and SDTR / WDTR messages
+ * in the host code.
+ *
+ * On the NCR53c710, interrupts are generated as on the NCR53c8x0,
+ * only the lack of a interrupt-on-the-fly facility complicates
+ * things. Also, SCSI ID registers and commands are
+ * bit fielded rather than binary encoded.
+ *
+ * On the NCR53c700 and NCR53c700-66, operations that are done via
+ * indirect, table mode on the more advanced chips must be
+ * replaced by calls through a jump table which
+ * acts as a surrogate for the DSA. Unfortunately, this
+ * will mean that we must service an interrupt for each
+ * disconnect/reconnect.
+ *
+ * 3. Eliminating latency by pipelining operations at the different levels.
+ *
+ * This driver allows a configurable number of commands to be enqueued
+ * for each target/lun combination (experimentally, I have discovered
+ * that two seems to work best) and will ultimately allow for
+ * SCSI-II tagged queuing.
+ *
+ *
+ * Architecture :
+ * This driver is built around a Linux queue of commands waiting to
+ * be executed, and a shared Linux/NCR array of commands to start. Commands
+ * are transfered to the array by the run_process_issue_queue() function
+ * which is called whenever a command completes.
+ *
+ * As commands are completed, the interrupt routine is triggered,
+ * looks for commands in the linked list of completed commands with
+ * valid status, removes these commands from a list of running commands,
+ * calls the done routine, and flags their target/luns as not busy.
+ *
+ * Due to limitations in the intelligence of the NCR chips, certain
+ * concessions are made. In many cases, it is easier to dynamically
+ * generate/fix-up code rather than calculate on the NCR at run time.
+ * So, code is generated or fixed up for
+ *
+ * - Handling data transfers, using a variable number of MOVE instructions
+ * interspersed with CALL MSG_IN, WHEN MSGIN instructions.
+ *
+ * The DATAIN and DATAOUT routines are separate, so that an incorrect
+ * direction can be trapped, and space isn't wasted.
+ *
+ * It may turn out that we're better off using some sort
+ * of table indirect instruction in a loop with a variable
+ * sized table on the NCR53c710 and newer chips.
+ *
+ * - Checking for reselection (NCR53c710 and better)
+ *
+ * - Handling the details of SCSI context switches (NCR53c710 and better),
+ * such as reprogramming appropriate synchronous parameters,
+ * removing the dsa structure from the NCR's queue of outstanding
+ * commands, etc.
+ *
+ */
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <linux/config.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/delay.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/time.h>
+#include <linux/blk.h>
+
+#ifdef CONFIG_AMIGA
+#include <asm/pgtable.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/irq.h>
+
+#define BIG_ENDIAN
+#define NO_IO_SPACE
+#endif
+
+#ifdef CONFIG_MVME166
+#include <asm/mvme166hw.h>
+
+#define BIG_ENDIAN
+#define NO_IO_SPACE
+#endif
+
+#include "scsi.h"
+#include "hosts.h"
+#include "53c7xx.h"
+#include "constants.h"
+#include "sd.h"
+#include <linux/stat.h>
+#include <linux/stddef.h>
+
+#ifdef NO_IO_SPACE
+/*
+ * The following make the definitions in 53c7xx.h (write8, etc) smaller,
+ * we don't have seperate i/o space anyway.
+ */
+#undef inb
+#undef outb
+#define inb(x) 1
+#define inw(x) 1
+#define inl(x) 1
+#define outb(x,y) 1
+#define outw(x,y) 1
+#define outl(x,y) 1
+#endif
+
+static int check_address (unsigned long addr, int size);
+static void dump_events (struct Scsi_Host *host, int count);
+static Scsi_Cmnd * return_outstanding_commands (struct Scsi_Host *host,
+ int free, int issue);
+static void hard_reset (struct Scsi_Host *host);
+static void ncr_scsi_reset (struct Scsi_Host *host);
+static void print_lots (struct Scsi_Host *host);
+static void set_synchronous (struct Scsi_Host *host, int target, int sxfer,
+ int scntl3, int now_connected);
+static int datapath_residual (struct Scsi_Host *host);
+static const char * sbcl_to_phase (int sbcl);
+static void print_progress (Scsi_Cmnd *cmd);
+static void print_queues (struct Scsi_Host *host);
+static void process_issue_queue (unsigned long flags);
+static int shutdown (struct Scsi_Host *host);
+static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result);
+static int disable (struct Scsi_Host *host);
+static int NCR53c7xx_run_tests (struct Scsi_Host *host);
+void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static int ncr_halt (struct Scsi_Host *host);
+static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
+ *cmd);
+static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd);
+static void print_dsa (struct Scsi_Host *host, u32 *dsa,
+ const char *prefix);
+static int print_insn (struct Scsi_Host *host, const u32 *insn,
+ const char *prefix, int kernel);
+
+static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd);
+static void NCR53c7x0_init_fixup (struct Scsi_Host *host);
+static int NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
+ NCR53c7x0_cmd *cmd);
+static void NCR53c7x0_soft_reset (struct Scsi_Host *host);
+
+/* Size of event list (per host adapter) */
+static int track_events = 0;
+static struct Scsi_Host *first_host = NULL; /* Head of list of NCR boards */
+static Scsi_Host_Template *the_template = NULL;
+
+/* NCR53c710 script handling code */
+
+#include "53c7xx_d.h"
+#ifdef A_int_debug_sync
+#define DEBUG_SYNC_INTR A_int_debug_sync
+#endif
+int NCR53c7xx_script_len = sizeof (SCRIPT);
+int NCR53c7xx_dsa_len = A_dsa_end + Ent_dsa_zero - Ent_dsa_code_template;
+#ifdef FORCE_DSA_ALIGNMENT
+int CmdPageStart = (0 - Ent_dsa_zero - sizeof(struct NCR53c7x0_cmd)) & 0xff;
+#endif
+int flushsize;
+
+static char *setup_strings[] =
+ {"","","","","","","",""};
+
+#define MAX_SETUP_STRINGS (sizeof(setup_strings) / sizeof(char *))
+#define SETUP_BUFFER_SIZE 200
+static char setup_buffer[SETUP_BUFFER_SIZE];
+static char setup_used[MAX_SETUP_STRINGS];
+
+void ncr53c7xx_setup (char *str, int *ints)
+{
+ int i;
+ char *p1, *p2;
+
+ p1 = setup_buffer;
+ *p1 = '\0';
+ if (str)
+ strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer));
+ setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
+ p1 = setup_buffer;
+ i = 0;
+ while (*p1 && (i < MAX_SETUP_STRINGS)) {
+ p2 = strchr(p1, ',');
+ if (p2) {
+ *p2 = '\0';
+ if (p1 != p2)
+ setup_strings[i] = p1;
+ p1 = p2 + 1;
+ i++;
+ }
+ else {
+ setup_strings[i] = p1;
+ break;
+ }
+ }
+ for (i=0; i<MAX_SETUP_STRINGS; i++)
+ setup_used[i] = 0;
+}
+
+
+/* check_setup_strings() returns index if key found, 0 if not
+ */
+
+static int check_setup_strings(char *key, int *flags, int *val, char *buf)
+{
+int x;
+char *cp;
+
+ for (x=0; x<MAX_SETUP_STRINGS; x++) {
+ if (setup_used[x])
+ continue;
+ if (!strncmp(setup_strings[x], key, strlen(key)))
+ break;
+ if (!strncmp(setup_strings[x], "next", strlen("next")))
+ return 0;
+ }
+ if (x == MAX_SETUP_STRINGS)
+ return 0;
+ setup_used[x] = 1;
+ cp = setup_strings[x] + strlen(key);
+ *val = -1;
+ if (*cp != ':')
+ return ++x;
+ cp++;
+ if ((*cp >= '0') && (*cp <= '9')) {
+ *val = simple_strtoul(cp,NULL,0);
+ }
+ return ++x;
+}
+
+
+
+/*
+ * KNOWN BUGS :
+ * - There is some sort of conflict when the PPP driver is compiled with
+ * support for 16 channels?
+ *
+ * - On systems which predate the 1.3.x initialization order change,
+ * the NCR driver will cause Cannot get free page messages to appear.
+ * These are harmless, but I don't know of an easy way to avoid them.
+ *
+ * - With OPTION_DISCONNECT, on two systems under unknown circumstances,
+ * we get a PHASE MISMATCH with DSA set to zero (suggests that we
+ * are occurring somewhere in the reselection code) where
+ * DSP=some value DCMD|DBC=same value.
+ *
+ * Closer inspection suggests that we may be trying to execute
+ * some portion of the DSA?
+ * scsi0 : handling residual transfer (+ 0 bytes from DMA FIFO)
+ * scsi0 : handling residual transfer (+ 0 bytes from DMA FIFO)
+ * scsi0 : no current command : unexpected phase MSGIN.
+ * DSP=0x1c46cc, DCMD|DBC=0x1c46ac, DSA=0x0
+ * DSPS=0x0, TEMP=0x1c3e70, DMODE=0x80
+ * scsi0 : DSP->
+ * 001c46cc : 0x001c46cc 0x00000000
+ * 001c46d4 : 0x001c5ea0 0x000011f8
+ *
+ * Changed the print code in the phase_mismatch handler so
+ * that we call print_lots to try to diagnose this.
+ *
+ */
+
+/*
+ * Possible future direction of architecture for max performance :
+ *
+ * We're using a single start array for the NCR chip. This is
+ * sub-optimal, because we cannot add a command which would conflict with
+ * an executing command to this start queue, and therefore must insert the
+ * next command for a given I/T/L combination after the first has completed;
+ * incurring our interrupt latency between SCSI commands.
+ *
+ * To allow further pipelining of the NCR and host CPU operation, we want
+ * to set things up so that immediately on termination of a command destined
+ * for a given LUN, we get that LUN busy again.
+ *
+ * To do this, we need to add a 32 bit pointer to which is jumped to
+ * on completion of a command. If no new command is available, this
+ * would point to the usual DSA issue queue select routine.
+ *
+ * If one were, it would point to a per-NCR53c7x0_cmd select routine
+ * which starts execution immediately, inserting the command at the head
+ * of the start queue if the NCR chip is selected or reselected.
+ *
+ * We would change so that we keep a list of outstanding commands
+ * for each unit, rather than a single running_list. We'd insert
+ * a new command into the right running list; if the NCR didn't
+ * have something running for that yet, we'd put it in the
+ * start queue as well. Some magic needs to happen to handle the
+ * race condition between the first command terminating before the
+ * new one is written.
+ *
+ * Potential for profiling :
+ * Call do_gettimeofday(struct timeval *tv) to get 800ns resolution.
+ */
+
+
+/*
+ * TODO :
+ * 1. To support WIDE transfers, not much needs to happen. We
+ * should do CHMOVE instructions instead of MOVEs when
+ * we have scatter/gather segments of uneven length. When
+ * we do this, we need to handle the case where we disconnect
+ * between segments.
+ *
+ * 2. Currently, when Icky things happen we do a FATAL(). Instead,
+ * we want to do an integrity check on the parts of the NCR hostdata
+ * structure which were initialized at boot time; FATAL() if that
+ * fails, and otherwise try to recover. Keep track of how many
+ * times this has happened within a single SCSI command; if it
+ * gets excessive, then FATAL().
+ *
+ * 3. Parity checking is currently disabled, and a few things should
+ * happen here now that we support synchronous SCSI transfers :
+ * 1. On soft-reset, we shoould set the EPC (Enable Parity Checking)
+ * and AAP (Assert SATN/ on parity error) bits in SCNTL0.
+ *
+ * 2. We should enable the parity interrupt in the SIEN0 register.
+ *
+ * 3. intr_phase_mismatch() needs to believe that message out is
+ * always an "acceptable" phase to have a mismatch in. If
+ * the old phase was MSG_IN, we should send a MESSAGE PARITY
+ * error. If the old phase was something else, we should send
+ * a INITIATOR_DETECTED_ERROR message. Note that this could
+ * cause a RESTORE POINTERS message; so we should handle that
+ * correctly first. Instead, we should probably do an
+ * initiator_abort.
+ *
+ * 4. MPEE bit of CTEST4 should be set so we get interrupted if
+ * we detect an error.
+ *
+ *
+ * 5. The initial code has been tested on the NCR53c810. I don't
+ * have access to NCR53c700, 700-66 (Forex boards), NCR53c710
+ * (NCR Pentium systems), NCR53c720, NCR53c820, or NCR53c825 boards to
+ * finish development on those platforms.
+ *
+ * NCR53c820/825/720 - need to add wide transfer support, including WDTR
+ * negotiation, programming of wide transfer capabilities
+ * on reselection and table indirect selection.
+ *
+ * NCR53c710 - need to add fatal interrupt or GEN code for
+ * command completion signaling. Need to modify all
+ * SDID, SCID, etc. registers, and table indirect select code
+ * since these use bit fielded (ie 1<<target) instead of
+ * binary encoded target ids. Need to accommodate
+ * different register mappings, probably scan through
+ * the SCRIPT code and change the non SFBR register operand
+ * of all MOVE instructions.
+ *
+ * It is rather worse than this actually, the 710 corrupts
+ * both TEMP and DSA when you do a MOVE MEMORY. This
+ * screws you up all over the place. MOVE MEMORY 4 with a
+ * destination of DSA seems to work OK, which helps some.
+ * Richard Hirst richard@sleepie.demon.co.uk
+ *
+ * NCR53c700/700-66 - need to add code to refix addresses on
+ * every nexus change, eliminate all table indirect code,
+ * very messy.
+ *
+ * 6. The NCR53c7x0 series is very popular on other platforms that
+ * could be running Linux - ie, some high performance AMIGA SCSI
+ * boards use it.
+ *
+ * So, I should include #ifdef'd code so that it is
+ * compatible with these systems.
+ *
+ * Specifically, the little Endian assumptions I made in my
+ * bit fields need to change, and if the NCR doesn't see memory
+ * the right way, we need to provide options to reverse words
+ * when the scripts are relocated.
+ *
+ * 7. Use vremap() to access memory mapped boards.
+ */
+
+/*
+ * Allow for simultaneous existence of multiple SCSI scripts so we
+ * can have a single driver binary for all of the family.
+ *
+ * - one for NCR53c700 and NCR53c700-66 chips (not yet supported)
+ * - one for rest (only the NCR53c810, 815, 820, and 825 are currently
+ * supported)
+ *
+ * So that we only need two SCSI scripts, we need to modify things so
+ * that we fixup register accesses in READ/WRITE instructions, and
+ * we'll also have to accommodate the bit vs. binary encoding of IDs
+ * with the 7xx chips.
+ */
+
+#define ROUNDUP(adr,type) \
+ ((void *) (((long) (adr) + sizeof(type) - 1) & ~(sizeof(type) - 1)))
+
+
+/*
+ * Function: issue_to_cmd
+ *
+ * Purpose: convert jump instruction in issue array to NCR53c7x0_cmd
+ * structure pointer.
+ *
+ * Inputs; issue - pointer to start of NOP or JUMP instruction
+ * in issue array.
+ *
+ * Returns: pointer to command on success; 0 if opcode is NOP.
+ */
+
+static inline struct NCR53c7x0_cmd *
+issue_to_cmd (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
+ u32 *issue)
+{
+ return (issue[0] != hostdata->NOP_insn) ?
+ /*
+ * If the IF TRUE bit is set, it's a JUMP instruction. The
+ * operand is a bus pointer to the dsa_begin routine for this DSA. The
+ * dsa field of the NCR53c7x0_cmd structure starts with the
+ * DSA code template. By converting to a virtual address,
+ * subtracting the code template size, and offset of the
+ * dsa field, we end up with a pointer to the start of the
+ * structure (alternatively, we could use the
+ * dsa_cmnd field, an anachronism from when we weren't
+ * sure what the relationship between the NCR structures
+ * and host structures were going to be.
+ */
+ (struct NCR53c7x0_cmd *) ((char *) bus_to_virt (issue[1]) -
+ (hostdata->E_dsa_code_begin - hostdata->E_dsa_code_template) -
+ offsetof(struct NCR53c7x0_cmd, dsa))
+ /* If the IF TRUE bit is not set, it's a NOP */
+ : NULL;
+}
+
+
+/*
+ * FIXME: we should junk these, in favor of synchronous_want and
+ * wide_want in the NCR53c7x0_hostdata structure.
+ */
+
+/* Template for "preferred" synchronous transfer parameters. */
+
+static const unsigned char sdtr_message[] = {
+#ifdef CONFIG_SCSI_NCR53C7xx_FAST
+ EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 25 /* *4ns */, 8 /* off */
+#else
+ EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 50 /* *4ns */, 8 /* off */
+#endif
+};
+
+/* Template to request asynchronous transfers */
+
+static const unsigned char async_message[] = {
+ EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 0, 0 /* asynchronous */
+};
+
+/* Template for "preferred" WIDE transfer parameters */
+
+static const unsigned char wdtr_message[] = {
+ EXTENDED_MESSAGE, 2 /* length */, EXTENDED_WDTR, 1 /* 2^1 bytes */
+};
+
+/*
+ * Function : struct Scsi_Host *find_host (int host)
+ *
+ * Purpose : KGDB support function which translates a host number
+ * to a host structure.
+ *
+ * Inputs : host - number of SCSI host
+ *
+ * Returns : NULL on failure, pointer to host structure on success.
+ */
+
+static struct Scsi_Host *
+find_host (int host) {
+ struct Scsi_Host *h;
+ for (h = first_host; h && h->host_no != host; h = h->next);
+ if (!h) {
+ printk (KERN_ALERT "scsi%d not found\n", host);
+ return NULL;
+ } else if (h->hostt != the_template) {
+ printk (KERN_ALERT "scsi%d is not a NCR board\n", host);
+ return NULL;
+ }
+ return h;
+}
+
+/*
+ * Function : request_synchronous (int host, int target)
+ *
+ * Purpose : KGDB interface which will allow us to negotiate for
+ * synchronous transfers. This ill be replaced with a more
+ * integrated function; perhaps a new entry in the scsi_host
+ * structure, accessible via an ioctl() or perhaps /proc/scsi.
+ *
+ * Inputs : host - number of SCSI host; target - number of target.
+ *
+ * Returns : 0 when negotiation has been setup for next SCSI command,
+ * -1 on failure.
+ */
+
+static int
+request_synchronous (int host, int target) {
+ struct Scsi_Host *h;
+ struct NCR53c7x0_hostdata *hostdata;
+ unsigned long flags;
+ if (target < 0) {
+ printk (KERN_ALERT "target %d is bogus\n", target);
+ return -1;
+ }
+ if (!(h = find_host (host)))
+ return -1;
+ else if (h->this_id == target) {
+ printk (KERN_ALERT "target %d is host ID\n", target);
+ return -1;
+ }
+ else if (target > h->max_id) {
+ printk (KERN_ALERT "target %d exceeds maximum of %d\n", target,
+ h->max_id);
+ return -1;
+ }
+ hostdata = (struct NCR53c7x0_hostdata *)h->hostdata;
+
+ save_flags(flags);
+ cli();
+ if (hostdata->initiate_sdtr & (1 << target)) {
+ restore_flags(flags);
+ printk (KERN_ALERT "target %d already doing SDTR\n", target);
+ return -1;
+ }
+ hostdata->initiate_sdtr |= (1 << target);
+ restore_flags(flags);
+ return 0;
+}
+
+/*
+ * Function : request_disconnect (int host, int on_or_off)
+ *
+ * Purpose : KGDB support function, tells us to allow or disallow
+ * disconnections.
+ *
+ * Inputs : host - number of SCSI host; on_or_off - non-zero to allow,
+ * zero to disallow.
+ *
+ * Returns : 0 on success, * -1 on failure.
+ */
+
+static int
+request_disconnect (int host, int on_or_off) {
+ struct Scsi_Host *h;
+ struct NCR53c7x0_hostdata *hostdata;
+ if (!(h = find_host (host)))
+ return -1;
+ hostdata = (struct NCR53c7x0_hostdata *) h->hostdata;
+ if (on_or_off)
+ hostdata->options |= OPTION_DISCONNECT;
+ else
+ hostdata->options &= ~OPTION_DISCONNECT;
+ return 0;
+}
+
+/*
+ * Function : static void NCR53c7x0_driver_init (struct Scsi_Host *host)
+ *
+ * Purpose : Initialize internal structures, as required on startup, or
+ * after a SCSI bus reset.
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ */
+
+static void
+NCR53c7x0_driver_init (struct Scsi_Host *host) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ int i, j;
+ u32 *ncrcurrent;
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ for (i = 0; i < 16; ++i) {
+ hostdata->request_sense[i] = 0;
+ for (j = 0; j < 8; ++j)
+ hostdata->busy[i][j] = 0;
+ set_synchronous (host, i, /* sxfer */ 0, hostdata->saved_scntl3, 0);
+ }
+ hostdata->issue_queue = NULL;
+ hostdata->running_list = hostdata->finished_queue =
+ hostdata->ncrcurrent = NULL;
+ for (i = 0, ncrcurrent = (u32 *) hostdata->schedule;
+ i < host->can_queue; ++i, ncrcurrent += 2) {
+ ncrcurrent[0] = hostdata->NOP_insn;
+ ncrcurrent[1] = 0xdeadbeef;
+ }
+ ncrcurrent[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
+ ncrcurrent[1] = (u32) virt_to_bus (hostdata->script) +
+ hostdata->E_wait_reselect;
+ hostdata->reconnect_dsa_head = 0;
+ hostdata->addr_reconnect_dsa_head = (u32)
+ virt_to_bus((void *) &(hostdata->reconnect_dsa_head));
+ hostdata->expecting_iid = 0;
+ hostdata->expecting_sto = 0;
+ if (hostdata->options & OPTION_ALWAYS_SYNCHRONOUS)
+ hostdata->initiate_sdtr = 0xffff;
+ else
+ hostdata->initiate_sdtr = 0;
+ hostdata->talked_to = 0;
+ hostdata->idle = 1;
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+}
+
+/*
+ * Function : static int clock_to_ccf_710 (int clock)
+ *
+ * Purpose : Return the clock conversion factor for a given SCSI clock.
+ *
+ * Inputs : clock - SCSI clock expressed in Hz.
+ *
+ * Returns : ccf on success, -1 on failure.
+ */
+
+static int
+clock_to_ccf_710 (int clock) {
+ if (clock <= 16666666)
+ return -1;
+ if (clock <= 25000000)
+ return 2; /* Divide by 1.0 */
+ else if (clock <= 37500000)
+ return 1; /* Divide by 1.5 */
+ else if (clock <= 50000000)
+ return 0; /* Divide by 2.0 */
+ else if (clock <= 66000000)
+ return 3; /* Divide by 3.0 */
+ else
+ return -1;
+}
+
+/*
+ * Function : static int NCR53c7x0_init (struct Scsi_Host *host)
+ *
+ * Purpose : initialize the internal structures for a given SCSI host
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ *
+ * Preconditions : when this function is called, the chip_type
+ * field of the hostdata structure MUST have been set.
+ *
+ * Returns : 0 on success, -1 on failure.
+ */
+
+int
+NCR53c7x0_init (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ int i, ccf;
+ unsigned char revision;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ struct Scsi_Host *search;
+ /*
+ * There are some things which we need to know about in order to provide
+ * a semblance of support. Print 'em if they aren't what we expect,
+ * otherwise don't add to the noise.
+ *
+ * -1 means we don't know what to expect.
+ */
+ int val, flags;
+ char buf[32];
+ int expected_id = -1;
+ int expected_clock = -1;
+ int uninitialized = 0;
+#ifdef NO_IO_SPACE
+ int expected_mapping = OPTION_MEMORY_MAPPED;
+#else
+ int expected_mapping = OPTION_IO_MAPPED;
+#endif
+ for (i=0;i<7;i++)
+ hostdata->valid_ids[i] = 1; /* Default all ID's to scan */
+
+ /* Parse commandline flags */
+ if (check_setup_strings("nosync",&flags,&val,buf))
+ {
+ hostdata->options |= OPTION_NO_ASYNC;
+ hostdata->options &= ~(OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS);
+ }
+
+ if (check_setup_strings("nodisconnect",&flags,&val,buf))
+ hostdata->options &= ~OPTION_DISCONNECT;
+
+ if (check_setup_strings("validids",&flags,&val,buf))
+ {
+ for (i=0;i<7;i++)
+ hostdata->valid_ids[i] = val & (1<<i);
+ }
+
+ if ((i = check_setup_strings("next",&flags,&val,buf)))
+ {
+ while (i)
+ setup_used[--i] = 1;
+ }
+
+
+ NCR53c7x0_local_setup(host);
+
+ switch (hostdata->chip) {
+ case 710:
+ hostdata->dstat_sir_intr = NCR53c7x0_dstat_sir_intr;
+ hostdata->init_save_regs = NULL;
+ hostdata->dsa_fixup = NCR53c7xx_dsa_fixup;
+ hostdata->init_fixup = NCR53c7x0_init_fixup;
+ hostdata->soft_reset = NCR53c7x0_soft_reset;
+ hostdata->run_tests = NCR53c7xx_run_tests;
+ expected_clock = hostdata->scsi_clock = 50000000;
+ expected_id = 7;
+ break;
+ default:
+ printk ("scsi%d : chip type of %d is not supported yet, detaching.\n",
+ host->host_no, hostdata->chip);
+ scsi_unregister (host);
+ return -1;
+ }
+
+ /* Assign constants accessed by NCR */
+ hostdata->NCR53c7xx_zero = 0;
+ hostdata->NCR53c7xx_msg_reject = MESSAGE_REJECT;
+ hostdata->NCR53c7xx_msg_abort = ABORT;
+ hostdata->NCR53c7xx_msg_nop = NOP;
+ hostdata->NOP_insn = (DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24;
+
+ if (expected_mapping == -1 ||
+ (hostdata->options & (OPTION_MEMORY_MAPPED)) !=
+ (expected_mapping & OPTION_MEMORY_MAPPED))
+ printk ("scsi%d : using %s mapped access\n", host->host_no,
+ (hostdata->options & OPTION_MEMORY_MAPPED) ? "memory" :
+ "io");
+
+ hostdata->dmode = (hostdata->chip == 700 || hostdata->chip == 70066) ?
+ DMODE_REG_00 : DMODE_REG_10;
+ hostdata->istat = ((hostdata->chip / 100) == 8) ?
+ ISTAT_REG_800 : ISTAT_REG_700;
+
+/* Only the ISTAT register is readable when the NCR is running, so make
+ sure it's halted. */
+ ncr_halt(host);
+
+/*
+ * XXX - the NCR53c700 uses bitfielded registers for SCID, SDID, etc,
+ * as does the 710 with one bit per SCSI ID. Conversely, the NCR
+ * uses a normal, 3 bit binary representation of these values.
+ *
+ * Get the rest of the NCR documentation, and FIND OUT where the change
+ * was.
+ */
+
+#if 0
+ /* May not be able to do this - chip my not have been set up yet */
+ tmp = hostdata->this_id_mask = NCR53c7x0_read8(SCID_REG);
+ for (host->this_id = 0; tmp != 1; tmp >>=1, ++host->this_id);
+#else
+ host->this_id = 7;
+#endif
+
+/*
+ * Note : we should never encounter a board setup for ID0. So,
+ * if we see ID0, assume that it was uninitialized and set it
+ * to the industry standard 7.
+ */
+ if (!host->this_id) {
+ printk("scsi%d : initiator ID was %d, changing to 7\n",
+ host->host_no, host->this_id);
+ host->this_id = 7;
+ hostdata->this_id_mask = 1 << 7;
+ uninitialized = 1;
+ };
+
+ if (expected_id == -1 || host->this_id != expected_id)
+ printk("scsi%d : using initiator ID %d\n", host->host_no,
+ host->this_id);
+
+ /*
+ * Save important registers to allow a soft reset.
+ */
+
+ /*
+ * CTEST7 controls cache snooping, burst mode, and support for
+ * external differential drivers. This isn't currently used - the
+ * default value may not be optimal anyway.
+ * Even worse, it may never have been set up since reset.
+ */
+ hostdata->saved_ctest7 = NCR53c7x0_read8(CTEST7_REG) & CTEST7_SAVE;
+ revision = (NCR53c7x0_read8(CTEST8_REG) & 0xF0) >> 4;
+ switch (revision) {
+ case 1:
+ revision = 0;
+ break;
+ case 2:
+ revision = 1;
+ break;
+ case 4:
+ revision = 2;
+ break;
+ case 8:
+ revision = 3;
+ break;
+ default:
+ revision = 255;
+ break;
+ }
+ printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
+
+ /*
+ * On NCR53c700 series chips, DCNTL controls the SCSI clock divisor,
+ * on 800 series chips, it allows for a totem-pole IRQ driver.
+ * NOTE saved_dcntl currently overwritten in init function.
+ * The value read here may be garbage anyway, MVME166 board at least
+ * does not initialise chip if kernel arrived via tftp.
+ */
+
+ hostdata->saved_dcntl = NCR53c7x0_read8(DCNTL_REG);
+
+ /*
+ * DMODE controls DMA burst length, and on 700 series chips,
+ * 286 mode and bus width
+ * NOTE: On MVME166, chip may have been reset, so this could be a
+ * power-on/reset default value.
+ */
+ hostdata->saved_dmode = NCR53c7x0_read8(hostdata->dmode);
+
+ /*
+ * Now that burst length and enabled/disabled status is known,
+ * clue the user in on it.
+ */
+
+ ccf = clock_to_ccf_710 (expected_clock);
+
+ for (i = 0; i < 16; ++i)
+ hostdata->cmd_allocated[i] = 0;
+
+ if (hostdata->init_save_regs)
+ hostdata->init_save_regs (host);
+ if (hostdata->init_fixup)
+ hostdata->init_fixup (host);
+
+ if (!the_template) {
+ the_template = host->hostt;
+ first_host = host;
+ }
+
+ /*
+ * Linux SCSI drivers have always been plagued with initialization
+ * problems - some didn't work with the BIOS disabled since they expected
+ * initialization from it, some didn't work when the networking code
+ * was enabled and registers got scrambled, etc.
+ *
+ * To avoid problems like this, in the future, we will do a soft
+ * reset on the SCSI chip, taking it back to a sane state.
+ */
+
+ hostdata->soft_reset (host);
+
+#if 1
+ hostdata->debug_count_limit = -1;
+#else
+ hostdata->debug_count_limit = 1;
+#endif
+ hostdata->intrs = -1;
+ hostdata->resets = -1;
+ memcpy ((void *) hostdata->synchronous_want, (void *) sdtr_message,
+ sizeof (hostdata->synchronous_want));
+
+ NCR53c7x0_driver_init (host);
+
+ /*
+ * Set up an interrupt handler if we aren't already sharing an IRQ
+ * with another board.
+ */
+
+#ifdef CONFIG_MVME166
+ if (request_irq(IRQ_MVME166_SCSI, NCR53c7x0_intr, 0, "SCSI-script", NULL))
+ panic ("Couldn't get SCSI IRQ");
+#ifdef MVME166_INTFLY
+ else if (request_irq(IRQ_MVME166_FLY, NCR53c7x0_intr, 0, "SCSI-intfly", NULL))
+ panic ("Couldn't get INT_FLY IRQ");
+#endif
+#else
+ for (search = first_host; search && !(search->hostt == the_template &&
+ search->irq == host->irq && search != host); search=search->next);
+
+ if (!search) {
+#ifdef CONFIG_AMIGA
+ if (request_irq(IRQ_AMIGA_PORTS, NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr)) {
+#else
+ if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7xx", NULL)) {
+#endif
+ printk("scsi%d : IRQ%d not free, detaching\n"
+ " You have either a configuration problem, or a\n"
+ " broken BIOS. You may wish to manually assign\n"
+ " an interrupt to the NCR board rather than using\n"
+ " an automatic setting.\n",
+ host->host_no, host->irq);
+ scsi_unregister (host);
+ return -1;
+ }
+ } else {
+ printk("scsi%d : using interrupt handler previously installed for scsi%d\n",
+ host->host_no, search->host_no);
+ }
+#endif
+
+ if ((hostdata->run_tests && hostdata->run_tests(host) == -1) ||
+ (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) {
+ /* XXX Should disable interrupts, etc. here */
+ scsi_unregister (host);
+ return -1;
+ } else {
+ if (host->io_port) {
+ host->n_io_port = 128;
+ request_region (host->io_port, host->n_io_port, "ncr53c7xx");
+ }
+ }
+
+ if (NCR53c7x0_read8 (SBCL_REG) & SBCL_BSY) {
+ printk ("scsi%d : bus wedge, doing SCSI reset\n", host->host_no);
+ hard_reset (host);
+ }
+ return 0;
+}
+
+/*
+ * Function : static int normal_init(Scsi_Host_Template *tpnt, int board,
+ * int chip, u32 base, int io_port, int irq, int dma, int pcivalid,
+ * unsigned char pci_bus, unsigned char pci_device_fn,
+ * long long options);
+ *
+ * Purpose : initializes a NCR53c7,8x0 based on base addresses,
+ * IRQ, and DMA channel.
+ *
+ * Useful where a new NCR chip is backwards compatible with
+ * a supported chip, but the DEVICE ID has changed so it
+ * doesn't show up when the autoprobe does a pcibios_find_device.
+ *
+ * Inputs : tpnt - Template for this SCSI adapter, board - board level
+ * product, chip - 710
+ *
+ * Returns : 0 on success, -1 on failure.
+ *
+ */
+
+int
+ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
+ u32 base, int io_port, int irq, int dma, long long options, int clock)
+{
+ struct Scsi_Host *instance;
+ struct NCR53c7x0_hostdata *hostdata;
+ char chip_str[80];
+ int script_len = 0, dsa_len = 0, size = 0, max_cmd_size = 0,
+ schedule_size = 0, ok = 0;
+ void *tmp;
+
+ switch (chip) {
+ case 710:
+ schedule_size = (tpnt->can_queue + 1) * 8 /* JUMP instruction size */;
+ script_len = NCR53c7xx_script_len;
+ dsa_len = NCR53c7xx_dsa_len;
+ options |= OPTION_INTFLY;
+ sprintf (chip_str, "NCR53c%d", chip);
+ break;
+ default:
+ printk("scsi-ncr53c7xx : unsupported SCSI chip %d\n", chip);
+ return -1;
+ }
+
+ printk("scsi-ncr53c7xx : %s at memory 0x%x, io 0x%x, irq %d",
+ chip_str, (unsigned) base, io_port, irq);
+ if (dma == DMA_NONE)
+ printk("\n");
+ else
+ printk(", dma %d\n", dma);
+
+ if (options & OPTION_DEBUG_PROBE_ONLY) {
+ printk ("scsi-ncr53c7xx : probe only enabled, aborting initialization\n");
+ return -1;
+ }
+
+ max_cmd_size = sizeof(struct NCR53c7x0_cmd) + dsa_len +
+ /* Size of dynamic part of command structure : */
+ 2 * /* Worst case : we don't know if we need DATA IN or DATA out */
+ ( 2 * /* Current instructions per scatter/gather segment */
+ tpnt->sg_tablesize +
+ 3 /* Current startup / termination required per phase */
+ ) *
+ 8 /* Each instruction is eight bytes */;
+
+ /* Allocate fixed part of hostdata, dynamic part to hold appropriate
+ SCSI SCRIPT(tm) plus a single, maximum-sized NCR53c7x0_cmd structure.
+
+ We need a NCR53c7x0_cmd structure for scan_scsis() when we are
+ not loaded as a module, and when we're loaded as a module, we
+ can't use a non-dynamically allocated structure because modules
+ are vmalloc()'d, which can allow structures to cross page
+ boundaries and breaks our physical/virtual address assumptions
+ for DMA.
+
+ So, we stick it past the end of our hostdata structure.
+
+ ASSUMPTION :
+ Regardless of how many simultaneous SCSI commands we allow,
+ the probe code only executes a _single_ instruction at a time,
+ so we only need one here, and don't need to allocate NCR53c7x0_cmd
+ structures for each target until we are no longer in scan_scsis
+ and kmalloc() has become functional (memory_init() happens
+ after all device driver initialization).
+ */
+
+ size = sizeof(struct NCR53c7x0_hostdata) + script_len +
+ /* Note that alignment will be guaranteed, since we put the command
+ allocated at probe time after the fixed-up SCSI script, which
+ consists of 32 bit words, aligned on a 32 bit boundary. But
+ on a 64bit machine we need 8 byte alignment for hostdata->free, so
+ we add in another 4 bytes to take care of potential misalignment
+ */
+ (sizeof(void *) - sizeof(u32)) + max_cmd_size + schedule_size;
+
+#ifdef FORCE_DSA_ALIGNMENT
+ /*
+ * 53c710 rev.0 doesn't have an add-with-carry instruction.
+ * Ensure we allocate enough memory to force DSA alignment.
+ */
+ size += 256;
+#endif
+ flushsize = size;
+ instance = scsi_register (tpnt, size);
+ if (!instance)
+ return -1;
+
+ /* FIXME : if we ever support an ISA NCR53c7xx based board, we
+ need to check if the chip is running in a 16 bit mode, and if so
+ unregister it if it is past the 16M (0x1000000) mark */
+
+ hostdata = (struct NCR53c7x0_hostdata *)
+ instance->hostdata;
+ hostdata->size = size;
+ hostdata->script_count = script_len / sizeof(u32);
+ hostdata = (struct NCR53c7x0_hostdata *) instance->hostdata;
+ hostdata->board = board;
+ hostdata->chip = chip;
+
+ /*
+ * Being memory mapped is more desirable, since
+ *
+ * - Memory accesses may be faster.
+ *
+ * - The destination and source address spaces are the same for
+ * all instructions, meaning we don't have to twiddle dmode or
+ * any other registers.
+ *
+ * So, we try for memory mapped, and if we don't get it,
+ * we go for port mapped, and that failing we tell the user
+ * it can't work.
+ */
+
+ if (base) {
+ instance->base = (unsigned char *) (unsigned long) base;
+ /* Check for forced I/O mapping */
+ if (!(options & OPTION_IO_MAPPED)) {
+ options |= OPTION_MEMORY_MAPPED;
+ ok = 1;
+ }
+ } else {
+ options &= ~OPTION_MEMORY_MAPPED;
+ }
+
+ if (io_port) {
+ instance->io_port = io_port;
+ options |= OPTION_IO_MAPPED;
+ ok = 1;
+ } else {
+ options &= ~OPTION_IO_MAPPED;
+ }
+
+ if (!ok) {
+ printk ("scsi%d : not initializing, no I/O or memory mapping known \n",
+ instance->host_no);
+ scsi_unregister (instance);
+ return -1;
+ }
+ instance->irq = irq;
+ instance->dma_channel = dma;
+
+ hostdata->options = options;
+ hostdata->dsa_len = dsa_len;
+ hostdata->max_cmd_size = max_cmd_size;
+ hostdata->num_cmds = 1;
+ /* Initialize single command */
+ tmp = (hostdata->script + hostdata->script_count);
+#ifdef FORCE_DSA_ALIGNMENT
+ {
+ void *t = ROUNDUP(tmp, void *);
+ if (((u32)t & 0xff) > CmdPageStart)
+ t = (void *)((u32)t + 255);
+ t = (void *)(((u32)t & ~0xff) + CmdPageStart);
+ hostdata->free = t;
+ printk ("scsi: Registered size increased by 256 to %d\n", size);
+ printk ("scsi: CmdPageStart = 0x%02x\n", CmdPageStart);
+ printk ("scsi: tmp = 0x%08x, hostdata->free set to 0x%08x\n",
+ (u32)tmp, (u32)t);
+ }
+#else
+ hostdata->free = ROUNDUP(tmp, void *);
+#endif
+ hostdata->free->real = tmp;
+ hostdata->free->size = max_cmd_size;
+ hostdata->free->free = NULL;
+ hostdata->free->next = NULL;
+ hostdata->extra_allocate = 0;
+
+ /* Allocate command start code space */
+ hostdata->schedule = (chip == 700 || chip == 70066) ?
+ NULL : (u32 *) ((char *)hostdata->free + max_cmd_size);
+
+/*
+ * For diagnostic purposes, we don't really care how fast things blaze.
+ * For profiling, we want to access the 800ns resolution system clock,
+ * using a 'C' call on the host processor.
+ *
+ * Therefore, there's no need for the NCR chip to directly manipulate
+ * this data, and we should put it wherever is most convenient for
+ * Linux.
+ */
+ if (track_events)
+ hostdata->events = (struct NCR53c7x0_event *) (track_events ?
+ vmalloc (sizeof (struct NCR53c7x0_event) * track_events) : NULL);
+ else
+ hostdata->events = NULL;
+
+ if (hostdata->events) {
+ memset ((void *) hostdata->events, 0, sizeof(struct NCR53c7x0_event) *
+ track_events);
+ hostdata->event_size = track_events;
+ hostdata->event_index = 0;
+ } else
+ hostdata->event_size = 0;
+
+ return NCR53c7x0_init(instance);
+}
+
+
+/*
+ * Function : static void NCR53c7x0_init_fixup (struct Scsi_Host *host)
+ *
+ * Purpose : copy and fixup the SCSI SCRIPTS(tm) code for this device.
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ *
+ */
+
+static void
+NCR53c7x0_init_fixup (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ unsigned char tmp;
+ int i, ncr_to_memory, memory_to_ncr;
+ u32 base;
+ NCR53c7x0_local_setup(host);
+
+
+ /* XXX - NOTE : this code MUST be made endian aware */
+ /* Copy code into buffer that was allocated at detection time. */
+ memcpy ((void *) hostdata->script, (void *) SCRIPT,
+ sizeof(SCRIPT));
+ /* Fixup labels */
+ for (i = 0; i < PATCHES; ++i)
+ hostdata->script[LABELPATCHES[i]] +=
+ virt_to_bus(hostdata->script);
+ /* Fixup addresses of constants that used to be EXTERNAL */
+
+ patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_abort,
+ virt_to_bus(&(hostdata->NCR53c7xx_msg_abort)));
+ patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_reject,
+ virt_to_bus(&(hostdata->NCR53c7xx_msg_reject)));
+ patch_abs_32 (hostdata->script, 0, NCR53c7xx_zero,
+ virt_to_bus(&(hostdata->NCR53c7xx_zero)));
+ patch_abs_32 (hostdata->script, 0, NCR53c7xx_sink,
+ virt_to_bus(&(hostdata->NCR53c7xx_sink)));
+ patch_abs_32 (hostdata->script, 0, NOP_insn,
+ virt_to_bus(&(hostdata->NOP_insn)));
+ patch_abs_32 (hostdata->script, 0, schedule,
+ virt_to_bus((void *) hostdata->schedule));
+
+ /* Fixup references to external variables: */
+ for (i = 0; i < EXTERNAL_PATCHES_LEN; ++i)
+ hostdata->script[EXTERNAL_PATCHES[i].offset] +=
+ virt_to_bus(EXTERNAL_PATCHES[i].address);
+
+ /*
+ * Fixup absolutes set at boot-time.
+ *
+ * All non-code absolute variables suffixed with "dsa_" and "int_"
+ * are constants, and need no fixup provided the assembler has done
+ * it for us (I don't know what the "real" NCR assembler does in
+ * this case, my assembler does the right magic).
+ */
+
+ patch_abs_rwri_data (hostdata->script, 0, dsa_save_data_pointer,
+ Ent_dsa_code_save_data_pointer - Ent_dsa_zero);
+ patch_abs_rwri_data (hostdata->script, 0, dsa_restore_pointers,
+ Ent_dsa_code_restore_pointers - Ent_dsa_zero);
+ patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect,
+ Ent_dsa_code_check_reselect - Ent_dsa_zero);
+
+ /*
+ * Just for the hell of it, preserve the settings of
+ * Burst Length and Enable Read Line bits from the DMODE
+ * register. Make sure SCRIPTS start automagically.
+ */
+
+#if defined(CONFIG_MVME166)
+ /* We know better what we want than 166Bug does! */
+ tmp = DMODE_10_BL_8 | DMODE_10_FC2;
+#else
+ tmp = NCR53c7x0_read8(DMODE_REG_10);
+ tmp &= (DMODE_BL_MASK | DMODE_10_FC2 | DMODE_10_FC1 | DMODE_710_PD |
+ DMODE_710_UO);
+#endif
+
+ if (!(hostdata->options & OPTION_MEMORY_MAPPED)) {
+ base = (u32) host->io_port;
+ memory_to_ncr = tmp|DMODE_800_DIOM;
+ ncr_to_memory = tmp|DMODE_800_SIOM;
+ } else {
+ base = virt_to_bus(host->base);
+ memory_to_ncr = ncr_to_memory = tmp;
+ }
+
+ /* SCRATCHB_REG_10 == SCRATCHA_REG_800, as it happens */
+ patch_abs_32 (hostdata->script, 0, addr_scratch, base + SCRATCHA_REG_800);
+ patch_abs_32 (hostdata->script, 0, addr_temp, base + TEMP_REG);
+ patch_abs_32 (hostdata->script, 0, addr_dsa, base + DSA_REG);
+
+ /*
+ * I needed some variables in the script to be accessible to
+ * both the NCR chip and the host processor. For these variables,
+ * I made the arbitrary decision to store them directly in the
+ * hostdata structure rather than in the RELATIVE area of the
+ * SCRIPTS.
+ */
+
+
+ patch_abs_rwri_data (hostdata->script, 0, dmode_memory_to_memory, tmp);
+ patch_abs_rwri_data (hostdata->script, 0, dmode_memory_to_ncr, memory_to_ncr);
+ patch_abs_rwri_data (hostdata->script, 0, dmode_ncr_to_memory, ncr_to_memory);
+
+ patch_abs_32 (hostdata->script, 0, msg_buf,
+ virt_to_bus((void *)&(hostdata->msg_buf)));
+ patch_abs_32 (hostdata->script, 0, reconnect_dsa_head,
+ virt_to_bus((void *)&(hostdata->reconnect_dsa_head)));
+ patch_abs_32 (hostdata->script, 0, addr_reconnect_dsa_head,
+ virt_to_bus((void *)&(hostdata->addr_reconnect_dsa_head)));
+ patch_abs_32 (hostdata->script, 0, reselected_identify,
+ virt_to_bus((void *)&(hostdata->reselected_identify)));
+/* reselected_tag is currently unused */
+#if 0
+ patch_abs_32 (hostdata->script, 0, reselected_tag,
+ virt_to_bus((void *)&(hostdata->reselected_tag)));
+#endif
+
+ patch_abs_32 (hostdata->script, 0, test_dest,
+ virt_to_bus((void*)&hostdata->test_dest));
+ patch_abs_32 (hostdata->script, 0, test_src,
+ virt_to_bus(&hostdata->test_source));
+ patch_abs_32 (hostdata->script, 0, saved_dsa,
+ virt_to_bus(&hostdata->saved2_dsa));
+ patch_abs_32 (hostdata->script, 0, emulfly,
+ virt_to_bus(&hostdata->emulated_intfly));
+
+ patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect,
+ (unsigned char)(Ent_dsa_code_check_reselect - Ent_dsa_zero));
+
+/* These are for event logging; the ncr_event enum contains the
+ actual interrupt numbers. */
+#ifdef A_int_EVENT_SELECT
+ patch_abs_32 (hostdata->script, 0, int_EVENT_SELECT, (u32) EVENT_SELECT);
+#endif
+#ifdef A_int_EVENT_DISCONNECT
+ patch_abs_32 (hostdata->script, 0, int_EVENT_DISCONNECT, (u32) EVENT_DISCONNECT);
+#endif
+#ifdef A_int_EVENT_RESELECT
+ patch_abs_32 (hostdata->script, 0, int_EVENT_RESELECT, (u32) EVENT_RESELECT);
+#endif
+#ifdef A_int_EVENT_COMPLETE
+ patch_abs_32 (hostdata->script, 0, int_EVENT_COMPLETE, (u32) EVENT_COMPLETE);
+#endif
+#ifdef A_int_EVENT_IDLE
+ patch_abs_32 (hostdata->script, 0, int_EVENT_IDLE, (u32) EVENT_IDLE);
+#endif
+#ifdef A_int_EVENT_SELECT_FAILED
+ patch_abs_32 (hostdata->script, 0, int_EVENT_SELECT_FAILED,
+ (u32) EVENT_SELECT_FAILED);
+#endif
+#ifdef A_int_EVENT_BEFORE_SELECT
+ patch_abs_32 (hostdata->script, 0, int_EVENT_BEFORE_SELECT,
+ (u32) EVENT_BEFORE_SELECT);
+#endif
+#ifdef A_int_EVENT_RESELECT_FAILED
+ patch_abs_32 (hostdata->script, 0, int_EVENT_RESELECT_FAILED,
+ (u32) EVENT_RESELECT_FAILED);
+#endif
+
+ /*
+ * Make sure the NCR and Linux code agree on the location of
+ * certain fields.
+ */
+
+ hostdata->E_accept_message = Ent_accept_message;
+ hostdata->E_command_complete = Ent_command_complete;
+ hostdata->E_cmdout_cmdout = Ent_cmdout_cmdout;
+ hostdata->E_data_transfer = Ent_data_transfer;
+ hostdata->E_debug_break = Ent_debug_break;
+ hostdata->E_dsa_code_template = Ent_dsa_code_template;
+ hostdata->E_dsa_code_template_end = Ent_dsa_code_template_end;
+ hostdata->E_end_data_transfer = Ent_end_data_transfer;
+ hostdata->E_initiator_abort = Ent_initiator_abort;
+ hostdata->E_msg_in = Ent_msg_in;
+ hostdata->E_other_transfer = Ent_other_transfer;
+ hostdata->E_other_in = Ent_other_in;
+ hostdata->E_other_out = Ent_other_out;
+ hostdata->E_reject_message = Ent_reject_message;
+ hostdata->E_respond_message = Ent_respond_message;
+ hostdata->E_select = Ent_select;
+ hostdata->E_select_msgout = Ent_select_msgout;
+ hostdata->E_target_abort = Ent_target_abort;
+#ifdef Ent_test_0
+ hostdata->E_test_0 = Ent_test_0;
+#endif
+ hostdata->E_test_1 = Ent_test_1;
+ hostdata->E_test_2 = Ent_test_2;
+#ifdef Ent_test_3
+ hostdata->E_test_3 = Ent_test_3;
+#endif
+ hostdata->E_wait_reselect = Ent_wait_reselect;
+ hostdata->E_dsa_code_begin = Ent_dsa_code_begin;
+
+ hostdata->dsa_cmdout = A_dsa_cmdout;
+ hostdata->dsa_cmnd = A_dsa_cmnd;
+ hostdata->dsa_datain = A_dsa_datain;
+ hostdata->dsa_dataout = A_dsa_dataout;
+ hostdata->dsa_end = A_dsa_end;
+ hostdata->dsa_msgin = A_dsa_msgin;
+ hostdata->dsa_msgout = A_dsa_msgout;
+ hostdata->dsa_msgout_other = A_dsa_msgout_other;
+ hostdata->dsa_next = A_dsa_next;
+ hostdata->dsa_select = A_dsa_select;
+ hostdata->dsa_start = Ent_dsa_code_template - Ent_dsa_zero;
+ hostdata->dsa_status = A_dsa_status;
+ hostdata->dsa_jump_dest = Ent_dsa_code_fix_jump - Ent_dsa_zero +
+ 8 /* destination operand */;
+
+ /* sanity check */
+ if (A_dsa_fields_start != Ent_dsa_code_template_end -
+ Ent_dsa_zero)
+ printk("scsi%d : NCR dsa_fields start is %d not %d\n",
+ host->host_no, A_dsa_fields_start, Ent_dsa_code_template_end -
+ Ent_dsa_zero);
+
+ printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no,
+ virt_to_bus(hostdata->script), hostdata->script);
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+}
+
+/*
+ * Function : static int NCR53c7xx_run_tests (struct Scsi_Host *host)
+ *
+ * Purpose : run various verification tests on the NCR chip,
+ * including interrupt generation, and proper bus mastering
+ * operation.
+ *
+ * Inputs : host - a properly initialized Scsi_Host structure
+ *
+ * Preconditions : the NCR chip must be in a halted state.
+ *
+ * Returns : 0 if all tests were successful, -1 on error.
+ *
+ */
+
+static int
+NCR53c7xx_run_tests (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ unsigned long timeout;
+ u32 start;
+ int failed, i;
+ unsigned long flags;
+ NCR53c7x0_local_setup(host);
+
+ /* The NCR chip _must_ be idle to run the test scripts */
+
+ save_flags(flags);
+ cli();
+ if (!hostdata->idle) {
+ printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
+ restore_flags(flags);
+ return -1;
+ }
+
+ /*
+ * Check for functional interrupts, this could work as an
+ * autoprobe routine.
+ */
+
+ if ((hostdata->options & OPTION_DEBUG_TEST1) &&
+ hostdata->state != STATE_DISABLED) {
+ hostdata->idle = 0;
+ hostdata->test_running = 1;
+ hostdata->test_completed = -1;
+ hostdata->test_dest = 0;
+ hostdata->test_source = 0xdeadbeef;
+ start = virt_to_bus (hostdata->script) + hostdata->E_test_1;
+ hostdata->state = STATE_RUNNING;
+ printk ("scsi%d : test 1", host->host_no);
+ flush_cache_all();
+ cache_push(virt_to_bus(hostdata->script), flushsize);
+ cache_clear(virt_to_bus(hostdata->script), flushsize);
+ NCR53c7x0_write32 (DSP_REG, start);
+ if (hostdata->options & OPTION_DEBUG_TRACE)
+ NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM |
+ DCNTL_STD);
+ printk (" started\n");
+ sti();
+
+ /*
+ * This is currently a .5 second timeout, since (in theory) no slow
+ * board will take that long. In practice, we've seen one
+ * pentium which occassionally fails with this, but works with
+ * 10 times as much?
+ */
+
+ timeout = jiffies + 5 * HZ / 10;
+ while ((hostdata->test_completed == -1) && jiffies < timeout)
+ barrier();
+
+ failed = 1;
+ if (hostdata->test_completed == -1)
+ printk ("scsi%d : driver test 1 timed out%s\n",host->host_no ,
+ (hostdata->test_dest == 0xdeadbeef) ?
+ " due to lost interrupt.\n"
+ " Please verify that the correct IRQ is being used for your board,\n"
+ : "");
+ else if (hostdata->test_completed != 1)
+ printk ("scsi%d : test 1 bad interrupt value (%d)\n",
+ host->host_no, hostdata->test_completed);
+ else
+ failed = (hostdata->test_dest != 0xdeadbeef);
+
+ if (hostdata->test_dest != 0xdeadbeef) {
+ printk ("scsi%d : driver test 1 read 0x%x instead of 0xdeadbeef indicating a\n"
+ " probable cache invalidation problem. Please configure caching\n"
+ " as write-through or disabled\n",
+ host->host_no, hostdata->test_dest);
+ }
+
+ if (failed) {
+ printk ("scsi%d : DSP = 0x%p (script at 0x%p, start at 0x%x)\n",
+ host->host_no, bus_to_virt(NCR53c7x0_read32(DSP_REG)),
+ hostdata->script, start);
+ printk ("scsi%d : DSPS = 0x%x\n", host->host_no,
+ NCR53c7x0_read32(DSPS_REG));
+ restore_flags(flags);
+ return -1;
+ }
+ hostdata->test_running = 0;
+ }
+
+ if ((hostdata->options & OPTION_DEBUG_TEST2) &&
+ hostdata->state != STATE_DISABLED) {
+ u32 dsa[48];
+ unsigned char identify = IDENTIFY(0, 0);
+ unsigned char cmd[6];
+ unsigned char data[36];
+ unsigned char status = 0xff;
+ unsigned char msg = 0xff;
+
+ cmd[0] = INQUIRY;
+ cmd[1] = cmd[2] = cmd[3] = cmd[5] = 0;
+ cmd[4] = sizeof(data);
+
+ dsa[2] = 1;
+ dsa[3] = virt_to_bus(&identify);
+ dsa[4] = 6;
+ dsa[5] = virt_to_bus(&cmd);
+ dsa[6] = sizeof(data);
+ dsa[7] = virt_to_bus(&data);
+ dsa[8] = 1;
+ dsa[9] = virt_to_bus(&status);
+ dsa[10] = 1;
+ dsa[11] = virt_to_bus(&msg);
+
+ for (i = 0; i < 6; ++i) {
+#ifdef VALID_IDS
+ if (!hostdata->valid_ids[i])
+ continue;
+#endif
+ cli();
+ if (!hostdata->idle) {
+ printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
+ restore_flags(flags);
+ return -1;
+ }
+
+ /* 710: bit mapped scsi ID, async */
+ dsa[0] = (1 << i) << 16;
+ hostdata->idle = 0;
+ hostdata->test_running = 2;
+ hostdata->test_completed = -1;
+ start = virt_to_bus(hostdata->script) + hostdata->E_test_2;
+ hostdata->state = STATE_RUNNING;
+ flush_cache_all();
+ cache_clear(virt_to_bus(hostdata->script), flushsize);
+ NCR53c7x0_write32 (DSA_REG, virt_to_bus(dsa));
+ NCR53c7x0_write32 (DSP_REG, start);
+ if (hostdata->options & OPTION_DEBUG_TRACE)
+ NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
+ DCNTL_SSM | DCNTL_STD);
+ sti();
+
+ timeout = jiffies + 5 * HZ; /* arbitrary */
+ while ((hostdata->test_completed == -1) && jiffies < timeout)
+ barrier();
+
+ NCR53c7x0_write32 (DSA_REG, 0);
+
+ if (hostdata->test_completed == 2) {
+ data[35] = 0;
+ printk ("scsi%d : test 2 INQUIRY to target %d, lun 0 : %s\n",
+ host->host_no, i, data + 8);
+ printk ("scsi%d : status ", host->host_no);
+ print_status (status);
+ printk ("\nscsi%d : message ", host->host_no);
+ print_msg (&msg);
+ printk ("\n");
+ } else if (hostdata->test_completed == 3) {
+ printk("scsi%d : test 2 no connection with target %d\n",
+ host->host_no, i);
+ if (!hostdata->idle) {
+ printk("scsi%d : not idle\n", host->host_no);
+ restore_flags(flags);
+ return -1;
+ }
+ } else if (hostdata->test_completed == -1) {
+ printk ("scsi%d : test 2 timed out\n", host->host_no);
+ restore_flags(flags);
+ return -1;
+ }
+ hostdata->test_running = 0;
+ }
+ }
+
+ restore_flags(flags);
+ return 0;
+}
+
+/*
+ * Function : static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : copy the NCR53c8xx dsa structure into cmd's dsa buffer,
+ * performing all necessary relocation.
+ *
+ * Inputs : cmd, a NCR53c7x0_cmd structure with a dsa area large
+ * enough to hold the NCR53c8xx dsa.
+ */
+
+static void
+NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
+ Scsi_Cmnd *c = cmd->cmd;
+ struct Scsi_Host *host = c->host;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ int i;
+
+ memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
+ hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template);
+
+ /*
+ * Note : within the NCR 'C' code, dsa points to the _start_
+ * of the DSA structure, and _not_ the offset of dsa_zero within
+ * that structure used to facilitate shorter signed offsets
+ * for the 8 bit ALU.
+ *
+ * The implications of this are that
+ *
+ * - 32 bit A_dsa_* absolute values require an additional
+ * dsa_zero added to their value to be correct, since they are
+ * relative to dsa_zero which is in essentially a separate
+ * space from the code symbols.
+ *
+ * - All other symbols require no special treatment.
+ */
+
+ patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_lun, c->lun);
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_addr_next, virt_to_bus(&cmd->dsa_next_addr));
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_next, virt_to_bus(cmd->dsa) + Ent_dsa_zero -
+ Ent_dsa_code_template + A_dsa_next);
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_sync, virt_to_bus((void *)hostdata->sync[c->target].script));
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_sscf_710, virt_to_bus((void *)&hostdata->sync[c->target].sscf_710));
+ patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_target, 1 << c->target);
+ /* XXX - new pointer stuff */
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_addr_saved_pointer, virt_to_bus(&cmd->saved_data_pointer));
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_addr_saved_residual, virt_to_bus(&cmd->saved_residual));
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_addr_residual, virt_to_bus(&cmd->residual));
+
+ /* XXX - new start stuff */
+
+ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+ dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+}
+
+/*
+ * Function : run_process_issue_queue (void)
+ *
+ * Purpose : insure that the coroutine is running and will process our
+ * request. process_issue_queue_running is checked/set here (in an
+ * inline function) rather than in process_issue_queue itself to reduce
+ * the chances of stack overflow.
+ *
+ */
+
+static volatile int process_issue_queue_running = 0;
+
+static __inline__ void
+run_process_issue_queue(void) {
+ unsigned long flags;
+ save_flags (flags);
+ cli();
+ if (!process_issue_queue_running) {
+ process_issue_queue_running = 1;
+ process_issue_queue(flags);
+ /*
+ * process_issue_queue_running is cleared in process_issue_queue
+ * once it can't do more work, and process_issue_queue exits with
+ * interrupts disabled.
+ */
+ }
+ restore_flags (flags);
+}
+
+/*
+ * Function : static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int
+ * result)
+ *
+ * Purpose : mark SCSI command as finished, OR'ing the host portion
+ * of the result word into the result field of the corresponding
+ * Scsi_Cmnd structure, and removing it from the internal queues.
+ *
+ * Inputs : cmd - command, result - entire result field
+ *
+ * Preconditions : the NCR chip should be in a halted state when
+ * abnormal_finished is run, since it modifies structures which
+ * the NCR expects to have exclusive access to.
+ */
+
+static void
+abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
+ Scsi_Cmnd *c = cmd->cmd;
+ struct Scsi_Host *host = c->host;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ unsigned long flags;
+ int left, found;
+ volatile struct NCR53c7x0_cmd * linux_search;
+ volatile struct NCR53c7x0_cmd * volatile *linux_prev;
+ volatile u32 *ncr_prev, *ncrcurrent, ncr_search;
+
+#if 0
+ printk ("scsi%d: abnormal finished\n", host->host_no);
+#endif
+
+ save_flags(flags);
+ cli();
+ found = 0;
+ /*
+ * Traverse the NCR issue array until we find a match or run out
+ * of instructions. Instructions in the NCR issue array are
+ * either JUMP or NOP instructions, which are 2 words in length.
+ */
+
+
+ for (found = 0, left = host->can_queue, ncrcurrent = hostdata->schedule;
+ left > 0; --left, ncrcurrent += 2)
+ {
+ if (issue_to_cmd (host, hostdata, (u32 *) ncrcurrent) == cmd)
+ {
+ ncrcurrent[0] = hostdata->NOP_insn;
+ ncrcurrent[1] = 0xdeadbeef;
+ ++found;
+ break;
+ }
+ }
+
+ /*
+ * Traverse the NCR reconnect list of DSA structures until we find
+ * a pointer to this dsa or have found too many command structures.
+ * We let prev point at the next field of the previous element or
+ * head of the list, so we don't do anything different for removing
+ * the head element.
+ */
+
+ for (left = host->can_queue,
+ ncr_search = hostdata->reconnect_dsa_head,
+ ncr_prev = &hostdata->reconnect_dsa_head;
+ left >= 0 && ncr_search &&
+ ((char*)bus_to_virt(ncr_search) + hostdata->dsa_start)
+ != (char *) cmd->dsa;
+ ncr_prev = (u32*) ((char*)bus_to_virt(ncr_search) +
+ hostdata->dsa_next), ncr_search = *ncr_prev, --left);
+
+ if (left < 0)
+ printk("scsi%d: loop detected in ncr reconncect list\n",
+ host->host_no);
+ else if (ncr_search)
+ if (found)
+ printk("scsi%d: scsi %ld in ncr issue array and reconnect lists\n",
+ host->host_no, c->pid);
+ else {
+ volatile u32 * next = (u32 *)
+ ((char *)bus_to_virt(ncr_search) + hostdata->dsa_next);
+ *ncr_prev = *next;
+/* If we're at the tail end of the issue queue, update that pointer too. */
+ found = 1;
+ }
+
+ /*
+ * Traverse the host running list until we find this command or discover
+ * we have too many elements, pointing linux_prev at the next field of the
+ * linux_previous element or head of the list, search at this element.
+ */
+
+ for (left = host->can_queue, linux_search = hostdata->running_list,
+ linux_prev = &hostdata->running_list;
+ left >= 0 && linux_search && linux_search != cmd;
+ linux_prev = &(linux_search->next),
+ linux_search = linux_search->next, --left);
+
+ if (left < 0)
+ printk ("scsi%d: loop detected in host running list for scsi pid %ld\n",
+ host->host_no, c->pid);
+ else if (linux_search) {
+ *linux_prev = linux_search->next;
+ --hostdata->busy[c->target][c->lun];
+ }
+
+ /* Return the NCR command structure to the free list */
+ cmd->next = hostdata->free;
+ hostdata->free = cmd;
+ c->host_scribble = NULL;
+
+ /* And return */
+ c->result = result;
+ c->scsi_done(c);
+
+ restore_flags(flags);
+ run_process_issue_queue();
+}
+
+/*
+ * Function : static void intr_break (struct Scsi_Host *host,
+ * struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : Handler for breakpoint interrupts from a SCSI script
+ *
+ * Inputs : host - pointer to this host adapter's structure,
+ * cmd - pointer to the command (if any) dsa was pointing
+ * to.
+ *
+ */
+
+static void
+intr_break (struct Scsi_Host *host, struct
+ NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_break *bp;
+#if 0
+ Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
+#endif
+ u32 *dsp;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ unsigned long flags;
+ NCR53c7x0_local_setup(host);
+
+ /*
+ * Find the break point corresponding to this address, and
+ * dump the appropriate debugging information to standard
+ * output.
+ */
+ save_flags(flags);
+ cli();
+ flush_cache_all();
+ cache_push(virt_to_bus(hostdata->script), flushsize);
+ dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
+ for (bp = hostdata->breakpoints; bp && bp->address != dsp;
+ bp = bp->next);
+ if (!bp)
+ panic("scsi%d : break point interrupt from %p with no breakpoint!",
+ host->host_no, dsp);
+
+ /*
+ * Configure the NCR chip for manual start mode, so that we can
+ * point the DSP register at the instruction that follows the
+ * INT int_debug_break instruction.
+ */
+
+ NCR53c7x0_write8 (hostdata->dmode,
+ NCR53c7x0_read8(hostdata->dmode)|DMODE_MAN);
+
+ /*
+ * And update the DSP register, using the size of the old
+ * instruction in bytes.
+ */
+
+ restore_flags(flags);
+}
+/*
+ * Function : static void print_synchronous (const char *prefix,
+ * const unsigned char *msg)
+ *
+ * Purpose : print a pretty, user and machine parsable representation
+ * of a SDTR message, including the "real" parameters, data
+ * clock so we can tell transfer rate at a glance.
+ *
+ * Inputs ; prefix - text to prepend, msg - SDTR message (5 bytes)
+ */
+
+static void
+print_synchronous (const char *prefix, const unsigned char *msg) {
+ if (msg[4]) {
+ int Hz = 1000000000 / (msg[3] * 4);
+ int integer = Hz / 1000000;
+ int fraction = (Hz - (integer * 1000000)) / 10000;
+ printk ("%speriod %dns offset %d %d.%02dMHz %s SCSI%s\n",
+ prefix, (int) msg[3] * 4, (int) msg[4], integer, fraction,
+ (((msg[3] * 4) < 200) ? "FAST" : "synchronous"),
+ (((msg[3] * 4) < 200) ? "-II" : ""));
+ } else
+ printk ("%sasynchronous SCSI\n", prefix);
+}
+
+/*
+ * Function : static void set_synchronous (struct Scsi_Host *host,
+ * int target, int sxfer, int scntl3, int now_connected)
+ *
+ * Purpose : reprogram transfers between the selected SCSI initiator and
+ * target with the given register values; in the indirect
+ * select operand, reselection script, and chip registers.
+ *
+ * Inputs : host - NCR53c7,8xx SCSI host, target - number SCSI target id,
+ * sxfer and scntl3 - NCR registers. now_connected - if non-zero,
+ * we should reprogram the registers now too.
+ *
+ * NOTE: For 53c710, scntl3 is actually used for SCF bits from
+ * SBCL, as we don't have a SCNTL3.
+ */
+
+static void
+set_synchronous (struct Scsi_Host *host, int target, int sxfer, int scntl3,
+ int now_connected) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ u32 *script;
+ NCR53c7x0_local_setup(host);
+
+ /* These are eight bit registers */
+ sxfer &= 0xff;
+ scntl3 &= 0xff;
+
+ hostdata->sync[target].sxfer_sanity = sxfer;
+ hostdata->sync[target].scntl3_sanity = scntl3;
+
+/*
+ * HARD CODED : synchronous script is EIGHT words long. This
+ * must agree with 53c7.8xx.h
+ */
+
+ if ((hostdata->chip != 700) && (hostdata->chip != 70066)) {
+ hostdata->sync[target].select_indirect = (1 << target) << 16 |
+ (sxfer << 8);
+ hostdata->sync[target].sscf_710 = scntl3;
+
+ script = (u32 *) hostdata->sync[target].script;
+
+ /* XXX - add NCR53c7x0 code to reprogram SCF bits if we want to */
+ script[0] = ((DCMD_TYPE_RWRI | DCMD_RWRI_OPC_MODIFY |
+ DCMD_RWRI_OP_MOVE) << 24) |
+ (SBCL_REG << 16) | (scntl3 << 8);
+ script[1] = 0;
+ script += 2;
+
+ script[0] = ((DCMD_TYPE_RWRI | DCMD_RWRI_OPC_MODIFY |
+ DCMD_RWRI_OP_MOVE) << 24) |
+ (SXFER_REG << 16) | (sxfer << 8);
+ script[1] = 0;
+ script += 2;
+
+#ifdef DEBUG_SYNC_INTR
+ if (hostdata->options & OPTION_DEBUG_DISCONNECT) {
+ script[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_INT) << 24) | DBC_TCI_TRUE;
+ script[1] = DEBUG_SYNC_INTR;
+ script += 2;
+ }
+#endif
+
+ script[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_RETURN) << 24) | DBC_TCI_TRUE;
+ script[1] = 0;
+ script += 2;
+ }
+
+ if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS)
+ printk ("scsi%d : target %d sync parameters are sxfer=0x%x, scntl3=0x%x\n",
+ host->host_no, target, sxfer, scntl3);
+
+ if (now_connected) {
+ NCR53c7x0_write8(SBCL_REG, scntl3);
+ NCR53c7x0_write8(SXFER_REG, sxfer);
+ }
+}
+
+
+/*
+ * Function : static int asynchronous (struct Scsi_Host *host, int target)
+ *
+ * Purpose : reprogram between the selected SCSI Host adapter and target
+ * (assumed to be currently connected) for asynchronous transfers.
+ *
+ * Inputs : host - SCSI host structure, target - numeric target ID.
+ *
+ * Preconditions : the NCR chip should be in one of the halted states
+ */
+
+static void
+asynchronous (struct Scsi_Host *host, int target) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ NCR53c7x0_local_setup(host);
+ set_synchronous (host, target, /* no offset */ 0, hostdata->saved_scntl3,
+ 1);
+ printk ("scsi%d : setting target %d to asynchronous SCSI\n",
+ host->host_no, target);
+}
+
+/*
+ * XXX - do we want to go out of our way (ie, add extra code to selection
+ * in the NCR53c710/NCR53c720 script) to reprogram the synchronous
+ * conversion bits, or can we be content in just setting the
+ * sxfer bits? I chose to do so [richard@sleepie.demon.co.uk]
+ */
+
+/* Table for NCR53c8xx synchronous values */
+
+/* This table is also correct for 710, allowing that scf=4 is equivalent
+ * of SSCF=0 (ie use DCNTL, divide by 3) for a 50.01-66.00MHz clock.
+ * For any other clock values, we cannot use entries with SCF values of
+ * 4. I guess that for a 66MHz clock, the slowest it will set is 2MHz,
+ * and for a 50MHz clock, the slowest will be 2.27Mhz. Should check
+ * that a device doesn't try and negotiate sync below these limits!
+ */
+
+static const struct {
+ int div; /* Total clock divisor * 10 */
+ unsigned char scf; /* */
+ unsigned char tp; /* 4 + tp = xferp divisor */
+} syncs[] = {
+/* div scf tp div scf tp div scf tp */
+ { 40, 1, 0}, { 50, 1, 1}, { 60, 1, 2},
+ { 70, 1, 3}, { 75, 2, 1}, { 80, 1, 4},
+ { 90, 1, 5}, { 100, 1, 6}, { 105, 2, 3},
+ { 110, 1, 7}, { 120, 2, 4}, { 135, 2, 5},
+ { 140, 3, 3}, { 150, 2, 6}, { 160, 3, 4},
+ { 165, 2, 7}, { 180, 3, 5}, { 200, 3, 6},
+ { 210, 4, 3}, { 220, 3, 7}, { 240, 4, 4},
+ { 270, 4, 5}, { 300, 4, 6}, { 330, 4, 7}
+};
+
+/*
+ * Function : static void synchronous (struct Scsi_Host *host, int target,
+ * char *msg)
+ *
+ * Purpose : reprogram transfers between the selected SCSI initiator and
+ * target for synchronous SCSI transfers such that the synchronous
+ * offset is less than that requested and period at least as long
+ * as that requested. Also modify *msg such that it contains
+ * an appropriate response.
+ *
+ * Inputs : host - NCR53c7,8xx SCSI host, target - number SCSI target id,
+ * msg - synchronous transfer request.
+ */
+
+
+static void
+synchronous (struct Scsi_Host *host, int target, char *msg) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ int desire, divisor, i, limit;
+ unsigned char scntl3, sxfer;
+/* The diagnostic message fits on one line, even with max. width integers */
+ char buf[80];
+
+/* Desired transfer clock in Hz */
+ desire = 1000000000L / (msg[3] * 4);
+/* Scale the available SCSI clock by 10 so we get tenths */
+ divisor = (hostdata->scsi_clock * 10) / desire;
+
+/* NCR chips can handle at most an offset of 8 */
+ if (msg[4] > 8)
+ msg[4] = 8;
+
+ if (hostdata->options & OPTION_DEBUG_SDTR)
+ printk("scsi%d : optimal synchronous divisor of %d.%01d\n",
+ host->host_no, divisor / 10, divisor % 10);
+
+ limit = (sizeof(syncs) / sizeof(syncs[0]) -1);
+ for (i = 0; (i < limit) && (divisor > syncs[i].div); ++i);
+
+ if (hostdata->options & OPTION_DEBUG_SDTR)
+ printk("scsi%d : selected synchronous divisor of %d.%01d\n",
+ host->host_no, syncs[i].div / 10, syncs[i].div % 10);
+
+ msg[3] = ((1000000000L / hostdata->scsi_clock) * syncs[i].div / 10 / 4);
+
+ if (hostdata->options & OPTION_DEBUG_SDTR)
+ printk("scsi%d : selected synchronous period of %dns\n", host->host_no,
+ msg[3] * 4);
+
+ scntl3 = syncs[i].scf;
+ sxfer = (msg[4] << SXFER_MO_SHIFT) | (syncs[i].tp << 4);
+ if (hostdata->options & OPTION_DEBUG_SDTR)
+ printk ("scsi%d : sxfer=0x%x scntl3=0x%x\n",
+ host->host_no, (int) sxfer, (int) scntl3);
+ set_synchronous (host, target, sxfer, scntl3, 1);
+ sprintf (buf, "scsi%d : setting target %d to ", host->host_no, target);
+ print_synchronous (buf, msg);
+}
+
+/*
+ * Function : static int NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host,
+ * struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : Handler for INT generated instructions for the
+ * NCR53c810/820 SCSI SCRIPT
+ *
+ * Inputs : host - pointer to this host adapter's structure,
+ * cmd - pointer to the command (if any) dsa was pointing
+ * to.
+ *
+ */
+
+static int
+NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
+ NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ int print;
+ Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ u32 dsps,*dsp; /* Argument of the INT instruction */
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ NCR53c7x0_local_setup(host);
+ dsps = NCR53c7x0_read32(DSPS_REG);
+ dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
+
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : DSPS = 0x%x\n", host->host_no, dsps);
+
+ switch (dsps) {
+ case A_int_msg_1:
+ print = 1;
+ switch (hostdata->msg_buf[0]) {
+ /*
+ * Unless we've initiated synchronous negotiation, I don't
+ * think that this should happen.
+ */
+ case MESSAGE_REJECT:
+ hostdata->dsp = hostdata->script + hostdata->E_accept_message /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ if (cmd && (cmd->flags & CMD_FLAG_SDTR)) {
+ printk ("scsi%d : target %d rejected SDTR\n", host->host_no,
+ c->target);
+ cmd->flags &= ~CMD_FLAG_SDTR;
+ asynchronous (host, c->target);
+ print = 0;
+ }
+ break;
+ case INITIATE_RECOVERY:
+ printk ("scsi%d : extended contingent allegiance not supported yet, rejecting\n",
+ host->host_no);
+ /* Fall through to default */
+ hostdata->dsp = hostdata->script + hostdata->E_reject_message /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ break;
+ default:
+ printk ("scsi%d : unsupported message, rejecting\n",
+ host->host_no);
+ hostdata->dsp = hostdata->script + hostdata->E_reject_message /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ }
+ if (print) {
+ printk ("scsi%d : received message", host->host_no);
+ if (c)
+ printk (" from target %d lun %d ", c->target, c->lun);
+ print_msg ((unsigned char *) hostdata->msg_buf);
+ printk("\n");
+ }
+
+ return SPECIFIC_INT_NOTHING;
+
+
+ case A_int_msg_sdtr:
+/*
+ * At this point, hostdata->msg_buf contains
+ * 0 EXTENDED MESSAGE
+ * 1 length
+ * 2 SDTR
+ * 3 period * 4ns
+ * 4 offset
+ */
+
+ if (cmd) {
+ char buf[80];
+ sprintf (buf, "scsi%d : target %d %s ", host->host_no, c->target,
+ (cmd->flags & CMD_FLAG_SDTR) ? "accepting" : "requesting");
+ print_synchronous (buf, (unsigned char *) hostdata->msg_buf);
+
+ /*
+ * Initiator initiated, won't happen unless synchronous
+ * transfers are enabled. If we get a SDTR message in
+ * response to our SDTR, we should program our parameters
+ * such that
+ * offset <= requested offset
+ * period >= requested period
+ */
+ if (cmd->flags & CMD_FLAG_SDTR) {
+ cmd->flags &= ~CMD_FLAG_SDTR;
+ if (hostdata->msg_buf[4])
+ synchronous (host, c->target, (unsigned char *)
+ hostdata->msg_buf);
+ else
+ asynchronous (host, c->target);
+ hostdata->dsp = hostdata->script + hostdata->E_accept_message /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ return SPECIFIC_INT_NOTHING;
+ } else {
+ if (hostdata->options & OPTION_SYNCHRONOUS) {
+ cmd->flags |= CMD_FLAG_DID_SDTR;
+ synchronous (host, c->target, (unsigned char *)
+ hostdata->msg_buf);
+ } else {
+ hostdata->msg_buf[4] = 0; /* 0 offset = async */
+ asynchronous (host, c->target);
+ }
+ patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
+ patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, (u32)
+ virt_to_bus ((void *)&hostdata->msg_buf));
+ hostdata->dsp = hostdata->script +
+ hostdata->E_respond_message / sizeof(u32);
+ hostdata->dsp_changed = 1;
+ }
+ return SPECIFIC_INT_NOTHING;
+ }
+ /* Fall through to abort if we couldn't find a cmd, and
+ therefore a dsa structure to twiddle */
+ case A_int_msg_wdtr:
+ hostdata->dsp = hostdata->script + hostdata->E_reject_message /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ return SPECIFIC_INT_NOTHING;
+ case A_int_err_unexpected_phase:
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : unexpected phase\n", host->host_no);
+ return SPECIFIC_INT_ABORT;
+ case A_int_err_selected:
+ if ((hostdata->chip / 100) == 8)
+ printk ("scsi%d : selected by target %d\n", host->host_no,
+ (int) NCR53c7x0_read8(SDID_REG_800) &7);
+ else
+ printk ("scsi%d : selected by target LCRC=0x%02x\n", host->host_no,
+ (int) NCR53c7x0_read8(LCRC_REG_10));
+ hostdata->dsp = hostdata->script + hostdata->E_target_abort /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ return SPECIFIC_INT_NOTHING;
+ case A_int_err_unexpected_reselect:
+ if ((hostdata->chip / 100) == 8)
+ printk ("scsi%d : unexpected reselect by target %d lun %d\n",
+ host->host_no, (int) NCR53c7x0_read8(SDID_REG_800) & 7,
+ hostdata->reselected_identify & 7);
+ else
+ printk ("scsi%d : unexpected reselect LCRC=0x%02x\n", host->host_no,
+ (int) NCR53c7x0_read8(LCRC_REG_10));
+ hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ return SPECIFIC_INT_NOTHING;
+/*
+ * Since contingent allegiance conditions are cleared by the next
+ * command issued to a target, we must issue a REQUEST SENSE
+ * command after receiving a CHECK CONDITION status, before
+ * another command is issued.
+ *
+ * Since this NCR53c7x0_cmd will be freed after use, we don't
+ * care if we step on the various fields, so modify a few things.
+ */
+ case A_int_err_check_condition:
+#if 0
+ if (hostdata->options & OPTION_DEBUG_INTR)
+#endif
+ printk ("scsi%d : CHECK CONDITION\n", host->host_no);
+ if (!c) {
+ printk("scsi%d : CHECK CONDITION with no SCSI command\n",
+ host->host_no);
+ return SPECIFIC_INT_PANIC;
+ }
+
+ /*
+ * FIXME : this uses the normal one-byte selection message.
+ * We may want to renegotiate for synchronous & WIDE transfers
+ * since these could be the crux of our problem.
+ *
+ hostdata->NOP_insn* FIXME : once SCSI-II tagged queuing is implemented, we'll
+ * have to set this up so that the rest of the DSA
+ * agrees with this being an untagged queue'd command.
+ */
+
+ patch_dsa_32 (cmd->dsa, dsa_msgout, 0, 1);
+
+ /*
+ * Modify the table indirect for COMMAND OUT phase, since
+ * Request Sense is a six byte command.
+ */
+
+ patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, 6);
+
+ c->cmnd[0] = REQUEST_SENSE;
+ c->cmnd[1] &= 0xe0; /* Zero all but LUN */
+ c->cmnd[2] = 0;
+ c->cmnd[3] = 0;
+ c->cmnd[4] = sizeof(c->sense_buffer);
+ c->cmnd[5] = 0;
+
+ /*
+ * Disable dataout phase, and program datain to transfer to the
+ * sense buffer, and add a jump to other_transfer after the
+ * command so overflow/underrun conditions are detected.
+ */
+
+ patch_dsa_32 (cmd->dsa, dsa_dataout, 0,
+ virt_to_bus(hostdata->script) + hostdata->E_other_transfer);
+ patch_dsa_32 (cmd->dsa, dsa_datain, 0,
+ virt_to_bus(cmd->data_transfer_start));
+ cmd->data_transfer_start[0] = (((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I |
+ DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer);
+ cmd->data_transfer_start[1] = (u32) virt_to_bus(c->sense_buffer);
+
+ cmd->data_transfer_start[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP)
+ << 24) | DBC_TCI_TRUE;
+ cmd->data_transfer_start[3] = (u32) virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer;
+
+ /*
+ * Currently, this command is flagged as completed, ie
+ * it has valid status and message data. Reflag it as
+ * incomplete. Q - need to do something so that original
+ * status, etc are used.
+ */
+
+ cmd->cmd->result = 0xffff;
+
+ /*
+ * Restart command as a REQUEST SENSE.
+ */
+ hostdata->dsp = (u32 *) hostdata->script + hostdata->E_select /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ return SPECIFIC_INT_NOTHING;
+ case A_int_debug_break:
+ return SPECIFIC_INT_BREAK;
+ case A_int_norm_aborted:
+ hostdata->dsp = (u32 *) hostdata->schedule;
+ hostdata->dsp_changed = 1;
+ if (cmd)
+ abnormal_finished (cmd, DID_ERROR << 16);
+ return SPECIFIC_INT_NOTHING;
+ case A_int_norm_emulateintfly:
+ /* I'm not sure this is the right ! thing to do, but it works
+ * with the A4000T when copyback is disabled, and also the
+ * WarpEngine with copyback enabled, so it looks as though
+ * it does work to some extent.
+ *
+ * RGH: I don't really like it - You get an interrupt which
+ * calls NCR53c7x0_intr(), which calls this function (via
+ * intr_dma()), which calls NCR53c7x0_intr().....
+ * Anyway lets see how it goes for now.
+ */
+ hostdata->emulated_intfly = 1;
+ NCR53c7x0_intr(host->irq, NULL, NULL);
+ return SPECIFIC_INT_NOTHING;
+ case A_int_test_1:
+ case A_int_test_2:
+ hostdata->idle = 1;
+ hostdata->test_completed = (dsps - A_int_test_1) / 0x00010000 + 1;
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk("scsi%d : test%d complete\n", host->host_no,
+ hostdata->test_completed);
+ return SPECIFIC_INT_NOTHING;
+#ifdef A_int_debug_reselected_ok
+ case A_int_debug_reselected_ok:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+ OPTION_DEBUG_DISCONNECT)) {
+ /*
+ * Note - this dsa is not based on location relative to
+ * the command structure, but to location relative to the
+ * DSA register
+ */
+ u32 *dsa;
+ dsa = (u32 *) bus_to_virt (NCR53c7x0_read32(DSA_REG));
+
+ printk("scsi%d : reselected_ok (DSA = 0x%x (virt 0x%p)\n",
+ host->host_no, NCR53c7x0_read32(DSA_REG), dsa);
+ printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
+ host->host_no, cmd->saved_data_pointer,
+ bus_to_virt(cmd->saved_data_pointer));
+ print_insn (host, hostdata->script + Ent_reselected_ok /
+ sizeof(u32), "", 1);
+ if ((hostdata->chip / 100) == 8)
+ printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
+ host->host_no, NCR53c7x0_read8(SXFER_REG),
+ NCR53c7x0_read8(SCNTL3_REG_800));
+ else
+ printk ("scsi%d : sxfer=0x%x, cannot read SBCL\n",
+ host->host_no, NCR53c7x0_read8(SXFER_REG));
+ if (c) {
+ print_insn (host, (u32 *)
+ hostdata->sync[c->target].script, "", 1);
+ print_insn (host, (u32 *)
+ hostdata->sync[c->target].script + 2, "", 1);
+ }
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_reselect_check
+ case A_int_debug_reselect_check:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+ u32 *dsa;
+#if 0
+ u32 *code;
+#endif
+ /*
+ * Note - this dsa is not based on location relative to
+ * the command structure, but to location relative to the
+ * DSA register
+ */
+ dsa = bus_to_virt (NCR53c7x0_read32(DSA_REG));
+ printk("scsi%d : reselected_check_next (DSA = 0x%lx (virt 0x%p))\n",
+ host->host_no, virt_to_bus(dsa), dsa);
+ if (dsa) {
+ printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
+ host->host_no, cmd->saved_data_pointer,
+ bus_to_virt (cmd->saved_data_pointer));
+#if 0
+ printk("scsi%d : template code :\n", host->host_no);
+ for (code = dsa + (Ent_dsa_code_check_reselect - Ent_dsa_zero)
+ / sizeof(u32); code < (dsa + Ent_dsa_zero / sizeof(u32));
+ code += print_insn (host, code, "", 1));
+#endif
+ }
+ print_insn (host, hostdata->script + Ent_reselected_ok /
+ sizeof(u32), "", 1);
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_dsa_schedule
+ case A_int_debug_dsa_schedule:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+ u32 *dsa;
+ /*
+ * Note - this dsa is not based on location relative to
+ * the command structure, but to location relative to the
+ * DSA register
+ */
+ dsa = (u32 *) bus_to_virt (NCR53c7x0_read32(DSA_REG));
+ printk("scsi%d : dsa_schedule (old DSA = 0x%lx (virt 0x%p))\n",
+ host->host_no, virt_to_bus(dsa), dsa);
+ if (dsa)
+ printk("scsi%d : resume address is 0x%x (virt 0x%p)\n"
+ " (temp was 0x%x (virt 0x%p))\n",
+ host->host_no, cmd->saved_data_pointer,
+ bus_to_virt (cmd->saved_data_pointer),
+ NCR53c7x0_read32 (TEMP_REG),
+ bus_to_virt (NCR53c7x0_read32(TEMP_REG)));
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_scheduled
+ case A_int_debug_scheduled:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+ printk("scsi%d : new I/O 0x%x (virt 0x%p) scheduled\n",
+ host->host_no, NCR53c7x0_read32(DSA_REG),
+ bus_to_virt(NCR53c7x0_read32(DSA_REG)));
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_idle
+ case A_int_debug_idle:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+ printk("scsi%d : idle\n", host->host_no);
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_cmd
+ case A_int_debug_cmd:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+ printk("scsi%d : command sent\n");
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_dsa_loaded
+ case A_int_debug_dsa_loaded:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+ printk("scsi%d : DSA loaded with 0x%x (virt 0x%p)\n", host->host_no,
+ NCR53c7x0_read32(DSA_REG),
+ bus_to_virt(NCR53c7x0_read32(DSA_REG)));
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_reselected
+ case A_int_debug_reselected:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+ OPTION_DEBUG_DISCONNECT)) {
+ if ((hostdata->chip / 100) == 8)
+ printk("scsi%d : reselected by target %d lun %d\n",
+ host->host_no, (int) NCR53c7x0_read8(SDID_REG_800) & ~0x80,
+ (int) hostdata->reselected_identify & 7);
+ else
+ printk("scsi%d : reselected by LCRC=0x%02x lun %d\n",
+ host->host_no, (int) NCR53c7x0_read8(LCRC_REG_10),
+ (int) hostdata->reselected_identify & 7);
+ print_queues(host);
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_disconnect_msg
+ case A_int_debug_disconnect_msg:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+ if (c)
+ printk("scsi%d : target %d lun %d disconnecting\n",
+ host->host_no, c->target, c->lun);
+ else
+ printk("scsi%d : unknown target disconnecting\n",
+ host->host_no);
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_disconnected
+ case A_int_debug_disconnected:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+ OPTION_DEBUG_DISCONNECT)) {
+ printk ("scsi%d : disconnected, new queues are\n",
+ host->host_no);
+ print_queues(host);
+#if 0
+ /* Not valid on ncr53c710! */
+ printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
+ host->host_no, NCR53c7x0_read8(SXFER_REG),
+ NCR53c7x0_read8(SCNTL3_REG_800));
+#endif
+ if (c) {
+ print_insn (host, (u32 *)
+ hostdata->sync[c->target].script, "", 1);
+ print_insn (host, (u32 *)
+ hostdata->sync[c->target].script + 2, "", 1);
+ }
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_panic
+ case A_int_debug_panic:
+ printk("scsi%d : int_debug_panic received\n", host->host_no);
+ print_lots (host);
+ return SPECIFIC_INT_PANIC;
+#endif
+#ifdef A_int_debug_saved
+ case A_int_debug_saved:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+ OPTION_DEBUG_DISCONNECT)) {
+ printk ("scsi%d : saved data pointer 0x%x (virt 0x%p)\n",
+ host->host_no, cmd->saved_data_pointer,
+ bus_to_virt (cmd->saved_data_pointer));
+ print_progress (c);
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_restored
+ case A_int_debug_restored:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+ OPTION_DEBUG_DISCONNECT)) {
+ if (cmd) {
+ int size;
+ printk ("scsi%d : restored data pointer 0x%x (virt 0x%p)\n",
+ host->host_no, cmd->saved_data_pointer, bus_to_virt (
+ cmd->saved_data_pointer));
+ size = print_insn (host, (u32 *)
+ bus_to_virt(cmd->saved_data_pointer), "", 1);
+ size = print_insn (host, (u32 *)
+ bus_to_virt(cmd->saved_data_pointer) + size, "", 1);
+ print_progress (c);
+ }
+#if 0
+ printk ("scsi%d : datapath residual %d\n",
+ host->host_no, datapath_residual (host)) ;
+#endif
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_sync
+ case A_int_debug_sync:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+ OPTION_DEBUG_DISCONNECT|OPTION_DEBUG_SDTR)) {
+ unsigned char sxfer = NCR53c7x0_read8 (SXFER_REG), scntl3;
+ if ((hostdata->chip / 100) == 8) {
+ scntl3 = NCR53c7x0_read8 (SCNTL3_REG_800);
+ if (c) {
+ if (sxfer != hostdata->sync[c->target].sxfer_sanity ||
+ scntl3 != hostdata->sync[c->target].scntl3_sanity) {
+ printk ("scsi%d : sync sanity check failed sxfer=0x%x, scntl3=0x%x",
+ host->host_no, sxfer, scntl3);
+ NCR53c7x0_write8 (SXFER_REG, sxfer);
+ NCR53c7x0_write8 (SCNTL3_REG_800, scntl3);
+ }
+ } else
+ printk ("scsi%d : unknown command sxfer=0x%x, scntl3=0x%x\n",
+ host->host_no, (int) sxfer, (int) scntl3);
+ } else {
+ if (c) {
+ if (sxfer != hostdata->sync[c->target].sxfer_sanity) {
+ printk ("scsi%d : sync sanity check failed sxfer=0x%x",
+ host->host_no, sxfer);
+ NCR53c7x0_write8 (SXFER_REG, sxfer);
+ NCR53c7x0_write8 (SBCL_REG,
+ hostdata->sync[c->target].sscf_710);
+ }
+ } else
+ printk ("scsi%d : unknown command sxfer=0x%x\n",
+ host->host_no, (int) sxfer);
+ }
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_datain
+ case A_int_debug_datain:
+ if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+ OPTION_DEBUG_DISCONNECT|OPTION_DEBUG_SDTR)) {
+ int size;
+ if ((hostdata->chip / 100) == 8)
+ printk ("scsi%d : In do_datain (%s) sxfer=0x%x, scntl3=0x%x\n"
+ " datapath residual=%d\n",
+ host->host_no, sbcl_to_phase (NCR53c7x0_read8 (SBCL_REG)),
+ (int) NCR53c7x0_read8(SXFER_REG),
+ (int) NCR53c7x0_read8(SCNTL3_REG_800),
+ datapath_residual (host)) ;
+ else
+ printk ("scsi%d : In do_datain (%s) sxfer=0x%x\n"
+ " datapath residual=%d\n",
+ host->host_no, sbcl_to_phase (NCR53c7x0_read8 (SBCL_REG)),
+ (int) NCR53c7x0_read8(SXFER_REG),
+ datapath_residual (host)) ;
+ print_insn (host, dsp, "", 1);
+ size = print_insn (host, (u32 *) bus_to_virt(dsp[1]), "", 1);
+ print_insn (host, (u32 *) bus_to_virt(dsp[1]) + size, "", 1);
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_check_dsa
+ case A_int_debug_check_dsa:
+ if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
+ int sdid;
+ int tmp;
+ char *where;
+ if (hostdata->chip / 100 == 8)
+ sdid = NCR53c7x0_read8 (SDID_REG_800) & 15;
+ else {
+ tmp = NCR53c7x0_read8 (SDID_REG_700);
+ if (!tmp)
+ panic ("SDID_REG_700 = 0");
+ tmp >>= 1;
+ sdid = 0;
+ while (tmp) {
+ tmp >>= 1;
+ sdid++;
+ }
+ }
+ where = dsp - NCR53c7x0_insn_size(NCR53c7x0_read8
+ (DCMD_REG)) == hostdata->script +
+ Ent_select_check_dsa / sizeof(u32) ?
+ "selection" : "reselection";
+ if (c && sdid != c->target) {
+ printk ("scsi%d : SDID target %d != DSA target %d at %s\n",
+ host->host_no, sdid, c->target, where);
+ print_lots(host);
+ dump_events (host, 20);
+ return SPECIFIC_INT_PANIC;
+ }
+ }
+ return SPECIFIC_INT_RESTART;
+#endif
+ default:
+ if ((dsps & 0xff000000) == 0x03000000) {
+ printk ("scsi%d : misc debug interrupt 0x%x\n",
+ host->host_no, dsps);
+ return SPECIFIC_INT_RESTART;
+ } else if ((dsps & 0xff000000) == 0x05000000) {
+ if (hostdata->events) {
+ struct NCR53c7x0_event *event;
+ ++hostdata->event_index;
+ if (hostdata->event_index >= hostdata->event_size)
+ hostdata->event_index = 0;
+ event = (struct NCR53c7x0_event *) hostdata->events +
+ hostdata->event_index;
+ event->event = (enum ncr_event) dsps;
+ event->dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+ if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
+ if (hostdata->chip / 100 == 8)
+ event->target = NCR53c7x0_read8(SSID_REG_800);
+ else {
+ unsigned char tmp, sdid;
+ tmp = NCR53c7x0_read8 (SDID_REG_700);
+ if (!tmp)
+ panic ("SDID_REG_700 = 0");
+ tmp >>= 1;
+ sdid = 0;
+ while (tmp) {
+ tmp >>= 1;
+ sdid++;
+ }
+ event->target = sdid;
+ }
+ }
+ else
+ event->target = 255;
+
+ if (event->event == EVENT_RESELECT)
+ event->lun = hostdata->reselected_identify & 0xf;
+ else if (c)
+ event->lun = c->lun;
+ else
+ event->lun = 255;
+ do_gettimeofday(&(event->time));
+ if (c) {
+ event->pid = c->pid;
+ memcpy ((void *) event->cmnd, (void *) c->cmnd,
+ sizeof (event->cmnd));
+ } else {
+ event->pid = -1;
+ }
+ }
+ return SPECIFIC_INT_RESTART;
+ }
+
+ printk ("scsi%d : unknown user interrupt 0x%x\n",
+ host->host_no, (unsigned) dsps);
+ return SPECIFIC_INT_PANIC;
+ }
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+}
+
+/*
+ * XXX - the stock NCR assembler won't output the scriptu.h file,
+ * which undefine's all #define'd CPP symbols from the script.h
+ * file, which will create problems if you use multiple scripts
+ * with the same symbol names.
+ *
+ * If you insist on using NCR's assembler, you could generate
+ * scriptu.h from script.h using something like
+ *
+ * grep #define script.h | \
+ * sed 's/#define[ ][ ]*\([_a-zA-Z][_a-zA-Z0-9]*\).*$/#undefine \1/' \
+ * > scriptu.h
+ */
+
+#include "53c7xx_u.h"
+
+/* XXX - add alternate script handling code here */
+
+
+/*
+ * Function : static void NCR537xx_soft_reset (struct Scsi_Host *host)
+ *
+ * Purpose : perform a soft reset of the NCR53c7xx chip
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ *
+ * Preconditions : NCR53c7x0_init must have been called for this
+ * host.
+ *
+ */
+
+static void
+NCR53c7x0_soft_reset (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ unsigned long flags;
+#ifdef CONFIG_MVME166
+ volatile unsigned long v;
+#endif
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ NCR53c7x0_local_setup(host);
+
+ save_flags(flags);
+ cli();
+
+ /* Disable scsi chip and s/w level 7 ints */
+
+#ifdef CONFIG_MVME166
+ v = *(volatile unsigned long *)0xfff4006c;
+ v &= ~0x8000;
+ *(volatile unsigned long *)0xfff4006c = v;
+ v = *(volatile unsigned long *)0xfff4202c;
+ v &= ~0x10;
+ *(volatile unsigned long *)0xfff4202c = v;
+#else
+ /* Anything specific for your hardware? */
+#endif
+
+ /*
+ * Do a soft reset of the chip so that everything is
+ * reinitialized to the power-on state.
+ *
+ * Basically follow the procedure outlined in the NCR53c700
+ * data manual under Chapter Six, How to Use, Steps Necessary to
+ * Start SCRIPTS, with the exception of actually starting the
+ * script and setting up the synchronous transfer gunk.
+ */
+
+ /* Should we reset the scsi bus here??????????????????? */
+
+ NCR53c7x0_write8(ISTAT_REG_700, ISTAT_10_SRST);
+ NCR53c7x0_write8(ISTAT_REG_700, 0);
+
+ /*
+ * saved_dcntl is set up in NCR53c7x0_init() before it is overwritten
+ * here. We should have some better way of working out the CF bit
+ * setting..
+ */
+
+ hostdata->saved_dcntl = DCNTL_10_EA|DCNTL_10_COM;
+ if (hostdata->scsi_clock > 50000000)
+ hostdata->saved_dcntl |= DCNTL_700_CF_3;
+ else
+ if (hostdata->scsi_clock > 37500000)
+ hostdata->saved_dcntl |= DCNTL_700_CF_2;
+#if 0
+ else
+ /* Any clocks less than 37.5MHz? */
+#endif
+
+ if (hostdata->options & OPTION_DEBUG_TRACE)
+ NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM);
+ else
+ NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl);
+#if 0
+ /* Following disables snooping - run with caches disabled at first */
+ NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD);
+#else
+ /* Setup CTEST7 for SC1=0, SC0=1 - sink/source data without invalidating
+ * cache lines. */
+ NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD|CTEST7_10_SC0);
+#endif
+ /* Actually burst of eight, according to my 53c710 databook */
+ NCR53c7x0_write8(hostdata->dmode, DMODE_10_BL_8 | DMODE_10_FC2);
+ NCR53c7x0_write8(SCID_REG, 1 << host->this_id);
+ NCR53c7x0_write8(SBCL_REG, 0);
+ NCR53c7x0_write8(SCNTL1_REG, SCNTL1_ESR_700);
+ NCR53c7x0_write8(SCNTL0_REG, ((hostdata->options & OPTION_PARITY) ?
+ SCNTL0_EPC : 0) | SCNTL0_EPG_700 | SCNTL0_ARB1 | SCNTL0_ARB2);
+
+ /*
+ * Enable all interrupts, except parity which we only want when
+ * the user requests it.
+ */
+
+ NCR53c7x0_write8(DIEN_REG, DIEN_700_BF |
+ DIEN_ABRT | DIEN_SSI | DIEN_SIR | DIEN_700_OPC);
+
+ NCR53c7x0_write8(SIEN_REG_700, ((hostdata->options & OPTION_PARITY) ?
+ SIEN_PAR : 0) | SIEN_700_STO | SIEN_RST | SIEN_UDC |
+ SIEN_SGE | SIEN_MA);
+
+#ifdef CONFIG_MVME166
+ /* Enable scsi chip and s/w level 7 ints */
+
+ v = *(volatile unsigned long *)0xfff40080;
+ v = (v & ~(0xf << 28)) | (4 << 28);
+ *(volatile unsigned long *)0xfff40080 = v;
+ v = *(volatile unsigned long *)0xfff4006c;
+ v |= 0x8000;
+ *(volatile unsigned long *)0xfff4006c = v;
+ v = *(volatile unsigned long *)0xfff4202c;
+ v = (v & ~0xff) | 0x10 | 4;
+ *(volatile unsigned long *)0xfff4202c = v;
+#else
+ /* Anything needed for your hardware */
+#endif
+ restore_flags(flags);
+}
+
+
+/*
+ * Function static struct NCR53c7x0_cmd *allocate_cmd (Scsi_Cmnd *cmd)
+ *
+ * Purpose : Return the first free NCR53c7x0_cmd structure (which are
+ * reused in a LIFO manner to minimize cache thrashing).
+ *
+ * Side effects : If we haven't yet scheduled allocation of NCR53c7x0_cmd
+ * structures for this device, do so. Attempt to complete all scheduled
+ * allocations using kmalloc(), putting NCR53c7x0_cmd structures on
+ * the free list. Teach programmers not to drink and hack.
+ *
+ * Inputs : cmd - SCSI command
+ *
+ * Returns : NCR53c7x0_cmd structure allocated on behalf of cmd;
+ * NULL on failure.
+ */
+
+static struct NCR53c7x0_cmd *
+allocate_cmd (Scsi_Cmnd *cmd) {
+ struct Scsi_Host *host = cmd->host;
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata;
+ void *real; /* Real address */
+ int size; /* Size of *tmp */
+ struct NCR53c7x0_cmd *tmp;
+ unsigned long flags;
+
+ if (hostdata->options & OPTION_DEBUG_ALLOCATION)
+ printk ("scsi%d : num_cmds = %d, can_queue = %d\n"
+ " target = %d, lun = %d, %s\n",
+ host->host_no, hostdata->num_cmds, host->can_queue,
+ cmd->target, cmd->lun, (hostdata->cmd_allocated[cmd->target] &
+ (1 << cmd->lun)) ? "already allocated" : "not allocated");
+
+/*
+ * If we have not yet reserved commands for this I_T_L nexus, and
+ * the device exists (as indicated by permanent Scsi_Cmnd structures
+ * being allocated under 1.3.x, or being outside of scan_scsis in
+ * 1.2.x), do so now.
+ */
+ if (!(hostdata->cmd_allocated[cmd->target] & (1 << cmd->lun)) &&
+ cmd->device && cmd->device->has_cmdblocks) {
+ if ((hostdata->extra_allocate + hostdata->num_cmds) < host->can_queue)
+ hostdata->extra_allocate += host->cmd_per_lun;
+ hostdata->cmd_allocated[cmd->target] |= (1 << cmd->lun);
+ }
+
+ for (; hostdata->extra_allocate > 0 ; --hostdata->extra_allocate,
+ ++hostdata->num_cmds) {
+ /* historically, kmalloc has returned unaligned addresses; pad so we
+ have enough room to ROUNDUP */
+ size = hostdata->max_cmd_size + sizeof (void *);
+#ifdef FORCE_DSA_ALIGNMENT
+ /*
+ * 53c710 rev.0 doesn't have an add-with-carry instruction.
+ * Ensure we allocate enough memory to force alignment.
+ */
+ size += 256;
+#endif
+/* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */
+ real = kmalloc (size, GFP_ATOMIC);
+ if (!real) {
+ if (hostdata->options & OPTION_DEBUG_ALLOCATION)
+ printk ("scsi%d : kmalloc(%d) failed\n",
+ host->host_no, size);
+ break;
+ }
+ tmp = ROUNDUP(real, void *);
+#ifdef FORCE_DSA_ALIGNMENT
+ {
+ if (((u32)tmp & 0xff) > CmdPageStart)
+ tmp = (struct NCR53c7x0_cmd *)((u32)tmp + 255);
+ tmp = (struct NCR53c7x0_cmd *)(((u32)tmp & ~0xff) + CmdPageStart);
+#ifdef DEBUG
+ printk ("scsi: size = %d, real = 0x%08x, tmp set to 0x%08x\n",
+ size, (u32)real, (u32)tmp);
+#endif
+ }
+#endif
+ tmp->real = real;
+ tmp->size = size;
+ tmp->free = ((void (*)(void *, int)) kfree);
+ save_flags (flags);
+ cli();
+ tmp->next = hostdata->free;
+ hostdata->free = tmp;
+ restore_flags (flags);
+ }
+ save_flags(flags);
+ cli();
+ tmp = (struct NCR53c7x0_cmd *) hostdata->free;
+ if (tmp) {
+ hostdata->free = tmp->next;
+ }
+ restore_flags(flags);
+ if (!tmp)
+ printk ("scsi%d : can't allocate command for target %d lun %d\n",
+ host->host_no, cmd->target, cmd->lun);
+ return tmp;
+}
+
+/*
+ * Function static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd)
+ *
+ *
+ * Purpose : allocate a NCR53c7x0_cmd structure, initialize it based on the
+ * Scsi_Cmnd structure passed in cmd, including dsa and Linux field
+ * initialization, and dsa code relocation.
+ *
+ * Inputs : cmd - SCSI command
+ *
+ * Returns : NCR53c7x0_cmd structure corresponding to cmd,
+ * NULL on failure.
+ */
+static struct NCR53c7x0_cmd *
+create_cmd (Scsi_Cmnd *cmd) {
+ NCR53c7x0_local_declare();
+ struct Scsi_Host *host = cmd->host;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ struct NCR53c7x0_cmd *tmp; /* NCR53c7x0_cmd structure for this command */
+ int datain, /* Number of instructions per phase */
+ dataout;
+ int data_transfer_instructions, /* Count of dynamic instructions */
+ i; /* Counter */
+ u32 *cmd_datain, /* Address of datain/dataout code */
+ *cmd_dataout; /* Incremented as we assemble */
+#ifdef notyet
+ unsigned char *msgptr; /* Current byte in select message */
+ int msglen; /* Length of whole select message */
+#endif
+ unsigned long flags;
+ u32 exp_select_indirect; /* Used in sanity check */
+ NCR53c7x0_local_setup(cmd->host);
+
+ if (!(tmp = allocate_cmd (cmd)))
+ return NULL;
+
+
+ /*
+ * Decide whether we need to generate commands for DATA IN,
+ * DATA OUT, neither, or both based on the SCSI command
+ */
+
+ switch (cmd->cmnd[0]) {
+ /* These commands do DATA IN */
+ case INQUIRY:
+ case MODE_SENSE:
+ case READ_6:
+ case READ_10:
+ case READ_CAPACITY:
+ case REQUEST_SENSE:
+ datain = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
+ dataout = 0;
+ break;
+ /* These commands do DATA OUT */
+ case MODE_SELECT:
+ case WRITE_6:
+ case WRITE_10:
+ case START_STOP: /* also SCAN, which may do DATA OUT */
+#if 0
+ printk("scsi%d : command is ", host->host_no);
+ print_command(cmd->cmnd);
+#endif
+#if 0
+ printk ("scsi%d : %d scatter/gather segments\n", host->host_no,
+ cmd->use_sg);
+#endif
+ datain = 0;
+ dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
+#if 0
+ hostdata->options |= OPTION_DEBUG_INTR;
+#endif
+ break;
+ /*
+ * These commands do no data transfer, we should force an
+ * interrupt if a data phase is attempted on them.
+ */
+ case TEST_UNIT_READY:
+ datain = dataout = 0;
+ break;
+ /*
+ * We don't know about these commands, so generate code to handle
+ * both DATA IN and DATA OUT phases.
+ */
+ default:
+ datain = dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
+ }
+
+ /*
+ * New code : so that active pointers work correctly regardless
+ * of where the saved data pointer is at, we want to immediately
+ * enter the dynamic code after selection, and on a non-data
+ * phase perform a CALL to the non-data phase handler, with
+ * returns back to this address.
+ *
+ * If a phase mismatch is encountered in the middle of a
+ * Block MOVE instruction, we want to _leave_ that instruction
+ * unchanged as the current case is, modify a temporary buffer,
+ * and point the active pointer (TEMP) at that.
+ *
+ * Furthermore, we want to implement a saved data pointer,
+ * set by the SAVE_DATA_POINTERs message.
+ *
+ * So, the data transfer segments will change to
+ * CALL data_transfer, WHEN NOT data phase
+ * MOVE x, x, WHEN data phase
+ * ( repeat )
+ * JUMP other_transfer
+ */
+
+ data_transfer_instructions = datain + dataout;
+
+ /*
+ * When we perform a request sense, we overwrite various things,
+ * including the data transfer code. Make sure we have enough
+ * space to do that.
+ */
+
+ if (data_transfer_instructions < 2)
+ data_transfer_instructions = 2;
+
+
+ /*
+ * The saved data pointer is set up so that a RESTORE POINTERS message
+ * will start the data transfer over at the begining.
+ */
+
+ tmp->saved_data_pointer = virt_to_bus (hostdata->script) +
+ hostdata->E_data_transfer;
+
+ /*
+ * Initialize Linux specific fields.
+ */
+
+ tmp->cmd = cmd;
+ tmp->next = NULL;
+ tmp->flags = 0;
+ tmp->dsa_next_addr = virt_to_bus(tmp->dsa) + hostdata->dsa_next -
+ hostdata->dsa_start;
+ tmp->dsa_addr = virt_to_bus(tmp->dsa) - hostdata->dsa_start;
+
+ /*
+ * Calculate addresses of dynamic code to fill in DSA
+ */
+
+ tmp->data_transfer_start = tmp->dsa + (hostdata->dsa_end -
+ hostdata->dsa_start) / sizeof(u32);
+ tmp->data_transfer_end = tmp->data_transfer_start +
+ 2 * data_transfer_instructions;
+
+ cmd_datain = datain ? tmp->data_transfer_start : NULL;
+ cmd_dataout = dataout ? (datain ? cmd_datain + 2 * datain : tmp->
+ data_transfer_start) : NULL;
+
+ /*
+ * Fill in the NCR53c7x0_cmd structure as follows
+ * dsa, with fixed up DSA code
+ * datain code
+ * dataout code
+ */
+
+ /* Copy template code into dsa and perform all necessary fixups */
+ if (hostdata->dsa_fixup)
+ hostdata->dsa_fixup(tmp);
+
+ patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
+ patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) {
+
+ exp_select_indirect = ((1 << cmd->target) << 16) |
+ (hostdata->sync[cmd->target].sxfer_sanity << 8);
+
+ if (hostdata->sync[cmd->target].select_indirect !=
+ exp_select_indirect) {
+ printk ("scsi%d : sanity check failed select_indirect=0x%x\n",
+ host->host_no, hostdata->sync[cmd->target].select_indirect);
+ FATAL(host);
+
+ }
+ }
+
+ patch_dsa_32(tmp->dsa, dsa_select, 0,
+ hostdata->sync[cmd->target].select_indirect);
+
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ /*
+ * Right now, we'll do the WIDE and SYNCHRONOUS negotiations on
+ * different commands; although it should be trivial to do them
+ * both at the same time.
+ */
+ if (hostdata->initiate_wdtr & (1 << cmd->target)) {
+ memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
+ sizeof(wdtr_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
+ save_flags(flags);
+ cli();
+ hostdata->initiate_wdtr &= ~(1 << cmd->target);
+ restore_flags(flags);
+ } else if (hostdata->initiate_sdtr & (1 << cmd->target)) {
+ memcpy ((void *) (tmp->select + 1), (void *) sdtr_message,
+ sizeof(sdtr_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
+ tmp->flags |= CMD_FLAG_SDTR;
+ save_flags(flags);
+ cli();
+ hostdata->initiate_sdtr &= ~(1 << cmd->target);
+ restore_flags(flags);
+
+ }
+#if 1
+ else if (!(hostdata->talked_to & (1 << cmd->target)) &&
+ !(hostdata->options & OPTION_NO_ASYNC)) {
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ memcpy ((void *) (tmp->select + 1), (void *) async_message,
+ sizeof(async_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(async_message));
+ tmp->flags |= CMD_FLAG_SDTR;
+ }
+#endif
+ else
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ hostdata->talked_to |= (1 << cmd->target);
+ tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ?
+ IDENTIFY (1, cmd->lun) : IDENTIFY (0, cmd->lun);
+ patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
+ patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
+ patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(cmd->cmnd));
+ patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ?
+ virt_to_bus (cmd_dataout)
+ : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
+ patch_dsa_32(tmp->dsa, dsa_datain, 0, cmd_datain ?
+ virt_to_bus (cmd_datain)
+ : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
+ /*
+ * XXX - need to make endian aware, should use separate variables
+ * for both status and message bytes.
+ */
+ patch_dsa_32(tmp->dsa, dsa_msgin, 0, 1);
+/*
+ * FIXME : these only works for little endian. We probably want to
+ * provide message and status fields in the NCR53c7x0_cmd
+ * structure, and assign them to cmd->result when we're done.
+ */
+#ifdef BIG_ENDIAN
+ patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 2);
+ patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
+ patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result) + 3);
+#else
+ patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 1);
+ patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
+ patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result));
+#endif
+ patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
+ patch_dsa_32(tmp->dsa, dsa_msgout_other, 1,
+ virt_to_bus(&(hostdata->NCR53c7xx_msg_nop)));
+
+ /*
+ * Generate code for zero or more of the DATA IN, DATA OUT phases
+ * in the format
+ *
+ * CALL data_transfer, WHEN NOT phase
+ * MOVE first buffer length, first buffer address, WHEN phase
+ * ...
+ * MOVE last buffer length, last buffer address, WHEN phase
+ * JUMP other_transfer
+ */
+
+/*
+ * See if we're getting to data transfer by generating an unconditional
+ * interrupt.
+ */
+#if 0
+ if (datain) {
+ cmd_datain[0] = 0x98080000;
+ cmd_datain[1] = 0x03ffd00d;
+ cmd_datain += 2;
+ }
+#endif
+
+/*
+ * XXX - I'm undecided whether all of this nonsense is faster
+ * in the long run, or whether I should just go and implement a loop
+ * on the NCR chip using table indirect mode?
+ *
+ * In any case, this is how it _must_ be done for 53c700/700-66 chips,
+ * so this stays even when we come up with something better.
+ *
+ * When we're limited to 1 simultaneous command, no overlapping processing,
+ * we're seeing 630K/sec, with 7% CPU usage on a slow Syquest 45M
+ * drive.
+ *
+ * Not bad, not good. We'll see.
+ */
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+
+ for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4,
+ cmd_dataout += 4, ++i) {
+ u32 buf = cmd->use_sg ?
+ virt_to_bus(((struct scatterlist *)cmd->buffer)[i].address) :
+ virt_to_bus(cmd->request_buffer);
+ u32 count = cmd->use_sg ?
+ ((struct scatterlist *)cmd->buffer)[i].length :
+ cmd->request_bufflen;
+
+ if (datain) {
+ /* CALL other_in, WHEN NOT DATA_IN */
+ cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
+ DCMD_TCI_IO) << 24) |
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
+ cmd_datain[1] = virt_to_bus (hostdata->script) +
+ hostdata->E_other_in;
+ /* MOVE count, buf, WHEN DATA_IN */
+ cmd_datain[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO)
+ << 24) | count;
+ cmd_datain[3] = buf;
+#if 0
+ print_insn (host, cmd_datain, "dynamic ", 1);
+ print_insn (host, cmd_datain + 2, "dynamic ", 1);
+#endif
+ }
+ if (dataout) {
+ /* CALL other_out, WHEN NOT DATA_OUT */
+ cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) |
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
+ cmd_dataout[1] = virt_to_bus(hostdata->script) +
+ hostdata->E_other_out;
+ /* MOVE count, buf, WHEN DATA+OUT */
+ cmd_dataout[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24)
+ | count;
+ cmd_dataout[3] = buf;
+#if 0
+ print_insn (host, cmd_dataout, "dynamic ", 1);
+ print_insn (host, cmd_dataout + 2, "dynamic ", 1);
+#endif
+ }
+ }
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+
+ /*
+ * Install JUMP instructions after the data transfer routines to return
+ * control to the do_other_transfer routines.
+ */
+
+
+ if (datain) {
+ cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE;
+ cmd_datain[1] = virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer;
+#if 0
+ print_insn (host, cmd_datain, "dynamic jump ", 1);
+#endif
+ cmd_datain += 2;
+ }
+#if 0
+ if (datain) {
+ cmd_datain[0] = 0x98080000;
+ cmd_datain[1] = 0x03ffdeed;
+ cmd_datain += 2;
+ }
+#endif
+ if (dataout) {
+ cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE;
+ cmd_dataout[1] = virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer;
+#if 0
+ print_insn (host, cmd_dataout, "dynamic jump ", 1);
+#endif
+ cmd_dataout += 2;
+ }
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ return tmp;
+}
+
+/*
+ * Function : int NCR53c7xx_queue_command (Scsi_Cmnd *cmd,
+ * void (*done)(Scsi_Cmnd *))
+ *
+ * Purpose : enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ * a pointer to the command descriptor.
+ *
+ * Returns : 0
+ *
+ * Side effects :
+ * cmd is added to the per instance driver issue_queue, with major
+ * twiddling done to the host specific fields of cmd. If the
+ * process_issue_queue coroutine isn't running, it is restarted.
+ *
+ * NOTE : we use the host_scribble field of the Scsi_Cmnd structure to
+ * hold our own data, and pervert the ptr field of the SCp field
+ * to create a linked list.
+ */
+
+int
+NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
+ struct Scsi_Host *host = cmd->host;
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata;
+ unsigned long flags;
+ Scsi_Cmnd *tmp;
+
+ cmd->scsi_done = done;
+ cmd->host_scribble = NULL;
+ cmd->SCp.ptr = NULL;
+ cmd->SCp.buffer = NULL;
+
+#ifdef VALID_IDS
+ /* Ignore commands on invalid IDs */
+ if (!hostdata->valid_ids[cmd->target]) {
+ printk("scsi%d : ignoring target %d lun %d\n", host->host_no,
+ cmd->target, cmd->lun);
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ return 0;
+ }
+#endif
+
+ save_flags(flags);
+ cli();
+ if ((hostdata->options & (OPTION_DEBUG_INIT_ONLY|OPTION_DEBUG_PROBE_ONLY))
+ || ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
+ !(hostdata->debug_lun_limit[cmd->target] & (1 << cmd->lun)))
+#ifdef LINUX_1_2
+ || cmd->target > 7
+#else
+ || cmd->target > host->max_id
+#endif
+ || cmd->target == host->this_id
+ || hostdata->state == STATE_DISABLED) {
+ printk("scsi%d : disabled or bad target %d lun %d\n", host->host_no,
+ cmd->target, cmd->lun);
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ restore_flags (flags);
+ return 0;
+ }
+
+ if ((hostdata->options & OPTION_DEBUG_NCOMMANDS_LIMIT) &&
+ (hostdata->debug_count_limit == 0)) {
+ printk("scsi%d : maximum commands exceeded\n", host->host_no);
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ restore_flags (flags);
+ return 0;
+ }
+
+ if (hostdata->options & OPTION_DEBUG_READ_ONLY) {
+ switch (cmd->cmnd[0]) {
+ case WRITE_6:
+ case WRITE_10:
+ printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
+ host->host_no);
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ restore_flags (flags);
+ return 0;
+ }
+ }
+
+ if ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
+ hostdata->debug_count_limit != -1)
+ --hostdata->debug_count_limit;
+
+ cmd->result = 0xffff; /* The NCR will overwrite message
+ and status with valid data */
+ cmd->host_scribble = (unsigned char *) tmp = create_cmd (cmd);
+
+ /*
+ * REQUEST SENSE commands are inserted at the head of the queue
+ * so that we do not clear the contingent allegiance condition
+ * they may be looking at.
+ */
+
+ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+ cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue;
+ hostdata->issue_queue = cmd;
+ } else {
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->SCp.ptr;
+ tmp = (Scsi_Cmnd *) tmp->SCp.ptr);
+ tmp->SCp.ptr = (unsigned char *) cmd;
+ }
+ restore_flags (flags);
+ run_process_issue_queue();
+ return 0;
+}
+
+/*
+ * Function : void to_schedule_list (struct Scsi_Host *host,
+ * struct NCR53c7x0_hostdata * hostdata, Scsi_Cmnd *cmd)
+ *
+ * Purpose : takes a SCSI command which was just removed from the
+ * issue queue, and deals with it by inserting it in the first
+ * free slot in the schedule list or by terminating it immediately.
+ *
+ * Inputs :
+ * host - SCSI host adapter; hostdata - hostdata structure for
+ * this adapter; cmd - a pointer to the command; should have
+ * the host_scribble field initialized to point to a valid
+ *
+ * Side effects :
+ * cmd is added to the per instance schedule list, with minor
+ * twiddling done to the host specific fields of cmd.
+ *
+ */
+
+static __inline__ void
+to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
+ struct NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ Scsi_Cmnd *tmp = cmd->cmd;
+ unsigned long flags;
+ /* dsa start is negative, so subtraction is used */
+ volatile u32 *ncrcurrent;
+
+ int i;
+ NCR53c7x0_local_setup(host);
+#if 0
+ printk("scsi%d : new dsa is 0x%lx (virt 0x%p)\n", host->host_no,
+ virt_to_bus(hostdata->dsa), hostdata->dsa);
+#endif
+
+ save_flags(flags);
+ cli();
+
+ /*
+ * Work around race condition : if an interrupt fired and we
+ * got disabled forget about this command.
+ */
+
+ if (hostdata->state == STATE_DISABLED) {
+ printk("scsi%d : driver disabled\n", host->host_no);
+ tmp->result = (DID_BAD_TARGET << 16);
+ cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
+ hostdata->free = cmd;
+ tmp->scsi_done(tmp);
+ restore_flags (flags);
+ return;
+ }
+
+ for (i = host->can_queue, ncrcurrent = hostdata->schedule;
+ i > 0 && ncrcurrent[0] != hostdata->NOP_insn;
+ --i, ncrcurrent += 2 /* JUMP instructions are two words */);
+
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+ if (i > 0) {
+ ++hostdata->busy[tmp->target][tmp->lun];
+ cmd->next = hostdata->running_list;
+ hostdata->running_list = cmd;
+
+ /* Restore this instruction to a NOP once the command starts */
+ cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) /
+ sizeof(u32)] = (u32) virt_to_bus ((void *)ncrcurrent);
+ /* Replace the current jump operand. */
+ ncrcurrent[1] =
+ virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
+ hostdata->E_dsa_code_template;
+ /* Replace the NOP instruction with a JUMP */
+ ncrcurrent[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE;
+ } else {
+ printk ("scsi%d: no free slot\n", host->host_no);
+ disable(host);
+ tmp->result = (DID_ERROR << 16);
+ cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
+ hostdata->free = cmd;
+ tmp->scsi_done(tmp);
+ restore_flags (flags);
+ return;
+ }
+
+ cache_push(virt_to_bus(cmd->dsa), hostdata->dsa_len);
+ cache_push(virt_to_bus(ncrcurrent), sizeof(ncrcurrent));
+
+ /*
+ * If the NCR chip is in an idle state, start it running the scheduler
+ * immediately. Otherwise, signal the chip to jump to schedule as
+ * soon as it is idle.
+ */
+
+ if (hostdata->idle) {
+ hostdata->idle = 0;
+ hostdata->state = STATE_RUNNING;
+ NCR53c7x0_write32 (DSP_REG, virt_to_bus ((void *)hostdata->schedule));
+ if (hostdata->options & OPTION_DEBUG_TRACE)
+ NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
+ DCNTL_SSM | DCNTL_STD);
+ } else {
+ NCR53c7x0_write8(hostdata->istat, ISTAT_10_SIGP);
+ }
+
+ restore_flags(flags);
+}
+
+/*
+ * Function : busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata
+ * *hostdata, Scsi_Cmnd *cmd)
+ *
+ * Purpose : decide if we can pass the given SCSI command on to the
+ * device in question or not.
+ *
+ * Returns : non-zero when we're busy, 0 when we aren't.
+ */
+
+static __inline__ int
+busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
+ Scsi_Cmnd *cmd) {
+ /* FIXME : in the future, this needs to accommodate SCSI-II tagged
+ queuing, and we may be able to play with fairness here a bit.
+ */
+ return hostdata->busy[cmd->target][cmd->lun];
+}
+
+/*
+ * Function : process_issue_queue (void)
+ *
+ * Purpose : transfer commands from the issue queue to NCR start queue
+ * of each NCR53c7/8xx in the system, avoiding kernel stack
+ * overflows when the scsi_done() function is invoked recursively.
+ *
+ * NOTE : process_issue_queue exits with interrupts *disabled*, so the
+ * caller must reenable them if it desires.
+ *
+ * NOTE : process_issue_queue should be called from both
+ * NCR53c7x0_queue_command() and from the interrupt handler
+ * after command completion in case NCR53c7x0_queue_command()
+ * isn't invoked again but we've freed up resources that are
+ * needed.
+ */
+
+static void
+process_issue_queue (unsigned long flags) {
+ Scsi_Cmnd *tmp, *prev;
+ struct Scsi_Host *host;
+ struct NCR53c7x0_hostdata *hostdata;
+ int done;
+
+ /*
+ * We run (with interrupts disabled) until we're sure that none of
+ * the host adapters have anything that can be done, at which point
+ * we set process_issue_queue_running to 0 and exit.
+ *
+ * Interrupts are enabled before doing various other internal
+ * instructions, after we've decided that we need to run through
+ * the loop again.
+ *
+ */
+
+ do {
+ cli(); /* Freeze request queues */
+ done = 1;
+ for (host = first_host; host && host->hostt == the_template;
+ host = host->next) {
+ hostdata = (struct NCR53c7x0_hostdata *) host->hostdata;
+ cli();
+ if (hostdata->issue_queue) {
+ if (hostdata->state == STATE_DISABLED) {
+ tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+ hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
+ tmp->result = (DID_BAD_TARGET << 16);
+ if (tmp->host_scribble) {
+ ((struct NCR53c7x0_cmd *)tmp->host_scribble)->next =
+ hostdata->free;
+ hostdata->free =
+ (struct NCR53c7x0_cmd *)tmp->host_scribble;
+ tmp->host_scribble = NULL;
+ }
+ tmp->scsi_done (tmp);
+ done = 0;
+ } else
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
+ prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *)
+ tmp->SCp.ptr)
+ if (!tmp->host_scribble ||
+ !busyp (host, hostdata, tmp)) {
+ if (prev)
+ prev->SCp.ptr = tmp->SCp.ptr;
+ else
+ hostdata->issue_queue = (Scsi_Cmnd *)
+ tmp->SCp.ptr;
+ tmp->SCp.ptr = NULL;
+ if (tmp->host_scribble) {
+ if (hostdata->options & OPTION_DEBUG_QUEUES)
+ printk ("scsi%d : moving command for target %d lun %d to start list\n",
+ host->host_no, tmp->target, tmp->lun);
+
+
+ to_schedule_list (host, hostdata,
+ (struct NCR53c7x0_cmd *)
+ tmp->host_scribble);
+ } else {
+ if (((tmp->result & 0xff) == 0xff) ||
+ ((tmp->result & 0xff00) == 0xff00)) {
+ printk ("scsi%d : danger Will Robinson!\n",
+ host->host_no);
+ tmp->result = DID_ERROR << 16;
+ disable (host);
+ }
+ tmp->scsi_done(tmp);
+ }
+ done = 0;
+ } /* if target/lun is not busy */
+ } /* if hostdata->issue_queue */
+ if (!done)
+ restore_flags (flags);
+ } /* for host */
+ } while (!done);
+ process_issue_queue_running = 0;
+}
+
+/*
+ * Function : static void intr_scsi (struct Scsi_Host *host,
+ * struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : handle all SCSI interrupts, indicated by the setting
+ * of the SIP bit in the ISTAT register.
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * may be NULL.
+ */
+
+static void
+intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata;
+ unsigned char sstat0_sist0, sist1, /* Registers */
+ fatal; /* Did a fatal interrupt
+ occur ? */
+
+ NCR53c7x0_local_setup(host);
+
+ fatal = 0;
+
+ sstat0_sist0 = NCR53c7x0_read8(SSTAT0_REG);
+ sist1 = 0;
+
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : SIST0 0x%0x, SIST1 0x%0x\n", host->host_no,
+ sstat0_sist0, sist1);
+
+ /* 250ms selection timeout */
+ if (sstat0_sist0 & SSTAT0_700_STO) {
+ fatal = 1;
+ if (hostdata->options & OPTION_DEBUG_INTR) {
+ printk ("scsi%d : Selection Timeout\n", host->host_no);
+ if (cmd) {
+ printk("scsi%d : target %d, lun %d, command ",
+ host->host_no, cmd->cmd->target, cmd->cmd->lun);
+ print_command (cmd->cmd->cmnd);
+ printk("scsi%d : dsp = 0x%x (virt 0x%p)\n", host->host_no,
+ NCR53c7x0_read32(DSP_REG),
+ bus_to_virt(NCR53c7x0_read32(DSP_REG)));
+ } else {
+ printk("scsi%d : no command\n", host->host_no);
+ }
+ }
+/*
+ * XXX - question : how do we want to handle the Illegal Instruction
+ * interrupt, which may occur before or after the Selection Timeout
+ * interrupt?
+ */
+
+ if (1) {
+ hostdata->idle = 1;
+ hostdata->expecting_sto = 0;
+
+ if (hostdata->test_running) {
+ hostdata->test_running = 0;
+ hostdata->test_completed = 3;
+ } else if (cmd) {
+ abnormal_finished(cmd, DID_BAD_TARGET << 16);
+ }
+#if 0
+ hostdata->intrs = 0;
+#endif
+ }
+ }
+
+/*
+ * FIXME : in theory, we can also get a UDC when a STO occurs.
+ */
+ if (sstat0_sist0 & SSTAT0_UDC) {
+ fatal = 1;
+ if (cmd) {
+ printk("scsi%d : target %d lun %d unexpected disconnect\n",
+ host->host_no, cmd->cmd->target, cmd->cmd->lun);
+ print_lots (host);
+ abnormal_finished(cmd, DID_ERROR << 16);
+ } else
+ printk("scsi%d : unexpected disconnect (no command)\n",
+ host->host_no);
+
+ hostdata->dsp = (u32 *) hostdata->schedule;
+ hostdata->dsp_changed = 1;
+ }
+
+ /* SCSI PARITY error */
+ if (sstat0_sist0 & SSTAT0_PAR) {
+ fatal = 1;
+ if (cmd && cmd->cmd) {
+ printk("scsi%d : target %d lun %d parity error.\n",
+ host->host_no, cmd->cmd->target, cmd->cmd->lun);
+ abnormal_finished (cmd, DID_PARITY << 16);
+ } else
+ printk("scsi%d : parity error\n", host->host_no);
+ /* Should send message out, parity error */
+
+ /* XXX - Reduce synchronous transfer rate! */
+ hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ /* SCSI GROSS error */
+ }
+
+ if (sstat0_sist0 & SSTAT0_SGE) {
+ fatal = 1;
+ printk("scsi%d : gross error, saved2_dsa = 0x%x\n", host->host_no,
+ (unsigned int)hostdata->saved2_dsa);
+ print_lots (host);
+
+ /*
+ * A SCSI gross error may occur when we have
+ *
+ * - A synchronous offset which causes the SCSI FIFO to be overwritten.
+ *
+ * - A REQ which causes the maximum synchronous offset programmed in
+ * the SXFER register to be exceeded.
+ *
+ * - A phase change with an outstanding synchronous offset.
+ *
+ * - Residual data in the synchronous data FIFO, with a transfer
+ * other than a synchronous receive is started.$#
+ */
+
+
+ /* XXX Should deduce synchronous transfer rate! */
+ hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ /* Phase mismatch */
+ }
+
+ if (sstat0_sist0 & SSTAT0_MA) {
+ fatal = 1;
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : SSTAT0_MA\n", host->host_no);
+ intr_phase_mismatch (host, cmd);
+ }
+
+#if 0
+ if (sstat0_sist0 & SIST0_800_RSL)
+ printk ("scsi%d : Oh no Mr. Bill!\n", host->host_no);
+#endif
+
+/*
+ * If a fatal SCSI interrupt occurs, we must insure that the DMA and
+ * SCSI FIFOs were flushed.
+ */
+
+ if (fatal) {
+ if (!hostdata->dstat_valid) {
+ hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+ hostdata->dstat_valid = 1;
+ }
+
+ if (!(hostdata->dstat & DSTAT_DFE)) {
+ printk ("scsi%d : DMA FIFO not empty\n", host->host_no);
+ /*
+ * Really need to check this code for 710 RGH.
+ * Havn't seen any problems, but maybe we should FLUSH before
+ * clearing sometimes.
+ */
+ NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
+ while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF)
+ ;
+ hostdata->dstat |= DSTAT_DFE;
+ }
+ }
+}
+
+#ifdef CYCLIC_TRACE
+
+/*
+ * The following implements a cyclic log of instructions executed, if you turn
+ * TRACE on. It will also print the log for you. Very useful when debugging
+ * 53c710 support, possibly not really needed any more.
+ */
+
+u32 insn_log[4096];
+u32 insn_log_index = 0;
+
+void log1 (u32 i)
+{
+ insn_log[insn_log_index++] = i;
+ if (insn_log_index == 4096)
+ insn_log_index = 0;
+}
+
+void log_insn (u32 *ip)
+{
+ log1 ((u32)ip);
+ log1 (*ip);
+ log1 (*(ip+1));
+ if (((*ip >> 24) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)
+ log1 (*(ip+2));
+}
+
+void dump_log(void)
+{
+ int cnt = 0;
+ int i = insn_log_index;
+ int size;
+ struct Scsi_Host *host = first_host;
+
+ while (cnt < 4096) {
+ printk ("%08x (+%6x): ", insn_log[i], (insn_log[i] - (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata)->script))/4);
+ if (++i == 4096)
+ i = 0;
+ cnt++;
+ if (((insn_log[i] >> 24) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)
+ size = 3;
+ else
+ size = 2;
+ while (size--) {
+ printk ("%08x ", insn_log[i]);
+ if (++i == 4096)
+ i = 0;
+ cnt++;
+ }
+ printk ("\n");
+ }
+}
+#endif
+
+/*
+ * Function : static void NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
+ *
+ * Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing
+ * the same IRQ line.
+ *
+ * Inputs : Since we're using the SA_INTERRUPT interrupt handler
+ * semantics, irq indicates the interrupt which invoked
+ * this handler.
+ *
+ * On the 710 we simualte an INTFLY with a script interrupt, and the
+ * script interrupt handler will call back to this function.
+ */
+
+void
+NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
+ NCR53c7x0_local_declare();
+ struct Scsi_Host *host; /* Host we are looking at */
+ unsigned char istat; /* Values of interrupt regs */
+ struct NCR53c7x0_hostdata *hostdata; /* host->hostdata */
+ struct NCR53c7x0_cmd *cmd, /* command which halted */
+ **cmd_prev_ptr;
+ u32 *dsa; /* DSA */
+ int done = 1; /* Indicates when handler
+ should terminate */
+ int interrupted = 0; /* This HA generated
+ an interrupt */
+ int have_intfly; /* Don't print warning
+ messages when we stack
+ INTFLYs */
+ unsigned long flags;
+
+#ifdef NCR_DEBUG
+ char buf[80]; /* Debugging sprintf buffer */
+ size_t buflen; /* Length of same */
+#endif
+
+#if defined(CONFIG_AMIGA)
+ custom.intena = IF_PORTS;
+#endif
+
+ do {
+ done = 1;
+ for (host = first_host; host; host = host->next)
+ if (host->hostt == the_template
+#if defined(MVME166_INTFLY)
+ /* We have two different interrupts pointing
+ * at this routine, so remove this check */
+#else
+ && host->irq == irq
+#endif
+ ) {
+ NCR53c7x0_local_setup(host);
+
+ hostdata = (struct NCR53c7x0_hostdata *) host->hostdata;
+ hostdata->dsp_changed = 0;
+ interrupted = 0;
+ have_intfly = 0;
+
+ do {
+ hostdata->dstat_valid = 0;
+ interrupted = 0;
+ /*
+ * Only read istat once, since reading it again will unstack
+ * interrupts?
+ */
+ istat = NCR53c7x0_read8(hostdata->istat);
+
+ if ((hostdata->options & OPTION_INTFLY) &&
+#ifdef MVME166_INTFLY
+ /* the bit is set which indicates an on-the-fly int */
+ (*(volatile unsigned long *)0xfff40068 & 0x8000))
+#else
+ (hostdata->emulated_intfly != 0))
+#endif
+ {
+ char search_found = 0; /* Got at least one ? */
+ done = 0;
+ interrupted = 1;
+
+#ifdef MVME166_INTFLY
+ /* clear the INTFLY bit */
+ *(volatile unsigned long *)0xfff40074 = 0x8000;
+#endif
+
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : INTFLY\n", host->host_no);
+
+ /*
+ * Traverse our list of running commands, and look
+ * for those with valid (non-0xff ff) status and message
+ * bytes encoded in the result which signify command
+ * completion.
+ */
+
+
+ save_flags(flags);
+ cli();
+restart:
+ for (cmd_prev_ptr = (struct NCR53c7x0_cmd **)
+ &(hostdata->running_list), cmd =
+ (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ;
+ cmd_prev_ptr = (struct NCR53c7x0_cmd **) &(cmd->next),
+ cmd = (struct NCR53c7x0_cmd *) cmd->next) {
+ Scsi_Cmnd *tmp;
+
+ if (!cmd) {
+ printk("scsi%d : very weird.\n", host->host_no);
+ break;
+ }
+
+ if (!(tmp = cmd->cmd)) {
+ printk("scsi%d : weird. NCR53c7x0_cmd has no Scsi_Cmnd\n",
+ host->host_no);
+ continue;
+ }
+#if 0
+ printk ("scsi%d : looking at result of 0x%x\n",
+ host->host_no, cmd->cmd->result);
+#endif
+
+ if (((tmp->result & 0xff) == 0xff) ||
+ ((tmp->result & 0xff00) == 0xff00))
+ continue;
+
+ search_found = 1;
+
+ /* Important - remove from list _before_ done is called */
+ if (cmd_prev_ptr)
+ *cmd_prev_ptr = (struct NCR53c7x0_cmd *) cmd->next;
+
+ --hostdata->busy[tmp->target][tmp->lun];
+ cmd->next = hostdata->free;
+ hostdata->free = cmd;
+
+ tmp->host_scribble = NULL;
+
+ if (hostdata->options & OPTION_DEBUG_INTR) {
+ printk ("scsi%d : command complete : pid %lu, id %d,lun %d result 0x%x ",
+ host->host_no, tmp->pid, tmp->target, tmp->lun, tmp->result);
+ print_command (tmp->cmnd);
+ }
+
+#if 0
+ hostdata->options &= ~OPTION_DEBUG_INTR;
+#endif
+ tmp->scsi_done(tmp);
+ goto restart;
+
+ }
+ restore_flags(flags);
+
+ if (!search_found && !have_intfly) {
+ printk ("scsi%d : WARNING : INTFLY with no completed commands.\n",
+ host->host_no);
+ } else if (!have_intfly) {
+ have_intfly = 1;
+ run_process_issue_queue();
+ }
+ }
+
+ if (hostdata->emulated_intfly)
+ {
+ hostdata->emulated_intfly = 0;
+ return;
+ }
+
+ if (istat & (ISTAT_SIP|ISTAT_DIP)) {
+ done = 0;
+ interrupted = 1;
+ hostdata->state = STATE_HALTED;
+
+ if (NCR53c7x0_read8 (SSTAT2_REG) & SSTAT2_FF_MASK)
+ printk ("scsi%d : SCSI FIFO not empty\n",
+ host->host_no);
+
+ /*
+ * NCR53c700 and NCR53c700-66 change the current SCSI
+ * process, hostdata->ncrcurrent, in the Linux driver so
+ * cmd = hostdata->ncrcurrent.
+ *
+ * With other chips, we must look through the commands
+ * executing and find the command structure which
+ * corresponds to the DSA register.
+ */
+
+ if (hostdata->options & OPTION_700) {
+ cmd = (struct NCR53c7x0_cmd *) hostdata->ncrcurrent;
+ } else {
+ dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+ for (cmd = (struct NCR53c7x0_cmd *)
+ hostdata->running_list; cmd &&
+ (dsa + (hostdata->dsa_start / sizeof(u32))) !=
+ cmd->dsa;
+ cmd = (struct NCR53c7x0_cmd *)(cmd->next));
+ }
+ if (hostdata->options & OPTION_DEBUG_INTR) {
+ if (cmd) {
+ printk("scsi%d : interrupt for pid %lu, id %d, lun %d ",
+ host->host_no, cmd->cmd->pid, (int) cmd->cmd->target,
+ (int) cmd->cmd->lun);
+ print_command (cmd->cmd->cmnd);
+ } else {
+ printk("scsi%d : no active command\n", host->host_no);
+ }
+ }
+
+ if (istat & ISTAT_SIP) {
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : ISTAT_SIP\n", host->host_no);
+ intr_scsi (host, cmd);
+ }
+
+ if (istat & ISTAT_DIP) {
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : ISTAT_DIP\n", host->host_no);
+ intr_dma (host, cmd);
+ }
+
+ if (!hostdata->dstat_valid) {
+ hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+ hostdata->dstat_valid = 1;
+ }
+
+ if (!(hostdata->dstat & DSTAT_DFE)) {
+ printk ("scsi%d : DMA FIFO not empty\n", host->host_no);
+ /* Really need to check this out for 710 RGH */
+ NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
+ while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF);
+ hostdata->dstat |= DSTAT_DFE;
+ }
+ }
+ } while (interrupted);
+
+
+
+ if (hostdata->intrs != -1)
+ hostdata->intrs++;
+#if 0
+ if (hostdata->intrs > 40) {
+ printk("scsi%d : too many interrupts, halting", host->host_no);
+ disable(host);
+ }
+#endif
+
+ if (!hostdata->idle && hostdata->state == STATE_HALTED) {
+ if (!hostdata->dsp_changed) {
+ hostdata->dsp = (u32 *)
+ bus_to_virt(NCR53c7x0_read32(DSP_REG));
+ }
+
+#if 0
+ printk("scsi%d : new dsp is 0x%lx (virt 0x%p)\n",
+ host->host_no, virt_to_bus(hostdata->dsp), hostdata->dsp);
+#endif
+
+ hostdata->state = STATE_RUNNING;
+ NCR53c7x0_write32 (DSP_REG, virt_to_bus(hostdata->dsp));
+ if (hostdata->options & OPTION_DEBUG_TRACE) {
+#ifdef CYCLIC_TRACE
+ log_insn (hostdata->dsp);
+#else
+ print_insn (host, hostdata->dsp, "t ", 1);
+#endif
+ NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
+ DCNTL_SSM | DCNTL_STD);
+ }
+ }
+ }
+ } while (!done);
+#ifdef CONFIG_AMIGA
+ custom.intena = IF_SETCLR | IF_PORTS;
+#endif
+}
+
+
+/*
+ * Function : static int abort_connected (struct Scsi_Host *host)
+ *
+ * Purpose : Assuming that the NCR SCSI processor is currently
+ * halted, break the currently established nexus. Clean
+ * up of the NCR53c7x0_cmd and Scsi_Cmnd structures should
+ * be done on receipt of the abort interrupt.
+ *
+ * Inputs : host - SCSI host
+ *
+ */
+
+static int
+abort_connected (struct Scsi_Host *host) {
+#ifdef NEW_ABORT
+ NCR53c7x0_local_declare();
+#endif
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+/* FIXME : this probably should change for production kernels; at the
+ least, counter should move to a per-host structure. */
+ static int counter = 5;
+#ifdef NEW_ABORT
+ int sstat, phase, offset;
+ u32 *script;
+ NCR53c7x0_local_setup(host);
+#endif
+
+ if (--counter <= 0) {
+ disable(host);
+ return 0;
+ }
+
+ printk ("scsi%d : DANGER : abort_connected() called \n",
+ host->host_no);
+
+#ifdef NEW_ABORT
+
+/*
+ * New strategy : Rather than using a generic abort routine,
+ * we'll specifically try to source or sink the appropriate
+ * amount of data for the phase we're currently in (taking into
+ * account the current synchronous offset)
+ */
+
+ sstat = (NCR53c8x0_read8 (SSTAT2_REG);
+ offset = OFFSET (sstat & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
+ phase = sstat & SSTAT2_PHASE_MASK;
+
+/*
+ * SET ATN
+ * MOVE source_or_sink, WHEN CURRENT PHASE
+ * < repeat for each outstanding byte >
+ * JUMP send_abort_message
+ */
+
+ script = hostdata->abort_script = kmalloc (
+ 8 /* instruction size */ * (
+ 1 /* set ATN */ +
+ (!offset ? 1 : offset) /* One transfer per outstanding byte */ +
+ 1 /* send abort message */),
+ GFP_ATOMIC);
+
+
+#else /* def NEW_ABORT */
+ hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+ sizeof(u32);
+#endif /* def NEW_ABORT */
+ hostdata->dsp_changed = 1;
+
+/* XXX - need to flag the command as aborted after the abort_connected
+ code runs
+ */
+ return 0;
+}
+
+/*
+ * Function : static int datapath_residual (Scsi_Host *host)
+ *
+ * Purpose : return residual data count of what's in the chip.
+ *
+ * Inputs : host - SCSI host
+ */
+
+static int
+datapath_residual (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ int count, synchronous, sstat;
+ unsigned int ddir;
+
+ NCR53c7x0_local_setup(host);
+ /* COMPAT : the 700 and 700-66 need to use DFIFO_00_BO_MASK */
+ count = ((NCR53c7x0_read8 (DFIFO_REG) & DFIFO_10_BO_MASK) -
+ (NCR53c7x0_read32 (DBC_REG) & DFIFO_10_BO_MASK)) & DFIFO_10_BO_MASK;
+ synchronous = NCR53c7x0_read8 (SXFER_REG) & SXFER_MO_MASK;
+ /* COMPAT : DDIR is elsewhere on non-'8xx chips. */
+ ddir = NCR53c7x0_read8 (CTEST0_REG_700) & CTEST0_700_DDIR;
+
+ if (ddir) {
+ /* Receive */
+ if (synchronous)
+ count += (NCR53c7x0_read8 (SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
+ else
+ if (NCR53c7x0_read8 (SSTAT1_REG) & SSTAT1_ILF)
+ ++count;
+ } else {
+ /* Send */
+ sstat = NCR53c7x0_read8 (SSTAT1_REG);
+ if (sstat & SSTAT1_OLF)
+ ++count;
+ if (synchronous && (sstat & SSTAT1_ORF))
+ ++count;
+ }
+ return count;
+}
+
+/*
+ * Function : static const char * sbcl_to_phase (int sbcl)_
+ *
+ * Purpose : Convert SBCL register to user-parsable phase representation
+ *
+ * Inputs : sbcl - value of sbcl register
+ */
+
+
+static const char *
+sbcl_to_phase (int sbcl) {
+ switch (sbcl & SBCL_PHASE_MASK) {
+ case SBCL_PHASE_DATAIN:
+ return "DATAIN";
+ case SBCL_PHASE_DATAOUT:
+ return "DATAOUT";
+ case SBCL_PHASE_MSGIN:
+ return "MSGIN";
+ case SBCL_PHASE_MSGOUT:
+ return "MSGOUT";
+ case SBCL_PHASE_CMDOUT:
+ return "CMDOUT";
+ case SBCL_PHASE_STATIN:
+ return "STATUSIN";
+ default:
+ return "unknown";
+ }
+}
+
+/*
+ * Function : static const char * sstat2_to_phase (int sstat)_
+ *
+ * Purpose : Convert SSTAT2 register to user-parsable phase representation
+ *
+ * Inputs : sstat - value of sstat register
+ */
+
+
+static const char *
+sstat2_to_phase (int sstat) {
+ switch (sstat & SSTAT2_PHASE_MASK) {
+ case SSTAT2_PHASE_DATAIN:
+ return "DATAIN";
+ case SSTAT2_PHASE_DATAOUT:
+ return "DATAOUT";
+ case SSTAT2_PHASE_MSGIN:
+ return "MSGIN";
+ case SSTAT2_PHASE_MSGOUT:
+ return "MSGOUT";
+ case SSTAT2_PHASE_CMDOUT:
+ return "CMDOUT";
+ case SSTAT2_PHASE_STATIN:
+ return "STATUSIN";
+ default:
+ return "unknown";
+ }
+}
+
+/*
+ * Function : static void intr_phase_mismatch (struct Scsi_Host *host,
+ * struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : Handle phase mismatch interrupts
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * may be NULL.
+ *
+ * Side effects : The abort_connected() routine is called or the NCR chip
+ * is restarted, jumping to the command_complete entry point, or
+ * patching the address and transfer count of the current instruction
+ * and calling the msg_in entry point as appropriate.
+ */
+
+static void
+intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ u32 dbc_dcmd, *dsp, *dsp_next;
+ unsigned char dcmd, sbcl;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ int residual;
+ enum {ACTION_ABORT, ACTION_ABORT_PRINT, ACTION_CONTINUE} action =
+ ACTION_ABORT_PRINT;
+ const char *where = NULL;
+
+ NCR53c7x0_local_setup(host);
+
+ /*
+ * Corrective action is based on where in the SCSI SCRIPT(tm) the error
+ * occurred, as well as which SCSI phase we are currently in.
+ */
+ dsp_next = bus_to_virt(NCR53c7x0_read32(DSP_REG));
+
+ /*
+ * Fetch the current instruction, and remove the operands for easier
+ * interpretation.
+ */
+ dbc_dcmd = NCR53c7x0_read32(DBC_REG);
+ dcmd = (dbc_dcmd & 0xff000000) >> 24;
+ /*
+ * Like other processors, the NCR adjusts the instruction pointer before
+ * instruction decode. Set the DSP address back to what it should
+ * be for this instruction based on its size (2 or 3 32 bit words).
+ */
+ dsp = dsp_next - NCR53c7x0_insn_size(dcmd);
+
+
+ /*
+ * Read new SCSI phase from the SBCL lines. Since all of our code uses
+ * a WHEN conditional instead of an IF conditional, we don't need to
+ * wait for a new REQ.
+ */
+ sbcl = NCR53c7x0_read8(SBCL_REG) & SBCL_PHASE_MASK;
+
+ if (!cmd) {
+ action = ACTION_ABORT_PRINT;
+ where = "no current command";
+ /*
+ * The way my SCSI SCRIPTS(tm) are architected, recoverable phase
+ * mismatches should only occur where we're doing a multi-byte
+ * BMI instruction. Specifically, this means
+ *
+ * - select messages (a SCSI-I target may ignore additional messages
+ * after the IDENTIFY; any target may reject a SDTR or WDTR)
+ *
+ * - command out (targets may send a message to signal an error
+ * condition, or go into STATUSIN after they've decided
+ * they don't like the command.
+ *
+ * - reply_message (targets may reject a multi-byte message in the
+ * middle)
+ *
+ * - data transfer routines (command completion with buffer space
+ * left, disconnect message, or error message)
+ */
+ } else if (((dsp >= cmd->data_transfer_start &&
+ dsp < cmd->data_transfer_end)) || dsp == (cmd->residual + 2)) {
+ if ((dcmd & (DCMD_TYPE_MASK|DCMD_BMI_OP_MASK|DCMD_BMI_INDIRECT|
+ DCMD_BMI_MSG|DCMD_BMI_CD)) == (DCMD_TYPE_BMI|
+ DCMD_BMI_OP_MOVE_I)) {
+ residual = datapath_residual (host);
+ if (hostdata->options & OPTION_DEBUG_DISCONNECT)
+ printk ("scsi%d : handling residual transfer (+ %d bytes from DMA FIFO)\n",
+ host->host_no, residual);
+
+ /*
+ * The first instruction is a CALL to the alternate handler for
+ * this data transfer phase, so we can do calls to
+ * munge_msg_restart as we would if control were passed
+ * from normal dynamic code.
+ */
+ if (dsp != cmd->residual + 2) {
+ cmd->residual[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
+ ((dcmd & DCMD_BMI_IO) ? DCMD_TCI_IO : 0)) << 24) |
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
+ cmd->residual[1] = virt_to_bus(hostdata->script)
+ + ((dcmd & DCMD_BMI_IO)
+ ? hostdata->E_other_in : hostdata->E_other_out);
+ }
+
+ /*
+ * The second instruction is the a data transfer block
+ * move instruction, reflecting the pointer and count at the
+ * time of the phase mismatch.
+ */
+ cmd->residual[2] = dbc_dcmd + residual;
+ cmd->residual[3] = NCR53c7x0_read32(DNAD_REG) - residual;
+
+ /*
+ * The third and final instruction is a jump to the instruction
+ * which follows the instruction which had to be 'split'
+ */
+ if (dsp != cmd->residual + 2) {
+ cmd->residual[4] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP)
+ << 24) | DBC_TCI_TRUE;
+ cmd->residual[5] = virt_to_bus(dsp_next);
+ }
+
+ /*
+ * For the sake of simplicity, transfer control to the
+ * conditional CALL at the start of the residual buffer.
+ */
+ hostdata->dsp = cmd->residual;
+ hostdata->dsp_changed = 1;
+ action = ACTION_CONTINUE;
+ } else {
+ where = "non-BMI dynamic DSA code";
+ action = ACTION_ABORT_PRINT;
+ }
+ } else if (dsp == (hostdata->script + hostdata->E_select_msgout / 4)) {
+ /* Release ATN */
+ NCR53c7x0_write8 (SOCL_REG, 0);
+ switch (sbcl) {
+ /*
+ * Some devices (SQ555 come to mind) grab the IDENTIFY message
+ * sent on selection, and decide to go into COMMAND OUT phase
+ * rather than accepting the rest of the messages or rejecting
+ * them. Handle these devices gracefully.
+ */
+ case SBCL_PHASE_CMDOUT:
+ hostdata->dsp = dsp + 2 /* two _words_ */;
+ hostdata->dsp_changed = 1;
+ printk ("scsi%d : target %d ignored SDTR and went into COMMAND OUT\n",
+ host->host_no, cmd->cmd->target);
+ cmd->flags &= ~CMD_FLAG_SDTR;
+ action = ACTION_CONTINUE;
+ break;
+ case SBCL_PHASE_MSGIN:
+ hostdata->dsp = hostdata->script + hostdata->E_msg_in /
+ sizeof(u32);
+ hostdata->dsp_changed = 1;
+ action = ACTION_CONTINUE;
+ break;
+ default:
+ where="select message out";
+ action = ACTION_ABORT_PRINT;
+ }
+ /*
+ * Some SCSI devices will interpret a command as they read the bytes
+ * off the SCSI bus, and may decide that the command is Bogus before
+ * they've read the entire command off the bus.
+ */
+ } else if (dsp == hostdata->script + hostdata->E_cmdout_cmdout / sizeof
+ (u32)) {
+ hostdata->dsp = hostdata->script + hostdata->E_data_transfer /
+ sizeof (u32);
+ hostdata->dsp_changed = 1;
+ action = ACTION_CONTINUE;
+ /* FIXME : we need to handle message reject, etc. within msg_respond. */
+#ifdef notyet
+ } else if (dsp == hostdata->script + hostdata->E_reply_message) {
+ switch (sbcl) {
+ /* Any other phase mismatches abort the currently executing command. */
+#endif
+ } else {
+ where = "unknown location";
+ action = ACTION_ABORT_PRINT;
+ }
+
+ /* Flush DMA FIFO */
+ if (!hostdata->dstat_valid) {
+ hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+ hostdata->dstat_valid = 1;
+ }
+ if (!(hostdata->dstat & DSTAT_DFE)) {
+ /* Really need to check this out for 710 RGH */
+ NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
+ while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF);
+ hostdata->dstat |= DSTAT_DFE;
+ }
+
+ switch (action) {
+ case ACTION_ABORT_PRINT:
+ printk("scsi%d : %s : unexpected phase %s.\n",
+ host->host_no, where ? where : "unknown location",
+ sbcl_to_phase(sbcl));
+ print_lots (host);
+ /* Fall through to ACTION_ABORT */
+ case ACTION_ABORT:
+ abort_connected (host);
+ break;
+ case ACTION_CONTINUE:
+ break;
+ }
+
+#if 0
+ if (hostdata->dsp_changed) {
+ printk("scsi%d: new dsp 0x%p\n", host->host_no, hostdata->dsp);
+ print_insn (host, hostdata->dsp, "", 1);
+ }
+#endif
+
+ cache_push(virt_to_bus(hostdata->script), flushsize);
+}
+
+/*
+ * Function : static void intr_bf (struct Scsi_Host *host,
+ * struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : handle BUS FAULT interrupts
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * may be NULL.
+ */
+
+static void
+intr_bf (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ u32 *dsp,
+ *next_dsp, /* Current dsp */
+ *dsa,
+ dbc_dcmd; /* DCMD (high eight bits) + DBC */
+ char *reason = NULL;
+ /* Default behavior is for a silent error, with a retry until we've
+ exhausted retries. */
+ enum {MAYBE, ALWAYS, NEVER} retry = MAYBE;
+ int report = 0;
+ NCR53c7x0_local_setup(host);
+
+ dbc_dcmd = NCR53c7x0_read32 (DBC_REG);
+ next_dsp = bus_to_virt (NCR53c7x0_read32(DSP_REG));
+ dsp = next_dsp - NCR53c7x0_insn_size ((dbc_dcmd >> 24) & 0xff);
+/* FIXME - check chip type */
+ dsa = bus_to_virt (NCR53c7x0_read32(DSA_REG));
+
+ /*
+ * Bus faults can be caused by either a Bad Address or
+ * Target Abort. We should check the Received Target Abort
+ * bit of the PCI status register and Master Abort Bit.
+ *
+ * - Master Abort bit indicates that no device claimed
+ * the address with DEVSEL within five clocks
+ *
+ * - Target Abort bit indicates that a target claimed it,
+ * but changed its mind once it saw the byte enables.
+ *
+ */
+
+ /* 53c710, not PCI system */
+ report = 1;
+ reason = "Unknown";
+
+#ifndef notyet
+ report = 1;
+#endif
+ if (report && reason)
+ {
+ printk(KERN_ALERT "scsi%d : BUS FAULT reason = %s\n",
+ host->host_no, reason ? reason : "unknown");
+ print_lots (host);
+ }
+
+#ifndef notyet
+ retry = NEVER;
+#endif
+
+ /*
+ * TODO : we should attempt to recover from any spurious bus
+ * faults. After X retries, we should figure that things are
+ * sufficiently wedged, and call NCR53c7xx_reset.
+ *
+ * This code should only get executed once we've decided that we
+ * cannot retry.
+ */
+
+ if (retry == NEVER) {
+ printk(KERN_ALERT " mail drew@PoohSticks.ORG\n");
+ FATAL (host);
+ }
+}
+
+/*
+ * Function : static void intr_dma (struct Scsi_Host *host,
+ * struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : handle all DMA interrupts, indicated by the setting
+ * of the DIP bit in the ISTAT register.
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * may be NULL.
+ */
+
+static void
+intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ unsigned char dstat; /* DSTAT */
+ u32 *dsp,
+ *next_dsp, /* Current dsp */
+ *dsa,
+ dbc_dcmd; /* DCMD (high eight bits) + DBC */
+ int tmp;
+ unsigned long flags;
+ NCR53c7x0_local_setup(host);
+
+ if (!hostdata->dstat_valid) {
+ hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+ hostdata->dstat_valid = 1;
+ }
+
+ dstat = hostdata->dstat;
+
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk("scsi%d : DSTAT=0x%x\n", host->host_no, (int) dstat);
+
+ dbc_dcmd = NCR53c7x0_read32 (DBC_REG);
+ next_dsp = bus_to_virt(NCR53c7x0_read32(DSP_REG));
+ dsp = next_dsp - NCR53c7x0_insn_size ((dbc_dcmd >> 24) & 0xff);
+/* XXX - check chip type */
+ dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+
+ /*
+ * DSTAT_ABRT is the aborted interrupt. This is set whenever the
+ * SCSI chip is aborted.
+ *
+ * With NCR53c700 and NCR53c700-66 style chips, we should only
+ * get this when the chip is currently running the accept
+ * reselect/select code and we have set the abort bit in the
+ * ISTAT register.
+ *
+ */
+
+ if (dstat & DSTAT_ABRT) {
+#if 0
+ /* XXX - add code here to deal with normal abort */
+ if ((hostdata->options & OPTION_700) && (hostdata->state ==
+ STATE_ABORTING)) {
+ } else
+#endif
+ {
+ printk(KERN_ALERT "scsi%d : unexpected abort interrupt at\n"
+ " ", host->host_no);
+ print_insn (host, dsp, KERN_ALERT "s ", 1);
+ FATAL (host);
+ }
+ }
+
+ /*
+ * DSTAT_SSI is the single step interrupt. Should be generated
+ * whenever we have single stepped or are tracing.
+ */
+
+ if (dstat & DSTAT_SSI) {
+ if (hostdata->options & OPTION_DEBUG_TRACE) {
+ /* Don't print instr. until we write DSP at end of intr function */
+ } else if (hostdata->options & OPTION_DEBUG_SINGLE) {
+ print_insn (host, dsp, "s ", 0);
+ save_flags(flags);
+ cli();
+/* XXX - should we do this, or can we get away with writing dsp? */
+
+ NCR53c7x0_write8 (DCNTL_REG, (NCR53c7x0_read8(DCNTL_REG) &
+ ~DCNTL_SSM) | DCNTL_STD);
+ restore_flags(flags);
+ } else {
+ printk(KERN_ALERT "scsi%d : unexpected single step interrupt at\n"
+ " ", host->host_no);
+ print_insn (host, dsp, KERN_ALERT "", 1);
+ printk(KERN_ALERT " mail drew@PoohSticks.ORG\n");
+ FATAL (host);
+ }
+ }
+
+ /*
+ * DSTAT_IID / DSTAT_OPC (same bit, same meaning, only the name
+ * is different) is generated whenever an illegal instruction is
+ * encountered.
+ *
+ * XXX - we may want to emulate INTFLY here, so we can use
+ * the same SCSI SCRIPT (tm) for NCR53c710 through NCR53c810
+ * chips.
+ */
+
+ if (dstat & DSTAT_OPC) {
+ /*
+ * Ascertain if this IID interrupts occurred before or after a STO
+ * interrupt. Since the interrupt handling code now leaves
+ * DSP unmodified until _after_ all stacked interrupts have been
+ * processed, reading the DSP returns the original DSP register.
+ * This means that if dsp lies between the select code, and
+ * message out following the selection code (where the IID interrupt
+ * would have to have occurred by due to the implicit wait for REQ),
+ * we have an IID interrupt resulting from a STO condition and
+ * can ignore it.
+ */
+
+ if (((dsp >= (hostdata->script + hostdata->E_select / sizeof(u32))) &&
+ (dsp <= (hostdata->script + hostdata->E_select_msgout /
+ sizeof(u32) + 8))) || (hostdata->test_running == 2)) {
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : ignoring DSTAT_IID for SSTAT_STO\n",
+ host->host_no);
+ if (hostdata->expecting_iid) {
+ hostdata->expecting_iid = 0;
+ hostdata->idle = 1;
+ if (hostdata->test_running == 2) {
+ hostdata->test_running = 0;
+ hostdata->test_completed = 3;
+ } else if (cmd)
+ abnormal_finished (cmd, DID_BAD_TARGET << 16);
+ } else {
+ hostdata->expecting_sto = 1;
+ }
+ /*
+ * We can't guarantee we'll be able to execute the WAIT DISCONNECT
+ * instruction within the 3.4us of bus free and arbitration delay
+ * that a target can RESELECT in and assert REQ after we've dropped
+ * ACK. If this happens, we'll get an illegal instruction interrupt.
+ * Doing away with the WAIT DISCONNECT instructions broke everything,
+ * so instead I'll settle for moving one WAIT DISCONNECT a few
+ * instructions closer to the CLEAR ACK before it to minimize the
+ * chances of this happening, and handle it if it occurs anyway.
+ *
+ * Simply continue with what we were doing, and control should
+ * be transfered to the schedule routine which will ultimately
+ * pass control onto the reselection or selection (not yet)
+ * code.
+ */
+ } else if (dbc_dcmd == 0x48000000 && (NCR53c7x0_read8 (SBCL_REG) &
+ SBCL_REQ)) {
+ if (!(hostdata->options & OPTION_NO_PRINT_RACE))
+ {
+ printk("scsi%d: REQ before WAIT DISCONNECT IID\n",
+ host->host_no);
+ hostdata->options |= OPTION_NO_PRINT_RACE;
+ }
+ } else {
+ printk(KERN_ALERT "scsi%d : illegal instruction\n", host->host_no);
+ print_lots (host);
+ printk(KERN_ALERT " mail Richard@sleepie.demon.co.uk with ALL\n"
+ " boot messages and diagnostic output\n");
+ FATAL (host);
+ }
+ }
+
+ /*
+ * DSTAT_BF are bus fault errors. DSTAT_800_BF is valid for 710 also.
+ */
+
+ if (dstat & DSTAT_800_BF) {
+ intr_bf (host, cmd);
+ }
+
+
+ /*
+ * DSTAT_SIR interrupts are generated by the execution of
+ * the INT instruction. Since the exact values available
+ * are determined entirely by the SCSI script running,
+ * and are local to a particular script, a unique handler
+ * is called for each script.
+ */
+
+ if (dstat & DSTAT_SIR) {
+ if (hostdata->options & OPTION_DEBUG_INTR)
+ printk ("scsi%d : DSTAT_SIR\n", host->host_no);
+ switch ((tmp = hostdata->dstat_sir_intr (host, cmd))) {
+ case SPECIFIC_INT_NOTHING:
+ case SPECIFIC_INT_RESTART:
+ break;
+ case SPECIFIC_INT_ABORT:
+ abort_connected(host);
+ break;
+ case SPECIFIC_INT_PANIC:
+ printk(KERN_ALERT "scsi%d : failure at ", host->host_no);
+ print_insn (host, dsp, KERN_ALERT "", 1);
+ printk(KERN_ALERT " dstat_sir_intr() returned SPECIFIC_INT_PANIC\n");
+ FATAL (host);
+ break;
+ case SPECIFIC_INT_BREAK:
+ intr_break (host, cmd);
+ break;
+ default:
+ printk(KERN_ALERT "scsi%d : failure at ", host->host_no);
+ print_insn (host, dsp, KERN_ALERT "", 1);
+ printk(KERN_ALERT" dstat_sir_intr() returned unknown value %d\n",
+ tmp);
+ FATAL (host);
+ }
+ }
+}
+
+/*
+ * Function : static int print_insn (struct Scsi_Host *host,
+ * u32 *insn, int kernel)
+ *
+ * Purpose : print numeric representation of the instruction pointed
+ * to by insn to the debugging or kernel message buffer
+ * as appropriate.
+ *
+ * If desired, a user level program can interpret this
+ * information.
+ *
+ * Inputs : host, insn - host, pointer to instruction, prefix -
+ * string to prepend, kernel - use printk instead of debugging buffer.
+ *
+ * Returns : size, in u32s, of instruction printed.
+ */
+
+/*
+ * FIXME: should change kernel parameter so that it takes an ENUM
+ * specifying severity - either KERN_ALERT or KERN_PANIC so
+ * all panic messages are output with the same severity.
+ */
+
+static int
+print_insn (struct Scsi_Host *host, const u32 *insn,
+ const char *prefix, int kernel) {
+ char buf[160], /* Temporary buffer and pointer. ICKY
+ arbitrary length. */
+
+
+ *tmp;
+ unsigned char dcmd; /* dcmd register for *insn */
+ int size;
+
+ /*
+ * Check to see if the instruction pointer is not bogus before
+ * indirecting through it; avoiding red-zone at start of
+ * memory.
+ *
+ * FIXME: icky magic needs to happen here on non-intel boxes which
+ * don't have kernel memory mapped in like this. Might be reasonable
+ * to use vverify()?
+ */
+
+ if (MAP_NR(insn) < 1 || MAP_NR(insn + 8) > MAP_NR(high_memory) ||
+ ((((dcmd = (insn[0] >> 24) & 0xff) & DCMD_TYPE_MMI) == DCMD_TYPE_MMI) &&
+ MAP_NR(insn + 12) > MAP_NR(high_memory))) {
+ size = 0;
+ sprintf (buf, "%s%p: address out of range\n",
+ prefix, insn);
+ } else {
+/*
+ * FIXME : (void *) cast in virt_to_bus should be unnecessary, because
+ * it should take const void * as argument.
+ */
+#ifndef CONFIG_MVME166
+ sprintf(buf, "%s0x%lx (virt 0x%p) : 0x%08x 0x%08x (virt 0x%p)",
+ (prefix ? prefix : ""), virt_to_bus((void *) insn), insn,
+ insn[0], insn[1], bus_to_virt (insn[1]));
+#else
+ /* Remove virtual addresses to reduce output, as they are the same */
+ sprintf(buf, "%s0x%x (+%x) : 0x%08x 0x%08x",
+ (prefix ? prefix : ""), (u32)insn, ((u32)insn -
+ (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata)->script))/4,
+ insn[0], insn[1]);
+#endif
+ tmp = buf + strlen(buf);
+ if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI) {
+#ifndef CONFIG_MVME166
+ sprintf (tmp, " 0x%08x (virt 0x%p)\n", insn[2],
+ bus_to_virt(insn[2]));
+#else
+ /* Remove virtual addr to reduce output, as it is the same */
+ sprintf (tmp, " 0x%08x\n", insn[2]);
+#endif
+ size = 3;
+ } else {
+ sprintf (tmp, "\n");
+ size = 2;
+ }
+ }
+
+ if (kernel)
+ printk ("%s", buf);
+#ifdef NCR_DEBUG
+ else {
+ size_t len = strlen(buf);
+ debugger_kernel_write(host, buf, len);
+ }
+#endif
+ return size;
+}
+
+/*
+ * Function : int NCR53c7xx_abort (Scsi_Cmnd *cmd)
+ *
+ * Purpose : Abort an errant SCSI command, doing all necessary
+ * cleanup of the issue_queue, running_list, shared Linux/NCR
+ * dsa issue and reconnect queues.
+ *
+ * Inputs : cmd - command to abort, code - entire result field
+ *
+ * Returns : 0 on success, -1 on failure.
+ */
+
+int
+NCR53c7xx_abort (Scsi_Cmnd *cmd) {
+ NCR53c7x0_local_declare();
+ struct Scsi_Host *host = cmd->host;
+ struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *)
+ host->hostdata : NULL;
+ unsigned long flags;
+ struct NCR53c7x0_cmd *curr, **prev;
+ Scsi_Cmnd *me, **last;
+#if 0
+ static long cache_pid = -1;
+#endif
+
+
+ if (!host) {
+ printk ("Bogus SCSI command pid %ld; no host structure\n",
+ cmd->pid);
+ return SCSI_ABORT_ERROR;
+ } else if (!hostdata) {
+ printk ("Bogus SCSI host %d; no hostdata\n", host->host_no);
+ return SCSI_ABORT_ERROR;
+ }
+ NCR53c7x0_local_setup(host);
+
+/*
+ * CHECK : I don't think that reading ISTAT will unstack any interrupts,
+ * since we need to write the INTF bit to clear it, and SCSI/DMA
+ * interrupts don't clear until we read SSTAT/SIST and DSTAT registers.
+ *
+ * See that this is the case. Appears to be correct on the 710, at least.
+ *
+ * I suspect that several of our failures may be coming from a new fatal
+ * interrupt (possibly due to a phase mismatch) happening after we've left
+ * the interrupt handler, but before the PIC has had the interrupt condition
+ * cleared.
+ */
+
+ if (NCR53c7x0_read8(hostdata->istat) & (ISTAT_DIP|ISTAT_SIP)) {
+ printk ("scsi%d : dropped interrupt for command %ld\n", host->host_no,
+ cmd->pid);
+ NCR53c7x0_intr (host->irq, NULL, NULL);
+ return SCSI_ABORT_BUSY;
+ }
+
+ save_flags(flags);
+ cli();
+#if 0
+ if (cache_pid == cmd->pid)
+ panic ("scsi%d : bloody fetus %d\n", host->host_no, cmd->pid);
+ else
+ cache_pid = cmd->pid;
+#endif
+
+
+/*
+ * The command could be hiding in the issue_queue. This would be very
+ * nice, as commands can't be moved from the high level driver's issue queue
+ * into the shared queue until an interrupt routine is serviced, and this
+ * moving is atomic.
+ *
+ * If this is the case, we don't have to worry about anything - we simply
+ * pull the command out of the old queue, and call it aborted.
+ */
+
+ for (me = (Scsi_Cmnd *) hostdata->issue_queue,
+ last = (Scsi_Cmnd **) &(hostdata->issue_queue);
+ me && me != cmd; last = (Scsi_Cmnd **)&(me->SCp.ptr),
+ me = (Scsi_Cmnd *)me->SCp.ptr);
+
+ if (me) {
+ *last = (Scsi_Cmnd *) me->SCp.ptr;
+ if (me->host_scribble) {
+ ((struct NCR53c7x0_cmd *)me->host_scribble)->next = hostdata->free;
+ hostdata->free = (struct NCR53c7x0_cmd *) me->host_scribble;
+ me->host_scribble = NULL;
+ }
+ cmd->result = DID_ABORT << 16;
+ cmd->scsi_done(cmd);
+ printk ("scsi%d : found command %ld in Linux issue queue\n",
+ host->host_no, me->pid);
+ restore_flags(flags);
+ run_process_issue_queue();
+ return SCSI_ABORT_SUCCESS;
+ }
+
+/*
+ * That failing, the command could be in our list of already executing
+ * commands. If this is the case, drastic measures are called for.
+ */
+
+ for (curr = (struct NCR53c7x0_cmd *) hostdata->running_list,
+ prev = (struct NCR53c7x0_cmd **) &(hostdata->running_list);
+ curr && curr->cmd != cmd; prev = (struct NCR53c7x0_cmd **)
+ &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
+
+ if (curr) {
+ if ((cmd->result & 0xff) != 0xff && (cmd->result & 0xff00) != 0xff00) {
+ if (prev)
+ *prev = (struct NCR53c7x0_cmd *) curr->next;
+ curr->next = (struct NCR53c7x0_cmd *) hostdata->free;
+ cmd->host_scribble = NULL;
+ hostdata->free = curr;
+ cmd->scsi_done(cmd);
+ printk ("scsi%d : found finished command %ld in running list\n",
+ host->host_no, cmd->pid);
+ restore_flags(flags);
+ return SCSI_ABORT_NOT_RUNNING;
+ } else {
+ printk ("scsi%d : DANGER : command running, can not abort.\n",
+ cmd->host->host_no);
+ restore_flags(flags);
+ return SCSI_ABORT_BUSY;
+ }
+ }
+
+/*
+ * And if we couldn't find it in any of our queues, it must have been
+ * a dropped interrupt.
+ */
+
+ curr = (struct NCR53c7x0_cmd *) cmd->host_scribble;
+ if (curr) {
+ curr->next = hostdata->free;
+ hostdata->free = curr;
+ cmd->host_scribble = NULL;
+ }
+
+ if (((cmd->result & 0xff00) == 0xff00) ||
+ ((cmd->result & 0xff) == 0xff)) {
+ printk ("scsi%d : did this command ever run?\n", host->host_no);
+ cmd->result = DID_ABORT << 16;
+ } else {
+ printk ("scsi%d : probably lost INTFLY, normal completion\n",
+ host->host_no);
+/*
+ * FIXME : We need to add an additional flag which indicates if a
+ * command was ever counted as BUSY, so if we end up here we can
+ * decrement the busy count if and only if it is necessary.
+ */
+ --hostdata->busy[cmd->target][cmd->lun];
+ }
+ restore_flags(flags);
+ cmd->scsi_done(cmd);
+
+/*
+ * We need to run process_issue_queue since termination of this command
+ * may allow another queued command to execute first?
+ */
+ return SCSI_ABORT_NOT_RUNNING;
+}
+
+/*
+ * Function : int NCR53c7xx_reset (Scsi_Cmnd *cmd)
+ *
+ * Purpose : perform a hard reset of the SCSI bus and NCR
+ * chip.
+ *
+ * Inputs : cmd - command which caused the SCSI RESET
+ *
+ * Returns : 0 on success.
+ */
+
+int
+NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) {
+ NCR53c7x0_local_declare();
+ unsigned long flags;
+ int found = 0;
+ struct NCR53c7x0_cmd * c;
+ Scsi_Cmnd *tmp;
+ /*
+ * When we call scsi_done(), it's going to wake up anything sleeping on the
+ * resources which were in use by the aborted commands, and we'll start to
+ * get new commands.
+ *
+ * We can't let this happen until after we've re-initialized the driver
+ * structures, and can't reinitialize those structures until after we've
+ * dealt with their contents.
+ *
+ * So, we need to find all of the commands which were running, stick
+ * them on a linked list of completed commands (we'll use the host_scribble
+ * pointer), do our reinitialization, and then call the done function for
+ * each command.
+ */
+ Scsi_Cmnd *nuke_list = NULL;
+ struct Scsi_Host *host = cmd->host;
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata;
+
+ NCR53c7x0_local_setup(host);
+ save_flags(flags);
+ cli();
+ ncr_halt (host);
+ print_lots (host);
+ dump_events (host, 30);
+ ncr_scsi_reset (host);
+ for (tmp = nuke_list = return_outstanding_commands (host, 1 /* free */,
+ 0 /* issue */ ); tmp; tmp = (Scsi_Cmnd *) tmp->SCp.buffer)
+ if (tmp == cmd) {
+ found = 1;
+ break;
+ }
+
+ /*
+ * If we didn't find the command which caused this reset in our running
+ * list, then we've lost it. See that it terminates normally anyway.
+ */
+ if (!found) {
+ c = (struct NCR53c7x0_cmd *) cmd->host_scribble;
+ if (c) {
+ cmd->host_scribble = NULL;
+ c->next = hostdata->free;
+ hostdata->free = c;
+ } else
+ printk ("scsi%d: lost command %ld\n", host->host_no, cmd->pid);
+ cmd->SCp.buffer = (struct scatterlist *) nuke_list;
+ nuke_list = cmd;
+ }
+
+ NCR53c7x0_driver_init (host);
+ hostdata->soft_reset (host);
+ if (hostdata->resets == 0)
+ disable(host);
+ else if (hostdata->resets != -1)
+ --hostdata->resets;
+ sti();
+ for (; nuke_list; nuke_list = tmp) {
+ tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
+ nuke_list->result = DID_RESET << 16;
+ nuke_list->scsi_done (nuke_list);
+ }
+ restore_flags(flags);
+ return SCSI_RESET_SUCCESS;
+}
+
+/*
+ * The NCR SDMS bios follows Annex A of the SCSI-CAM draft, and
+ * therefore shares the scsicam_bios_param function.
+ */
+
+/*
+ * Function : int insn_to_offset (Scsi_Cmnd *cmd, u32 *insn)
+ *
+ * Purpose : convert instructions stored at NCR pointer into data
+ * pointer offset.
+ *
+ * Inputs : cmd - SCSI command; insn - pointer to instruction. Either current
+ * DSP, or saved data pointer.
+ *
+ * Returns : offset on success, -1 on failure.
+ */
+
+
+static int
+insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) cmd->host->hostdata;
+ struct NCR53c7x0_cmd *ncmd =
+ (struct NCR53c7x0_cmd *) cmd->host_scribble;
+ int offset = 0, buffers;
+ struct scatterlist *segment;
+ char *ptr;
+ int found = 0;
+
+/*
+ * With the current code implementation, if the insn is inside dynamically
+ * generated code, the data pointer will be the instruction preceding
+ * the next transfer segment.
+ */
+
+ if (!check_address ((unsigned long) ncmd, sizeof (struct NCR53c7x0_cmd)) &&
+ ((insn >= ncmd->data_transfer_start &&
+ insn < ncmd->data_transfer_end) ||
+ (insn >= ncmd->residual &&
+ insn < (ncmd->residual +
+ sizeof(ncmd->residual))))) {
+ ptr = bus_to_virt(insn[3]);
+
+ if ((buffers = cmd->use_sg)) {
+ for (offset = 0,
+ segment = (struct scatterlist *) cmd->buffer;
+ buffers && !((found = ((ptr >= segment->address) &&
+ (ptr < (segment->address + segment->length)))));
+ --buffers, offset += segment->length, ++segment)
+#if 0
+ printk("scsi%d: comparing 0x%p to 0x%p\n",
+ cmd->host->host_no, saved, segment->address);
+#else
+ ;
+#endif
+ offset += ptr - segment->address;
+ } else {
+ found = 1;
+ offset = ptr - (char *) (cmd->request_buffer);
+ }
+ } else if ((insn >= hostdata->script +
+ hostdata->E_data_transfer / sizeof(u32)) &&
+ (insn <= hostdata->script +
+ hostdata->E_end_data_transfer / sizeof(u32))) {
+ found = 1;
+ offset = 0;
+ }
+ return found ? offset : -1;
+}
+
+
+
+/*
+ * Function : void print_progress (Scsi_Cmnd *cmd)
+ *
+ * Purpose : print the current location of the saved data pointer
+ *
+ * Inputs : cmd - command we are interested in
+ *
+ */
+
+static void
+print_progress (Scsi_Cmnd *cmd) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_cmd *ncmd =
+ (struct NCR53c7x0_cmd *) cmd->host_scribble;
+ int offset, i;
+ char *where;
+ u32 *ptr;
+ NCR53c7x0_local_setup (cmd->host);
+ for (i = 0; i < 2; ++i) {
+ if (check_address ((unsigned long) ncmd,
+ sizeof (struct NCR53c7x0_cmd)) == -1)
+ continue;
+ if (!i) {
+ where = "saved";
+ ptr = bus_to_virt(ncmd->saved_data_pointer);
+ } else {
+ where = "active";
+ ptr = bus_to_virt (NCR53c7x0_read32 (DSP_REG) -
+ NCR53c7x0_insn_size (NCR53c7x0_read8 (DCMD_REG)) *
+ sizeof(u32));
+ }
+ offset = insn_to_offset (cmd, ptr);
+
+ if (offset != -1)
+ printk ("scsi%d : %s data pointer at offset %d\n",
+ cmd->host->host_no, where, offset);
+ else {
+ int size;
+ printk ("scsi%d : can't determine %s data pointer offset\n",
+ cmd->host->host_no, where);
+ if (ncmd) {
+ size = print_insn (cmd->host,
+ bus_to_virt(ncmd->saved_data_pointer), "", 1);
+ print_insn (cmd->host,
+ bus_to_virt(ncmd->saved_data_pointer) + size * sizeof(u32),
+ "", 1);
+ }
+ }
+ }
+}
+
+
+static void
+print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ int i, len;
+ char *ptr;
+ Scsi_Cmnd *cmd;
+
+ if (check_address ((unsigned long) dsa, hostdata->dsa_end -
+ hostdata->dsa_start) == -1) {
+ printk("scsi%d : bad dsa virt 0x%p\n", host->host_no, dsa);
+ return;
+ }
+ printk("%sscsi%d : dsa at phys 0x%lx (virt 0x%p)\n"
+ " + %d : dsa_msgout length = %u, data = 0x%x (virt 0x%p)\n" ,
+ prefix ? prefix : "",
+ host->host_no, virt_to_bus (dsa), dsa, hostdata->dsa_msgout,
+ dsa[hostdata->dsa_msgout / sizeof(u32)],
+ dsa[hostdata->dsa_msgout / sizeof(u32) + 1],
+ bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]));
+
+ /*
+ * Only print messages if they're sane in length so we don't
+ * blow the kernel printk buffer on something which won't buy us
+ * anything.
+ */
+
+ if (dsa[hostdata->dsa_msgout / sizeof(u32)] <
+ sizeof (hostdata->free->select))
+ for (i = dsa[hostdata->dsa_msgout / sizeof(u32)],
+ ptr = bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]);
+ i > 0 && !check_address ((unsigned long) ptr, 1);
+ ptr += len, i -= len) {
+ printk(" ");
+ len = print_msg (ptr);
+ printk("\n");
+ if (!len)
+ break;
+ }
+
+ printk(" + %d : select_indirect = 0x%x\n",
+ hostdata->dsa_select, dsa[hostdata->dsa_select / sizeof(u32)]);
+ cmd = (Scsi_Cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
+ printk(" + %d : dsa_cmnd = 0x%x ", hostdata->dsa_cmnd,
+ (u32) virt_to_bus(cmd));
+ if (cmd) {
+ printk(" result = 0x%x, target = %d, lun = %d, cmd = ",
+ cmd->result, cmd->target, cmd->lun);
+ print_command(cmd->cmnd);
+ } else
+ printk("\n");
+ printk(" + %d : dsa_next = 0x%x\n", hostdata->dsa_next,
+ dsa[hostdata->dsa_next / sizeof(u32)]);
+ if (cmd) {
+ printk("scsi%d target %d : sxfer_sanity = 0x%x, scntl3_sanity = 0x%x\n"
+ " script : ",
+ host->host_no, cmd->target,
+ hostdata->sync[cmd->target].sxfer_sanity,
+ hostdata->sync[cmd->target].scntl3_sanity);
+ for (i = 0; i < (sizeof(hostdata->sync[cmd->target].script) / 4); ++i)
+ printk ("0x%x ", hostdata->sync[cmd->target].script[i]);
+ printk ("\n");
+ print_progress (cmd);
+ }
+}
+/*
+ * Function : void print_queues (Scsi_Host *host)
+ *
+ * Purpose : print the contents of the NCR issue and reconnect queues
+ *
+ * Inputs : host - SCSI host we are interested in
+ *
+ */
+
+static void
+print_queues (struct Scsi_Host *host) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ u32 *dsa, *next_dsa;
+ volatile u32 *ncrcurrent;
+ int left;
+ Scsi_Cmnd *cmd, *next_cmd;
+ unsigned long flags;
+
+ printk ("scsi%d : issue queue\n", host->host_no);
+
+ for (left = host->can_queue, cmd = (Scsi_Cmnd *) hostdata->issue_queue;
+ left >= 0 && cmd;
+ cmd = next_cmd) {
+ next_cmd = (Scsi_Cmnd *) cmd->SCp.ptr;
+ save_flags(flags);
+ cli();
+ if (cmd->host_scribble) {
+ if (check_address ((unsigned long) (cmd->host_scribble),
+ sizeof (cmd->host_scribble)) == -1)
+ printk ("scsi%d: scsi pid %ld bad pointer to NCR53c7x0_cmd\n",
+ host->host_no, cmd->pid);
+ /* print_dsa does sanity check on address, no need to check */
+ else
+ print_dsa (host, ((struct NCR53c7x0_cmd *) cmd->host_scribble)
+ -> dsa, "");
+ } else
+ printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
+ host->host_no, cmd->pid, cmd->target, cmd->lun);
+ restore_flags(flags);
+ }
+
+ if (left <= 0) {
+ printk ("scsi%d : loop detected in issue queue\n",
+ host->host_no);
+ }
+
+ /*
+ * Traverse the NCR reconnect and start DSA structures, printing out
+ * each element until we hit the end or detect a loop. Currently,
+ * the reconnect structure is a linked list; and the start structure
+ * is an array. Eventually, the reconnect structure will become a
+ * list as well, since this simplifies the code.
+ */
+
+ printk ("scsi%d : schedule dsa array :\n", host->host_no);
+ for (left = host->can_queue, ncrcurrent = hostdata->schedule;
+ left > 0; ncrcurrent += 2, --left)
+ if (ncrcurrent[0] != hostdata->NOP_insn)
+/* FIXME : convert pointer to dsa_begin to pointer to dsa. */
+ print_dsa (host, bus_to_virt (ncrcurrent[1] -
+ (hostdata->E_dsa_code_begin -
+ hostdata->E_dsa_code_template)), "");
+ printk ("scsi%d : end schedule dsa array\n", host->host_no);
+
+ printk ("scsi%d : reconnect_dsa_head :\n", host->host_no);
+
+ for (left = host->can_queue,
+ dsa = bus_to_virt (hostdata->reconnect_dsa_head);
+ left >= 0 && dsa;
+ dsa = next_dsa) {
+ save_flags (flags);
+ cli();
+ if (check_address ((unsigned long) dsa, sizeof(dsa)) == -1) {
+ printk ("scsi%d: bad DSA pointer 0x%p", host->host_no,
+ dsa);
+ next_dsa = NULL;
+ }
+ else
+ {
+ next_dsa = bus_to_virt(dsa[hostdata->dsa_next / sizeof(u32)]);
+ print_dsa (host, dsa, "");
+ }
+ restore_flags(flags);
+ }
+ printk ("scsi%d : end reconnect_dsa_head\n", host->host_no);
+ if (left < 0)
+ printk("scsi%d: possible loop in ncr reconnect list\n",
+ host->host_no);
+}
+
+static void
+print_lots (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata;
+ u32 *dsp_next, *dsp, *dsa, dbc_dcmd;
+ unsigned char dcmd, sbcl;
+ int i, size;
+ NCR53c7x0_local_setup(host);
+
+ if ((dsp_next = bus_to_virt(NCR53c7x0_read32 (DSP_REG)))) {
+ dbc_dcmd = NCR53c7x0_read32(DBC_REG);
+ dcmd = (dbc_dcmd & 0xff000000) >> 24;
+ dsp = dsp_next - NCR53c7x0_insn_size(dcmd);
+ dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+ sbcl = NCR53c7x0_read8 (SBCL_REG);
+
+ /*
+ * For the 53c710, the following will report value 0 for SCNTL3
+ * and STEST0 - we dont have these registers.
+ */
+ printk ("scsi%d : DCMD|DBC=0x%x, DNAD=0x%x (virt 0x%p)\n"
+ " DSA=0x%lx (virt 0x%p)\n"
+ " DSPS=0x%x, TEMP=0x%x (virt 0x%p), DMODE=0x%x\n"
+ " SXFER=0x%x, SCNTL3=0x%x\n"
+ " %s%s%sphase=%s, %d bytes in SCSI FIFO\n"
+ " STEST0=0x%x\n",
+ host->host_no, dbc_dcmd, NCR53c7x0_read32(DNAD_REG),
+ bus_to_virt(NCR53c7x0_read32(DNAD_REG)),
+ virt_to_bus(dsa), dsa,
+ NCR53c7x0_read32(DSPS_REG), NCR53c7x0_read32(TEMP_REG),
+ bus_to_virt (NCR53c7x0_read32(TEMP_REG)),
+ (int) NCR53c7x0_read8(hostdata->dmode),
+ (int) NCR53c7x0_read8(SXFER_REG),
+ ((hostdata->chip / 100) == 8) ?
+ (int) NCR53c7x0_read8(SCNTL3_REG_800) : 0,
+ (sbcl & SBCL_BSY) ? "BSY " : "",
+ (sbcl & SBCL_SEL) ? "SEL " : "",
+ (sbcl & SBCL_REQ) ? "REQ " : "",
+ sstat2_to_phase(NCR53c7x0_read8 (((hostdata->chip / 100) == 8) ?
+ SSTAT1_REG : SSTAT2_REG)),
+ (NCR53c7x0_read8 ((hostdata->chip / 100) == 8 ?
+ SSTAT1_REG : SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT,
+ ((hostdata->chip / 100) == 8) ?
+ NCR53c7x0_read8 (STEST0_REG_800) : 0);
+ printk ("scsi%d : DSP 0x%lx (virt 0x%p) ->\n", host->host_no,
+ virt_to_bus(dsp), dsp);
+ for (i = 6; i > 0; --i, dsp += size)
+ size = print_insn (host, dsp, "", 1);
+ if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
+ if ((hostdata->chip / 100) == 8)
+ printk ("scsi%d : connected (SDID=0x%x, SSID=0x%x)\n",
+ host->host_no, NCR53c7x0_read8 (SDID_REG_800),
+ NCR53c7x0_read8 (SSID_REG_800));
+ else
+ printk ("scsi%d : connected (SDID=0x%x)\n",
+ host->host_no, NCR53c7x0_read8 (SDID_REG_700));
+ print_dsa (host, dsa, "");
+ }
+
+#if 1
+ print_queues (host);
+#endif
+ }
+}
+
+/*
+ * Function : static int shutdown (struct Scsi_Host *host)
+ *
+ * Purpose : does a clean (we hope) shutdown of the NCR SCSI
+ * chip. Use prior to dumping core, unloading the NCR driver,
+ *
+ * Returns : 0 on success
+ */
+static int
+shutdown (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ unsigned long flags;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ NCR53c7x0_local_setup(host);
+ save_flags (flags);
+ cli();
+/* Get in a state where we can reset the SCSI bus */
+ ncr_halt (host);
+ ncr_scsi_reset (host);
+ hostdata->soft_reset(host);
+
+ disable (host);
+ restore_flags (flags);
+ return 0;
+}
+
+/*
+ * Function : void ncr_scsi_reset (struct Scsi_Host *host)
+ *
+ * Purpose : reset the SCSI bus.
+ */
+
+static void
+ncr_scsi_reset (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ unsigned long flags;
+ NCR53c7x0_local_setup(host);
+ save_flags (flags);
+ cli();
+ NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
+ udelay(25); /* Minimum amount of time to assert RST */
+ NCR53c7x0_write8(SCNTL1_REG, 0);
+ restore_flags (flags);
+}
+
+/*
+ * Function : void hard_reset (struct Scsi_Host *host)
+ *
+ */
+
+static void
+hard_reset (struct Scsi_Host *host) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ unsigned long flags;
+ save_flags (flags);
+ cli();
+ ncr_scsi_reset(host);
+ NCR53c7x0_driver_init (host);
+ if (hostdata->soft_reset)
+ hostdata->soft_reset (host);
+ restore_flags(flags);
+}
+
+
+/*
+ * Function : Scsi_Cmnd *return_outstanding_commands (struct Scsi_Host *host,
+ * int free, int issue)
+ *
+ * Purpose : return a linked list (using the SCp.buffer field as next,
+ * so we don't perturb hostdata. We don't use a field of the
+ * NCR53c7x0_cmd structure since we may not have allocated one
+ * for the command causing the reset.) of Scsi_Cmnd structures that
+ * had propogated below the Linux issue queue level. If free is set,
+ * free the NCR53c7x0_cmd structures which are associated with
+ * the Scsi_Cmnd structures, and clean up any internal
+ * NCR lists that the commands were on. If issue is set,
+ * also return commands in the issue queue.
+ *
+ * Returns : linked list of commands
+ *
+ * NOTE : the caller should insure that the NCR chip is halted
+ * if the free flag is set.
+ */
+
+static Scsi_Cmnd *
+return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ struct NCR53c7x0_cmd *c;
+ int i;
+ u32 *ncrcurrent;
+ Scsi_Cmnd *list = NULL, *tmp;
+ for (c = (struct NCR53c7x0_cmd *) hostdata->running_list; c;
+ c = (struct NCR53c7x0_cmd *) c->next) {
+ if (c->cmd->SCp.buffer) {
+ printk ("scsi%d : loop detected in running list!\n", host->host_no);
+ break;
+ } else {
+ printk ("The sti() implicit in a printk() prevents hangs\n");
+ break;
+ }
+
+ c->cmd->SCp.buffer = (struct scatterlist *) list;
+ list = c->cmd;
+ if (free) {
+ c->next = hostdata->free;
+ hostdata->free = c;
+ }
+ }
+
+ if (free) {
+ for (i = 0, ncrcurrent = (u32 *) hostdata->schedule;
+ i < host->can_queue; ++i, ncrcurrent += 2) {
+ ncrcurrent[0] = hostdata->NOP_insn;
+ ncrcurrent[1] = 0xdeadbeef;
+ }
+ hostdata->ncrcurrent = NULL;
+ }
+
+ if (issue) {
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; tmp = tmp->next) {
+ if (tmp->SCp.buffer) {
+ printk ("scsi%d : loop detected in issue queue!\n",
+ host->host_no);
+ break;
+ }
+ tmp->SCp.buffer = (struct scatterlist *) list;
+ list = tmp;
+ }
+ if (free)
+ hostdata->issue_queue = NULL;
+
+ }
+ return list;
+}
+
+/*
+ * Function : static int disable (struct Scsi_Host *host)
+ *
+ * Purpose : disables the given NCR host, causing all commands
+ * to return a driver error. Call this so we can unload the
+ * module during development and try again. Eventually,
+ * we should be able to find clean workarounds for these
+ * problems.
+ *
+ * Inputs : host - hostadapter to twiddle
+ *
+ * Returns : 0 on success.
+ */
+
+static int
+disable (struct Scsi_Host *host) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ unsigned long flags;
+ Scsi_Cmnd *nuke_list, *tmp;
+ save_flags(flags);
+ cli();
+ if (hostdata->state != STATE_HALTED)
+ ncr_halt (host);
+ nuke_list = return_outstanding_commands (host, 1 /* free */, 1 /* issue */);
+ hard_reset (host);
+ hostdata->state = STATE_DISABLED;
+ restore_flags(flags);
+ printk ("scsi%d : nuking commands\n", host->host_no);
+ for (; nuke_list; nuke_list = tmp) {
+ tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
+ nuke_list->result = DID_ERROR << 16;
+ nuke_list->scsi_done(nuke_list);
+ }
+ printk ("scsi%d : done. \n", host->host_no);
+ printk (KERN_ALERT "scsi%d : disabled. Unload and reload\n",
+ host->host_no);
+ return 0;
+}
+
+/*
+ * Function : static int ncr_halt (struct Scsi_Host *host)
+ *
+ * Purpose : halts the SCSI SCRIPTS(tm) processor on the NCR chip
+ *
+ * Inputs : host - SCSI chip to halt
+ *
+ * Returns : 0 on success
+ */
+
+static int
+ncr_halt (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ unsigned long flags;
+ unsigned char istat, tmp;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ int stage;
+ NCR53c7x0_local_setup(host);
+
+ save_flags(flags);
+ cli();
+ /* Stage 0 : eat all interrupts
+ Stage 1 : set ABORT
+ Stage 2 : eat all but abort interrupts
+ Stage 3 : eat all interrupts
+ */
+ for (stage = 0;;) {
+ if (stage == 1) {
+ NCR53c7x0_write8(hostdata->istat, ISTAT_ABRT);
+ ++stage;
+ }
+ istat = NCR53c7x0_read8 (hostdata->istat);
+ if (istat & ISTAT_SIP) {
+ tmp = NCR53c7x0_read8(SSTAT0_REG);
+ } else if (istat & ISTAT_DIP) {
+ tmp = NCR53c7x0_read8(DSTAT_REG);
+ if (stage == 2) {
+ if (tmp & DSTAT_ABRT) {
+ NCR53c7x0_write8(hostdata->istat, 0);
+ ++stage;
+ } else {
+ printk(KERN_ALERT "scsi%d : could not halt NCR chip\n",
+ host->host_no);
+ disable (host);
+ }
+ }
+ }
+ if (!(istat & (ISTAT_SIP|ISTAT_DIP)))
+ if (stage == 0)
+ ++stage;
+ else if (stage == 3)
+ break;
+ }
+ hostdata->state = STATE_HALTED;
+ restore_flags(flags);
+#if 0
+ print_lots (host);
+#endif
+ return 0;
+}
+
+/*
+ * Function: event_name (int event)
+ *
+ * Purpose: map event enum into user-readable strings.
+ */
+
+static const char *
+event_name (int event) {
+ switch (event) {
+ case EVENT_NONE: return "none";
+ case EVENT_ISSUE_QUEUE: return "to issue queue";
+ case EVENT_START_QUEUE: return "to start queue";
+ case EVENT_SELECT: return "selected";
+ case EVENT_DISCONNECT: return "disconnected";
+ case EVENT_RESELECT: return "reselected";
+ case EVENT_COMPLETE: return "completed";
+ case EVENT_IDLE: return "idle";
+ case EVENT_SELECT_FAILED: return "select failed";
+ case EVENT_BEFORE_SELECT: return "before select";
+ case EVENT_RESELECT_FAILED: return "reselect failed";
+ default: return "unknown";
+ }
+}
+
+/*
+ * Function : void dump_events (struct Scsi_Host *host, count)
+ *
+ * Purpose : print last count events which have occurred.
+ */
+static void
+dump_events (struct Scsi_Host *host, int count) {
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ struct NCR53c7x0_event event;
+ int i;
+ unsigned long flags;
+ if (hostdata->events) {
+ if (count > hostdata->event_size)
+ count = hostdata->event_size;
+ for (i = hostdata->event_index; count > 0;
+ i = (i ? i - 1 : hostdata->event_size -1), --count) {
+ save_flags(flags);
+/*
+ * By copying the event we're currently examining with interrupts
+ * disabled, we can do multiple printk(), etc. operations and
+ * still be guaranteed that they're happening on the same
+ * event structure.
+ */
+ cli();
+#if 0
+ event = hostdata->events[i];
+#else
+ memcpy ((void *) &event, (void *) &(hostdata->events[i]),
+ sizeof(event));
+#endif
+
+ restore_flags(flags);
+ printk ("scsi%d : %s event %d at %ld secs %ld usecs target %d lun %d\n",
+ host->host_no, event_name (event.event), count,
+ (long) event.time.tv_sec, (long) event.time.tv_usec,
+ event.target, event.lun);
+ if (event.dsa)
+ printk (" event for dsa 0x%lx (virt 0x%p)\n",
+ virt_to_bus(event.dsa), event.dsa);
+ if (event.pid != -1) {
+ printk (" event for pid %ld ", event.pid);
+ print_command (event.cmnd);
+ }
+ }
+ }
+}
+
+/*
+ * Function: check_address
+ *
+ * Purpose: Check to see if a possibly corrupt pointer will fault the
+ * kernel.
+ *
+ * Inputs: addr - address; size - size of area
+ *
+ * Returns: 0 if area is OK, -1 on error.
+ *
+ * NOTES: should be implemented in terms of vverify on kernels
+ * that have it.
+ */
+
+static int
+check_address (unsigned long addr, int size) {
+ return (MAP_NR(addr) < 1 || MAP_NR(addr + size) > MAP_NR(high_memory) ?
+ -1 : 0);
+}
+
+#ifdef MODULE
+int
+NCR53c7x0_release(struct Scsi_Host *host) {
+ struct NCR53c7x0_hostdata *hostdata =
+ (struct NCR53c7x0_hostdata *) host->hostdata;
+ struct NCR53c7x0_cmd *cmd, *tmp;
+ shutdown (host);
+ if (host->irq != IRQ_NONE)
+ {
+ int irq_count;
+ struct Scsi_Host *tmp;
+ for (irq_count = 0, tmp = first_host; tmp; tmp = tmp->next)
+ if (tmp->hostt == the_template && tmp->irq == host->irq)
+ ++irq_count;
+ if (irq_count == 1)
+ free_irq(host->irq, NULL);
+ }
+ if (host->dma_channel != DMA_NONE)
+ free_dma(host->dma_channel);
+ if (host->io_port)
+ release_region(host->io_port, host->n_io_port);
+
+ for (cmd = (struct NCR53c7x0_cmd *) hostdata->free; cmd; cmd = tmp,
+ --hostdata->num_cmds) {
+ tmp = (struct NCR53c7x0_cmd *) cmd->next;
+ /*
+ * If we're going to loop, try to stop it to get a more accurate
+ * count of the leaked commands.
+ */
+ cmd->next = NULL;
+ if (cmd->free)
+ cmd->free ((void *) cmd->real, cmd->size);
+ }
+ if (hostdata->num_cmds)
+ printk ("scsi%d : leaked %d NCR53c7x0_cmd structures\n",
+ host->host_no, hostdata->num_cmds);
+ if (hostdata->events)
+ vfree ((void *)hostdata->events);
+ return 1;
+}
+Scsi_Host_Template driver_template = NCR53c7xx;
+#include "scsi_module.c"
+#endif /* def MODULE */
diff --git a/drivers/scsi/53c7xx.h b/drivers/scsi/53c7xx.h
new file mode 100644
index 000000000..56271a104
--- /dev/null
+++ b/drivers/scsi/53c7xx.h
@@ -0,0 +1,1675 @@
+/*
+ * 53c710 driver. Modified from Drew Eckhardts driver
+ * for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * I have left the code for the 53c8xx family in here, because it didn't
+ * seem worth removing it. The possibility of IO_MAPPED chips rather
+ * than MEMORY_MAPPED remains, in case someone wants to add support for
+ * 53c710 chips on Intel PCs (some older machines have them on the
+ * motherboard).
+ *
+ * NOTE THERE MAY BE PROBLEMS WITH CASTS IN read8 AND Co.
+ */
+
+/*
+ * NCR 53c{7,8}0x0 driver, header file
+ *
+ * Sponsored by
+ * iX Multiuser Multitasking Magazine
+ * Hannover, Germany
+ * hm@ix.de
+ *
+ * Copyright 1993, 1994, 1995 Drew Eckhardt
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@PoohSticks.ORG
+ * +1 (303) 786-7975
+ *
+ * TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
+ *
+ * PRE-ALPHA
+ *
+ * For more information, please consult
+ *
+ * NCR 53C700/53C700-66
+ * SCSI I/O Processor
+ * Data Manual
+ *
+ * NCR 53C810
+ * PCI-SCSI I/O Processor
+ * Data Manual
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * +1 (719) 578-3400
+ *
+ * Toll free literature number
+ * +1 (800) 334-5454
+ *
+ */
+
+#ifndef NCR53c710_H
+#define NCR53c710_H
+#if !defined(LINUX_1_2) && !defined(LINUX_1_3)
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > 65536 + 3 * 256
+#define LINUX_1_3
+#else
+#define LINUX_1_2
+#endif
+#endif
+
+/*
+ * Prevent name space pollution in hosts.c, and only provide the
+ * define we need to get the NCR53c7x0 driver into the host template
+ * array.
+ */
+
+#if defined(HOSTS_C) || defined(MODULE)
+#include <scsi/scsicam.h>
+
+extern int NCR53c7xx_abort(Scsi_Cmnd *);
+extern int NCR53c7xx_detect(Scsi_Host_Template *tpnt);
+extern int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+#ifdef MODULE
+extern int NCR53c7xx_release(struct Scsi_Host *);
+#else
+#define NCR53c7xx_release NULL
+#endif
+
+#ifdef LINUX_1_2
+#define NCR53c7xx {NULL, NULL, "NCR53c{7,8}xx (rel 17)", NCR53c7xx_detect,\
+ NULL, /* info */ NULL, /* command, deprecated */ NULL, \
+ NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset, \
+ NULL /* slave attach */, scsicam_bios_param, /* can queue */ 24, \
+ /* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 3, \
+ /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING}
+#else
+#define NCR53c7xx {NULL, NULL, NULL, NULL, \
+ "NCR53c{7,8}xx (rel 17)", NCR53c7xx_detect,\
+ NULL, /* info */ NULL, /* command, deprecated */ NULL, \
+ NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset, \
+ NULL /* slave attach */, scsicam_bios_param, /* can queue */ 24, \
+ /* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 3, \
+ /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING}
+#endif
+
+#endif /* defined(HOSTS_C) || defined(MODULE) */
+
+#ifndef HOSTS_C
+#ifdef LINUX_1_2
+/*
+ * Change virtual addresses to physical addresses and vv.
+ * These are trivial on the 1:1 Linux/i386 mapping (but if we ever
+ * make the kernel segment mapped at 0, we need to do translation
+ * on the i386 as well)
+ */
+extern inline unsigned long virt_to_phys(volatile void * address)
+{
+ return (unsigned long) address;
+}
+
+extern inline void * phys_to_virt(unsigned long address)
+{
+ return (void *) address;
+}
+
+/*
+ * IO bus memory addresses are also 1:1 with the physical address
+ */
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the x86 architecture, we just read/write the
+ * memory location directly.
+ */
+#define readb(addr) (*(volatile unsigned char *) (addr))
+#define readw(addr) (*(volatile unsigned short *) (addr))
+#define readl(addr) (*(volatile unsigned int *) (addr))
+
+#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+
+#define mb()
+
+#endif /* def LINUX_1_2 */
+
+/* SCSI control 0 rw, default = 0xc0 */
+#define SCNTL0_REG 0x00
+#define SCNTL0_ARB1 0x80 /* 0 0 = simple arbitration */
+#define SCNTL0_ARB2 0x40 /* 1 1 = full arbitration */
+#define SCNTL0_STRT 0x20 /* Start Sequence */
+#define SCNTL0_WATN 0x10 /* Select with ATN */
+#define SCNTL0_EPC 0x08 /* Enable parity checking */
+/* Bit 2 is reserved on 800 series chips */
+#define SCNTL0_EPG_700 0x04 /* Enable parity generation */
+#define SCNTL0_AAP 0x02 /* ATN/ on parity error */
+#define SCNTL0_TRG 0x01 /* Target mode */
+
+/* SCSI control 1 rw, default = 0x00 */
+
+#define SCNTL1_REG 0x01
+#define SCNTL1_EXC 0x80 /* Extra Clock Cycle of Data setup */
+#define SCNTL1_ADB 0x40 /* contents of SODL on bus */
+#define SCNTL1_ESR_700 0x20 /* Enable SIOP response to selection
+ and reselection */
+#define SCNTL1_DHP_800 0x20 /* Disable halt on parity error or ATN
+ target mode only */
+#define SCNTL1_CON 0x10 /* Connected */
+#define SCNTL1_RST 0x08 /* SCSI RST/ */
+#define SCNTL1_AESP 0x04 /* Force bad parity */
+#define SCNTL1_SND_700 0x02 /* Start SCSI send */
+#define SCNTL1_IARB_800 0x02 /* Immediate Arbitration, start
+ arbitration immediately after
+ busfree is detected */
+#define SCNTL1_RCV_700 0x01 /* Start SCSI receive */
+#define SCNTL1_SST_800 0x01 /* Start SCSI transfer */
+
+/* SCSI control 2 rw, */
+
+#define SCNTL2_REG_800 0x02
+#define SCNTL2_800_SDU 0x80 /* SCSI disconnect unexpected */
+
+/* SCSI control 3 rw */
+
+#define SCNTL3_REG_800 0x03
+#define SCNTL3_800_SCF_SHIFT 4
+#define SCNTL3_800_SCF_MASK 0x70
+#define SCNTL3_800_SCF2 0x40 /* Synchronous divisor */
+#define SCNTL3_800_SCF1 0x20 /* 0x00 = SCLK/3 */
+#define SCNTL3_800_SCF0 0x10 /* 0x10 = SCLK/1 */
+ /* 0x20 = SCLK/1.5
+ 0x30 = SCLK/2
+ 0x40 = SCLK/3 */
+
+#define SCNTL3_800_CCF_SHIFT 0
+#define SCNTL3_800_CCF_MASK 0x07
+#define SCNTL3_800_CCF2 0x04 /* 0x00 50.01 to 66 */
+#define SCNTL3_800_CCF1 0x02 /* 0x01 16.67 to 25 */
+#define SCNTL3_800_CCF0 0x01 /* 0x02 25.01 - 37.5
+ 0x03 37.51 - 50
+ 0x04 50.01 - 66 */
+
+/*
+ * SCSI destination ID rw - the appropriate bit is set for the selected
+ * target ID. This is written by the SCSI SCRIPTS processor.
+ * default = 0x00
+ */
+#define SDID_REG_700 0x02
+#define SDID_REG_800 0x06
+
+#define GP_REG_800 0x07 /* General purpose IO */
+#define GP_800_IO1 0x02
+#define GP_800_IO2 0x01
+
+/* SCSI interrupt enable rw, default = 0x00 */
+#define SIEN_REG_700 0x03
+#define SIEN0_REG_800 0x40
+#define SIEN_MA 0x80 /* Phase mismatch (ini) or ATN (tgt) */
+#define SIEN_FC 0x40 /* Function complete */
+#define SIEN_700_STO 0x20 /* Selection or reselection timeout */
+#define SIEN_800_SEL 0x20 /* Selected */
+#define SIEN_700_SEL 0x10 /* Selected or reselected */
+#define SIEN_800_RESEL 0x10 /* Reselected */
+#define SIEN_SGE 0x08 /* SCSI gross error */
+#define SIEN_UDC 0x04 /* Unexpected disconnect */
+#define SIEN_RST 0x02 /* SCSI RST/ received */
+#define SIEN_PAR 0x01 /* Parity error */
+
+/*
+ * SCSI chip ID rw
+ * NCR53c700 :
+ * When arbitrating, the highest bit is used, when reselection or selection
+ * occurs, the chip responds to all IDs for which a bit is set.
+ * default = 0x00
+ * NCR53c810 :
+ * Uses bit mapping
+ */
+#define SCID_REG 0x04
+/* Bit 7 is reserved on 800 series chips */
+#define SCID_800_RRE 0x40 /* Enable response to reselection */
+#define SCID_800_SRE 0x20 /* Enable response to selection */
+/* Bits four and three are reserved on 800 series chips */
+#define SCID_800_ENC_MASK 0x07 /* Encoded SCSI ID */
+
+/* SCSI transfer rw, default = 0x00 */
+#define SXFER_REG 0x05
+#define SXFER_DHP 0x80 /* Disable halt on parity */
+
+#define SXFER_TP2 0x40 /* Transfer period msb */
+#define SXFER_TP1 0x20
+#define SXFER_TP0 0x10 /* lsb */
+#define SXFER_TP_MASK 0x70
+/* FIXME : SXFER_TP_SHIFT == 5 is right for '8xx chips */
+#define SXFER_TP_SHIFT 5
+#define SXFER_TP_4 0x00 /* Divisors */
+#define SXFER_TP_5 0x10<<1
+#define SXFER_TP_6 0x20<<1
+#define SXFER_TP_7 0x30<<1
+#define SXFER_TP_8 0x40<<1
+#define SXFER_TP_9 0x50<<1
+#define SXFER_TP_10 0x60<<1
+#define SXFER_TP_11 0x70<<1
+
+#define SXFER_MO3 0x08 /* Max offset msb */
+#define SXFER_MO2 0x04
+#define SXFER_MO1 0x02
+#define SXFER_MO0 0x01 /* lsb */
+#define SXFER_MO_MASK 0x0f
+#define SXFER_MO_SHIFT 0
+
+/*
+ * SCSI output data latch rw
+ * The contents of this register are driven onto the SCSI bus when
+ * the Assert Data Bus bit of the SCNTL1 register is set and
+ * the CD, IO, and MSG bits of the SOCL register match the SCSI phase
+ */
+#define SODL_REG_700 0x06
+#define SODL_REG_800 0x54
+
+
+/*
+ * SCSI output control latch rw, default = 0
+ * Note that when the chip is being manually programmed as an initiator,
+ * the MSG, CD, and IO bits must be set correctly for the phase the target
+ * is driving the bus in. Otherwise no data transfer will occur due to
+ * phase mismatch.
+ */
+
+#define SOCL_REG 0x07
+#define SOCL_REQ 0x80 /* REQ */
+#define SOCL_ACK 0x40 /* ACK */
+#define SOCL_BSY 0x20 /* BSY */
+#define SOCL_SEL 0x10 /* SEL */
+#define SOCL_ATN 0x08 /* ATN */
+#define SOCL_MSG 0x04 /* MSG */
+#define SOCL_CD 0x02 /* C/D */
+#define SOCL_IO 0x01 /* I/O */
+
+/*
+ * SCSI first byte received latch ro
+ * This register contains the first byte received during a block MOVE
+ * SCSI SCRIPTS instruction, including
+ *
+ * Initiator mode Target mode
+ * Message in Command
+ * Status Message out
+ * Data in Data out
+ *
+ * It also contains the selecting or reselecting device's ID and our
+ * ID.
+ *
+ * Note that this is the register the various IF conditionals can
+ * operate on.
+ */
+#define SFBR_REG 0x08
+
+/*
+ * SCSI input data latch ro
+ * In initiator mode, data is latched into this register on the rising
+ * edge of REQ/. In target mode, data is latched on the rising edge of
+ * ACK/
+ */
+#define SIDL_REG_700 0x09
+#define SIDL_REG_800 0x50
+
+/*
+ * SCSI bus data lines ro
+ * This register reflects the instantaneous status of the SCSI data
+ * lines. Note that SCNTL0 must be set to disable parity checking,
+ * otherwise reading this register will latch new parity.
+ */
+#define SBDL_REG_700 0x0a
+#define SBDL_REG_800 0x58
+
+#define SSID_REG_800 0x0a
+#define SSID_800_VAL 0x80 /* Exactly two bits asserted at sel */
+#define SSID_800_ENCID_MASK 0x07 /* Device which performed operation */
+
+
+/*
+ * SCSI bus control lines rw,
+ * instantaneous readout of control lines
+ */
+#define SBCL_REG 0x0b
+#define SBCL_REQ 0x80 /* REQ ro */
+#define SBCL_ACK 0x40 /* ACK ro */
+#define SBCL_BSY 0x20 /* BSY ro */
+#define SBCL_SEL 0x10 /* SEL ro */
+#define SBCL_ATN 0x08 /* ATN ro */
+#define SBCL_MSG 0x04 /* MSG ro */
+#define SBCL_CD 0x02 /* C/D ro */
+#define SBCL_IO 0x01 /* I/O ro */
+#define SBCL_PHASE_CMDOUT SBCL_CD
+#define SBCL_PHASE_DATAIN SBCL_IO
+#define SBCL_PHASE_DATAOUT 0
+#define SBCL_PHASE_MSGIN (SBCL_CD|SBCL_IO|SBCL_MSG)
+#define SBCL_PHASE_MSGOUT (SBCL_CD|SBCL_MSG)
+#define SBCL_PHASE_STATIN (SBCL_CD|SBCL_IO)
+#define SBCL_PHASE_MASK (SBCL_CD|SBCL_IO|SBCL_MSG)
+/*
+ * Synchronous SCSI Clock Control bits
+ * 0 - set by DCNTL
+ * 1 - SCLK / 1.0
+ * 2 - SCLK / 1.5
+ * 3 - SCLK / 2.0
+ */
+#define SBCL_SSCF1 0x02 /* wo, -66 only */
+#define SBCL_SSCF0 0x01 /* wo, -66 only */
+#define SBCL_SSCF_MASK 0x03
+
+/*
+ * XXX note : when reading the DSTAT and STAT registers to clear interrupts,
+ * insure that 10 clocks elapse between the two
+ */
+/* DMA status ro */
+#define DSTAT_REG 0x0c
+#define DSTAT_DFE 0x80 /* DMA FIFO empty */
+#define DSTAT_800_MDPE 0x40 /* Master Data Parity Error */
+#define DSTAT_800_BF 0x20 /* Bus Fault */
+#define DSTAT_ABRT 0x10 /* Aborted - set on error */
+#define DSTAT_SSI 0x08 /* SCRIPTS single step interrupt */
+#define DSTAT_SIR 0x04 /* SCRIPTS interrupt received -
+ set when INT instruction is
+ executed */
+#define DSTAT_WTD 0x02 /* Watchdog timeout detected */
+#define DSTAT_OPC 0x01 /* Illegal instruction */
+#define DSTAT_800_IID 0x01 /* Same thing, different name */
+
+
+/* NCR53c800 moves this stuff into SIST0 */
+#define SSTAT0_REG 0x0d /* SCSI status 0 ro */
+#define SIST0_REG_800 0x42
+#define SSTAT0_MA 0x80 /* ini : phase mismatch,
+ * tgt : ATN/ asserted
+ */
+#define SSTAT0_CMP 0x40 /* function complete */
+#define SSTAT0_700_STO 0x20 /* Selection or reselection timeout */
+#define SIST0_800_SEL 0x20 /* Selected */
+#define SSTAT0_700_SEL 0x10 /* Selected or reselected */
+#define SIST0_800_RSL 0x10 /* Reselected */
+#define SSTAT0_SGE 0x08 /* SCSI gross error */
+#define SSTAT0_UDC 0x04 /* Unexpected disconnect */
+#define SSTAT0_RST 0x02 /* SCSI RST/ received */
+#define SSTAT0_PAR 0x01 /* Parity error */
+
+/* And uses SSTAT0 for what was SSTAT1 */
+
+#define SSTAT1_REG 0x0e /* SCSI status 1 ro */
+#define SSTAT1_ILF 0x80 /* SIDL full */
+#define SSTAT1_ORF 0x40 /* SODR full */
+#define SSTAT1_OLF 0x20 /* SODL full */
+#define SSTAT1_AIP 0x10 /* Arbitration in progress */
+#define SSTAT1_LOA 0x08 /* Lost arbitration */
+#define SSTAT1_WOA 0x04 /* Won arbitration */
+#define SSTAT1_RST 0x02 /* Instant readout of RST/ */
+#define SSTAT1_SDP 0x01 /* Instant readout of SDP/ */
+
+#define SSTAT2_REG 0x0f /* SCSI status 2 ro */
+#define SSTAT2_FF3 0x80 /* number of bytes in synchronous */
+#define SSTAT2_FF2 0x40 /* data FIFO */
+#define SSTAT2_FF1 0x20
+#define SSTAT2_FF0 0x10
+#define SSTAT2_FF_MASK 0xf0
+#define SSTAT2_FF_SHIFT 4
+
+/*
+ * Latched signals, latched on the leading edge of REQ/ for initiators,
+ * ACK/ for targets.
+ */
+#define SSTAT2_SDP 0x08 /* SDP */
+#define SSTAT2_MSG 0x04 /* MSG */
+#define SSTAT2_CD 0x02 /* C/D */
+#define SSTAT2_IO 0x01 /* I/O */
+#define SSTAT2_PHASE_CMDOUT SSTAT2_CD
+#define SSTAT2_PHASE_DATAIN SSTAT2_IO
+#define SSTAT2_PHASE_DATAOUT 0
+#define SSTAT2_PHASE_MSGIN (SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
+#define SSTAT2_PHASE_MSGOUT (SSTAT2_CD|SSTAT2_MSG)
+#define SSTAT2_PHASE_STATIN (SSTAT2_CD|SSTAT2_IO)
+#define SSTAT2_PHASE_MASK (SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
+
+
+/* NCR53c700-66 only */
+#define SCRATCHA_REG_00 0x10 /* through 0x13 Scratch A rw */
+/* NCR53c710 and higher */
+#define DSA_REG 0x10 /* DATA structure address */
+
+#define CTEST0_REG_700 0x14 /* Chip test 0 ro */
+#define CTEST0_REG_800 0x18 /* Chip test 0 rw, general purpose */
+/* 0x80 - 0x04 are reserved */
+#define CTEST0_700_RTRG 0x02 /* Real target mode */
+#define CTEST0_700_DDIR 0x01 /* Data direction, 1 =
+ * SCSI bus to host, 0 =
+ * host to SCSI.
+ */
+
+#define CTEST1_REG_700 0x15 /* Chip test 1 ro */
+#define CTEST1_REG_800 0x19 /* Chip test 1 ro */
+#define CTEST1_FMT3 0x80 /* Identify which byte lanes are empty */
+#define CTEST1_FMT2 0x40 /* in the DMA FIFO */
+#define CTEST1_FMT1 0x20
+#define CTEST1_FMT0 0x10
+
+#define CTEST1_FFL3 0x08 /* Identify which bytes lanes are full */
+#define CTEST1_FFL2 0x04 /* in the DMA FIFO */
+#define CTEST1_FFL1 0x02
+#define CTEST1_FFL0 0x01
+
+#define CTEST2_REG_700 0x16 /* Chip test 2 ro */
+#define CTEST2_REG_800 0x1a /* Chip test 2 ro */
+
+#define CTEST2_800_DDIR 0x80 /* 1 = SCSI->host */
+#define CTEST2_800_SIGP 0x40 /* A copy of SIGP in ISTAT.
+ Reading this register clears */
+#define CTEST2_800_CIO 0x20 /* Configured as IO */.
+#define CTEST2_800_CM 0x10 /* Configured as memory */
+
+/* 0x80 - 0x40 are reserved on 700 series chips */
+#define CTEST2_700_SOFF 0x20 /* SCSI Offset Compare,
+ * As an initiator, this bit is
+ * one when the synchronous offset
+ * is zero, as a target this bit
+ * is one when the synchronous
+ * offset is at the maximum
+ * defined in SXFER
+ */
+#define CTEST2_700_SFP 0x10 /* SCSI FIFO parity bit,
+ * reading CTEST3 unloads a byte
+ * from the FIFO and sets this
+ */
+#define CTEST2_700_DFP 0x08 /* DMA FIFO parity bit,
+ * reading CTEST6 unloads a byte
+ * from the FIFO and sets this
+ */
+#define CTEST2_TEOP 0x04 /* SCSI true end of process,
+ * indicates a totally finished
+ * transfer
+ */
+#define CTEST2_DREQ 0x02 /* Data request signal */
+/* 0x01 is reserved on 700 series chips */
+#define CTEST2_800_DACK 0x01
+
+/*
+ * Chip test 3 ro
+ * Unloads the bottom byte of the eight deep SCSI synchronous FIFO,
+ * check SSTAT2 FIFO full bits to determine size. Note that a GROSS
+ * error results if a read is attempted on this register. Also note
+ * that 16 and 32 bit reads of this register will cause corruption.
+ */
+#define CTEST3_REG_700 0x17
+/* Chip test 3 rw */
+#define CTEST3_REG_800 0x1b
+#define CTEST3_800_V3 0x80 /* Chip revision */
+#define CTEST3_800_V2 0x40
+#define CTEST3_800_V1 0x20
+#define CTEST3_800_V0 0x10
+#define CTEST3_800_FLF 0x08 /* Flush DMA FIFO */
+#define CTEST3_800_CLF 0x04 /* Clear DMA FIFO */
+#define CTEST3_800_FM 0x02 /* Fetch mode pin */
+/* bit 0 is reserved on 800 series chips */
+
+#define CTEST4_REG_700 0x18 /* Chip test 4 rw */
+#define CTEST4_REG_800 0x21 /* Chip test 4 rw */
+/* 0x80 is reserved on 700 series chips */
+#define CTEST4_800_BDIS 0x80 /* Burst mode disable */
+#define CTEST4_ZMOD 0x40 /* High impedance mode */
+#define CTEST4_SZM 0x20 /* SCSI bus high impedance */
+#define CTEST4_700_SLBE 0x10 /* SCSI loopback enabled */
+#define CTEST4_800_SRTM 0x10 /* Shadow Register Test Mode */
+#define CTEST4_700_SFWR 0x08 /* SCSI FIFO write enable,
+ * redirects writes from SODL
+ * to the SCSI FIFO.
+ */
+#define CTEST4_800_MPEE 0x08 /* Enable parity checking
+ during master cycles on PCI
+ bus */
+
+/*
+ * These bits send the contents of the CTEST6 register to the appropriate
+ * byte lane of the 32 bit DMA FIFO. Normal operation is zero, otherwise
+ * the high bit means the low two bits select the byte lane.
+ */
+#define CTEST4_FBL2 0x04
+#define CTEST4_FBL1 0x02
+#define CTEST4_FBL0 0x01
+#define CTEST4_FBL_MASK 0x07
+#define CTEST4_FBL_0 0x04 /* Select DMA FIFO byte lane 0 */
+#define CTEST4_FBL_1 0x05 /* Select DMA FIFO byte lane 1 */
+#define CTEST4_FBL_2 0x06 /* Select DMA FIFO byte lane 2 */
+#define CTEST4_FBL_3 0x07 /* Select DMA FIFO byte lane 3 */
+#define CTEST4_800_SAVE (CTEST4_800_BDIS)
+
+
+#define CTEST5_REG_700 0x19 /* Chip test 5 rw */
+#define CTEST5_REG_800 0x22 /* Chip test 5 rw */
+/*
+ * Clock Address Incrementor. When set, it increments the
+ * DNAD register to the next bus size boundary. It automatically
+ * resets itself when the operation is complete.
+ */
+#define CTEST5_ADCK 0x80
+/*
+ * Clock Byte Counter. When set, it decrements the DBC register to
+ * the next bus size boundary.
+ */
+#define CTEST5_BBCK 0x40
+/*
+ * Reset SCSI Offset. Setting this bit to 1 clears the current offset
+ * pointer in the SCSI synchronous offset counter (SSTAT). This bit
+ * is set to 1 if a SCSI Gross Error Condition occurs. The offset should
+ * be cleared when a synchronous transfer fails. When written, it is
+ * automatically cleared after the SCSI synchronous offset counter is
+ * reset.
+ */
+/* Bit 5 is reserved on 800 series chips */
+#define CTEST5_700_ROFF 0x20
+/*
+ * Master Control for Set or Reset pulses. When 1, causes the low
+ * four bits of register to set when set, 0 causes the low bits to
+ * clear when set.
+ */
+#define CTEST5_MASR 0x10
+#define CTEST5_DDIR 0x08 /* DMA direction */
+/*
+ * Bits 2-0 are reserved on 800 series chips
+ */
+#define CTEST5_700_EOP 0x04 /* End of process */
+#define CTEST5_700_DREQ 0x02 /* Data request */
+#define CTEST5_700_DACK 0x01 /* Data acknowledge */
+
+/*
+ * Chip test 6 rw - writing to this register writes to the byte
+ * lane in the DMA FIFO as determined by the FBL bits in the CTEST4
+ * register.
+ */
+#define CTEST6_REG_700 0x1a
+#define CTEST6_REG_800 0x23
+
+#define CTEST7_REG 0x1b /* Chip test 7 rw */
+/* 0x80 - 0x40 are reserved on NCR53c700 and NCR53c700-66 chips */
+#define CTEST7_10_CDIS 0x80 /* Cache burst disable */
+#define CTEST7_10_SC1 0x40 /* Snoop control bits */
+#define CTEST7_10_SC0 0x20
+#define CTEST7_10_SC_MASK 0x60
+/* 0x20 is reserved on the NCR53c700 */
+#define CTEST7_0060_FM 0x20 /* Fetch mode */
+#define CTEST7_STD 0x10 /* Selection timeout disable */
+#define CTEST7_DFP 0x08 /* DMA FIFO parity bit for CTEST6 */
+#define CTEST7_EVP 0x04 /* 1 = host bus even parity, 0 = odd */
+#define CTEST7_10_TT1 0x02 /* Transfer type */
+#define CTEST7_00_DC 0x02 /* Set to drive DC low during instruction
+ fetch */
+#define CTEST7_DIFF 0x01 /* Differential mode */
+
+#define CTEST7_SAVE ( CTEST7_EVP | CTEST7_DIFF )
+
+
+#define TEMP_REG 0x1c /* through 0x1f Temporary stack rw */
+
+#define DFIFO_REG 0x20 /* DMA FIFO rw */
+/*
+ * 0x80 is reserved on the NCR53c710, the CLF and FLF bits have been
+ * moved into the CTEST8 register.
+ */
+#define DFIFO_00_FLF 0x80 /* Flush DMA FIFO to memory */
+#define DFIFO_00_CLF 0x40 /* Clear DMA and SCSI FIFOs */
+#define DFIFO_BO6 0x40
+#define DFIFO_BO5 0x20
+#define DFIFO_BO4 0x10
+#define DFIFO_BO3 0x08
+#define DFIFO_BO2 0x04
+#define DFIFO_BO1 0x02
+#define DFIFO_BO0 0x01
+#define DFIFO_10_BO_MASK 0x7f /* 7 bit counter */
+#define DFIFO_00_BO_MASK 0x3f /* 6 bit counter */
+
+/*
+ * Interrupt status rw
+ * Note that this is the only register which can be read while SCSI
+ * SCRIPTS are being executed.
+ */
+#define ISTAT_REG_700 0x21
+#define ISTAT_REG_800 0x14
+#define ISTAT_ABRT 0x80 /* Software abort, write
+ *1 to abort, wait for interrupt. */
+/* 0x40 and 0x20 are reserved on NCR53c700 and NCR53c700-66 chips */
+#define ISTAT_10_SRST 0x40 /* software reset */
+#define ISTAT_10_SIGP 0x20 /* signal script */
+/* 0x10 is reserved on NCR53c700 series chips */
+#define ISTAT_800_SEM 0x10 /* semaphore */
+#define ISTAT_CON 0x08 /* 1 when connected */
+#define ISTAT_800_INTF 0x04 /* Interrupt on the fly */
+#define ISTAT_700_PRE 0x04 /* Pointer register empty.
+ * Set to 1 when DSPS and DSP
+ * registers are empty in pipeline
+ * mode, always set otherwise.
+ */
+#define ISTAT_SIP 0x02 /* SCSI interrupt pending from
+ * SCSI portion of SIOP see
+ * SSTAT0
+ */
+#define ISTAT_DIP 0x01 /* DMA interrupt pending
+ * see DSTAT
+ */
+
+/* NCR53c700-66 and NCR53c710 only */
+#define CTEST8_REG 0x22 /* Chip test 8 rw */
+#define CTEST8_0066_EAS 0x80 /* Enable alternate SCSI clock,
+ * ie read from SCLK/ rather than CLK/
+ */
+#define CTEST8_0066_EFM 0x40 /* Enable fetch and master outputs */
+#define CTEST8_0066_GRP 0x20 /* Generate Receive Parity for
+ * pass through. This insures that
+ * bad parity won't reach the host
+ * bus.
+ */
+#define CTEST8_0066_TE 0x10 /* TolerANT enable. Enable
+ * active negation, should only
+ * be used for slow SCSI
+ * non-differential.
+ */
+#define CTEST8_0066_HSC 0x08 /* Halt SCSI clock */
+#define CTEST8_0066_SRA 0x04 /* Shorten REQ/ACK filtering,
+ * must be set for fast SCSI-II
+ * speeds.
+ */
+#define CTEST8_0066_DAS 0x02 /* Disable automatic target/initiator
+ * switching.
+ */
+#define CTEST8_0066_LDE 0x01 /* Last disconnect enable.
+ * The status of pending
+ * disconnect is maintained by
+ * the core, eliminating
+ * the possibility of missing a
+ * selection or reselection
+ * while waiting to fetch a
+ * WAIT DISCONNECT opcode.
+ */
+
+#define CTEST8_10_V3 0x80 /* Chip revision */
+#define CTEST8_10_V2 0x40
+#define CTEST8_10_V1 0x20
+#define CTEST8_10_V0 0x10
+#define CTEST8_10_V_MASK 0xf0
+#define CTEST8_10_FLF 0x08 /* Flush FIFOs */
+#define CTEST8_10_CLF 0x04 /* Clear FIFOs */
+#define CTEST8_10_FM 0x02 /* Fetch pin mode */
+#define CTEST8_10_SM 0x01 /* Snoop pin mode */
+
+
+/*
+ * The CTEST9 register may be used to differentiate between a
+ * NCR53c700 and a NCR53c710.
+ *
+ * Write 0xff to this register.
+ * Read it.
+ * If the contents are 0xff, it is a NCR53c700
+ * If the contents are 0x00, it is a NCR53c700-66 first revision
+ * If the contents are some other value, it is some other NCR53c700-66
+ */
+#define CTEST9_REG_00 0x23 /* Chip test 9 ro */
+#define LCRC_REG_10 0x23
+
+/*
+ * 0x24 through 0x27 are the DMA byte counter register. Instructions
+ * write their high 8 bits into the DCMD register, the low 24 bits into
+ * the DBC register.
+ *
+ * Function is dependent on the command type being executed.
+ */
+
+
+#define DBC_REG 0x24
+/*
+ * For Block Move Instructions, DBC is a 24 bit quantity representing
+ * the number of bytes to transfer.
+ * For Transfer Control Instructions, DBC is bit fielded as follows :
+ */
+/* Bits 20 - 23 should be clear */
+#define DBC_TCI_TRUE (1 << 19) /* Jump when true */
+#define DBC_TCI_COMPARE_DATA (1 << 18) /* Compare data */
+#define DBC_TCI_COMPARE_PHASE (1 << 17) /* Compare phase with DCMD field */
+#define DBC_TCI_WAIT_FOR_VALID (1 << 16) /* Wait for REQ */
+/* Bits 8 - 15 are reserved on some implementations ? */
+#define DBC_TCI_MASK_MASK 0xff00 /* Mask for data compare */
+#define DBC_TCI_MASK_SHIFT 8
+#define DBC_TCI_DATA_MASK 0xff /* Data to be compared */
+#define DBC_TCI_DATA_SHIFT 0
+
+#define DBC_RWRI_IMMEDIATE_MASK 0xff00 /* Immediate data */
+#define DBC_RWRI_IMMEDIATE_SHIFT 8 /* Amount to shift */
+#define DBC_RWRI_ADDRESS_MASK 0x3f0000 /* Register address */
+#define DBC_RWRI_ADDRESS_SHIFT 16
+
+
+/*
+ * DMA command r/w
+ */
+#define DCMD_REG 0x27
+#define DCMD_TYPE_MASK 0xc0 /* Masks off type */
+#define DCMD_TYPE_BMI 0x00 /* Indicates a Block Move instruction */
+#define DCMD_BMI_IO 0x01 /* I/O, CD, and MSG bits selecting */
+#define DCMD_BMI_CD 0x02 /* the phase for the block MOVE */
+#define DCMD_BMI_MSG 0x04 /* instruction */
+
+#define DCMD_BMI_OP_MASK 0x18 /* mask for opcode */
+#define DCMD_BMI_OP_MOVE_T 0x00 /* MOVE */
+#define DCMD_BMI_OP_MOVE_I 0x08 /* MOVE Initiator */
+
+#define DCMD_BMI_INDIRECT 0x20 /* Indirect addressing */
+
+#define DCMD_TYPE_TCI 0x80 /* Indicates a Transfer Control
+ instruction */
+#define DCMD_TCI_IO 0x01 /* I/O, CD, and MSG bits selecting */
+#define DCMD_TCI_CD 0x02 /* the phase for the block MOVE */
+#define DCMD_TCI_MSG 0x04 /* instruction */
+#define DCMD_TCI_OP_MASK 0x38 /* mask for opcode */
+#define DCMD_TCI_OP_JUMP 0x00 /* JUMP */
+#define DCMD_TCI_OP_CALL 0x08 /* CALL */
+#define DCMD_TCI_OP_RETURN 0x10 /* RETURN */
+#define DCMD_TCI_OP_INT 0x18 /* INT */
+
+#define DCMD_TYPE_RWRI 0x40 /* Indicates I/O or register Read/Write
+ instruction */
+#define DCMD_RWRI_OPC_MASK 0x38 /* Opcode mask */
+#define DCMD_RWRI_OPC_WRITE 0x28 /* Write SFBR to register */
+#define DCMD_RWRI_OPC_READ 0x30 /* Read register to SFBR */
+#define DCMD_RWRI_OPC_MODIFY 0x38 /* Modify in place */
+
+#define DCMD_RWRI_OP_MASK 0x07
+#define DCMD_RWRI_OP_MOVE 0x00
+#define DCMD_RWRI_OP_SHL 0x01
+#define DCMD_RWRI_OP_OR 0x02
+#define DCMD_RWRI_OP_XOR 0x03
+#define DCMD_RWRI_OP_AND 0x04
+#define DCMD_RWRI_OP_SHR 0x05
+#define DCMD_RWRI_OP_ADD 0x06
+#define DCMD_RWRI_OP_ADDC 0x07
+
+#define DCMD_TYPE_MMI 0xc0 /* Indicates a Memory Move instruction
+ (three words) */
+
+
+#define DNAD_REG 0x28 /* through 0x2b DMA next address for
+ data */
+#define DSP_REG 0x2c /* through 0x2f DMA SCRIPTS pointer rw */
+#define DSPS_REG 0x30 /* through 0x33 DMA SCRIPTS pointer
+ save rw */
+#define DMODE_REG_00 0x34 /* DMA mode rw */
+#define DMODE_00_BL1 0x80 /* Burst length bits */
+#define DMODE_00_BL0 0x40
+#define DMODE_BL_MASK 0xc0
+/* Burst lengths (800) */
+#define DMODE_BL_2 0x00 /* 2 transfer */
+#define DMODE_BL_4 0x40 /* 4 transfers */
+#define DMODE_BL_8 0x80 /* 8 transfers */
+#define DMODE_BL_16 0xc0 /* 16 transfers */
+
+#define DMODE_10_BL_1 0x00 /* 1 transfer */
+#define DMODE_10_BL_2 0x40 /* 2 transfers */
+#define DMODE_10_BL_4 0x80 /* 4 transfers */
+#define DMODE_10_BL_8 0xc0 /* 8 transfers */
+#define DMODE_10_FC2 0x20 /* Driven to FC2 pin */
+#define DMODE_10_FC1 0x10 /* Driven to FC1 pin */
+#define DMODE_710_PD 0x08 /* Program/data on FC0 pin */
+#define DMODE_710_UO 0x02 /* User prog. output */
+
+#define DMODE_700_BW16 0x20 /* Host buswidth = 16 */
+#define DMODE_700_286 0x10 /* 286 mode */
+#define DMODE_700_IOM 0x08 /* Transfer to IO port */
+#define DMODE_700_FAM 0x04 /* Fixed address mode */
+#define DMODE_700_PIPE 0x02 /* Pipeline mode disables
+ * automatic fetch / exec
+ */
+#define DMODE_MAN 0x01 /* Manual start mode,
+ * requires a 1 to be written
+ * to the start DMA bit in the DCNTL
+ * register to run scripts
+ */
+
+#define DMODE_700_SAVE ( DMODE_00_BL_MASK | DMODE_00_BW16 | DMODE_00_286 )
+
+/* NCR53c800 series only */
+#define SCRATCHA_REG_800 0x34 /* through 0x37 Scratch A rw */
+/* NCR53c710 only */
+#define SCRATCHB_REG_10 0x34 /* through 0x37 scratch B rw */
+
+#define DMODE_REG_10 0x38 /* DMA mode rw, NCR53c710 and newer */
+#define DMODE_800_SIOM 0x20 /* Source IO = 1 */
+#define DMODE_800_DIOM 0x10 /* Destination IO = 1 */
+#define DMODE_800_ERL 0x08 /* Enable Read Line */
+
+/* 35-38 are reserved on 700 and 700-66 series chips */
+#define DIEN_REG 0x39 /* DMA interrupt enable rw */
+/* 0x80, 0x40, and 0x20 are reserved on 700-series chips */
+#define DIEN_800_MDPE 0x40 /* Master data parity error */
+#define DIEN_800_BF 0x20 /* BUS fault */
+#define DIEN_700_BF 0x20 /* BUS fault */
+#define DIEN_ABRT 0x10 /* Enable aborted interrupt */
+#define DIEN_SSI 0x08 /* Enable single step interrupt */
+#define DIEN_SIR 0x04 /* Enable SCRIPTS INT command
+ * interrupt
+ */
+/* 0x02 is reserved on 800 series chips */
+#define DIEN_700_WTD 0x02 /* Enable watchdog timeout interrupt */
+#define DIEN_700_OPC 0x01 /* Enable illegal instruction
+ * interrupt
+ */
+#define DIEN_800_IID 0x01 /* Same meaning, different name */
+
+/*
+ * DMA watchdog timer rw
+ * set in 16 CLK input periods.
+ */
+#define DWT_REG 0x3a
+
+/* DMA control rw */
+#define DCNTL_REG 0x3b
+#define DCNTL_700_CF1 0x80 /* Clock divisor bits */
+#define DCNTL_700_CF0 0x40
+#define DCNTL_700_CF_MASK 0xc0
+/* Clock divisors Divisor SCLK range (MHZ) */
+#define DCNTL_700_CF_2 0x00 /* 2.0 37.51-50.00 */
+#define DCNTL_700_CF_1_5 0x40 /* 1.5 25.01-37.50 */
+#define DCNTL_700_CF_1 0x80 /* 1.0 16.67-25.00 */
+#define DCNTL_700_CF_3 0xc0 /* 3.0 50.01-66.67 (53c700-66) */
+
+#define DCNTL_700_S16 0x20 /* Load scripts 16 bits at a time */
+#define DCNTL_SSM 0x10 /* Single step mode */
+#define DCNTL_700_LLM 0x08 /* Low level mode, can only be set
+ * after selection */
+#define DCNTL_800_IRQM 0x08 /* Totem pole IRQ pin */
+#define DCNTL_STD 0x04 /* Start DMA / SCRIPTS */
+/* 0x02 is reserved */
+#define DCNTL_00_RST 0x01 /* Software reset, resets everything
+ * but 286 mode bit in DMODE. On the
+ * NCR53c710, this bit moved to CTEST8
+ */
+#define DCNTL_10_COM 0x01 /* 700 software compatibility mode */
+#define DCNTL_10_EA 0x20 /* Enable Ack - needed for MVME166 */
+
+#define DCNTL_700_SAVE ( DCNTL_CF_MASK | DCNTL_S16)
+
+
+/* NCR53c700-66 only */
+#define SCRATCHB_REG_00 0x3c /* through 0x3f scratch b rw */
+#define SCRATCHB_REG_800 0x5c /* through 0x5f scratch b rw */
+/* NCR53c710 only */
+#define ADDER_REG_10 0x3c /* Adder, NCR53c710 only */
+
+#define SIEN1_REG_800 0x41
+#define SIEN1_800_STO 0x04 /* selection/reselection timeout */
+#define SIEN1_800_GEN 0x02 /* general purpose timer */
+#define SIEN1_800_HTH 0x01 /* handshake to handshake */
+
+#define SIST1_REG_800 0x43
+#define SIST1_800_STO 0x04 /* selection/reselection timeout */
+#define SIST1_800_GEN 0x02 /* general purpose timer */
+#define SIST1_800_HTH 0x01 /* handshake to handshake */
+
+#define SLPAR_REG_800 0x44 /* Parity */
+
+#define MACNTL_REG_800 0x46 /* Memory access control */
+#define MACNTL_800_TYP3 0x80
+#define MACNTL_800_TYP2 0x40
+#define MACNTL_800_TYP1 0x20
+#define MACNTL_800_TYP0 0x10
+#define MACNTL_800_DWR 0x08
+#define MACNTL_800_DRD 0x04
+#define MACNTL_800_PSCPT 0x02
+#define MACNTL_800_SCPTS 0x01
+
+#define GPCNTL_REG_800 0x47 /* General Purpose Pin Control */
+
+/* Timeouts are expressed such that 0=off, 1=100us, doubling after that */
+#define STIME0_REG_800 0x48 /* SCSI Timer Register 0 */
+#define STIME0_800_HTH_MASK 0xf0 /* Handshake to Handshake timeout */
+#define STIME0_800_HTH_SHIFT 4
+#define STIME0_800_SEL_MASK 0x0f /* Selection timeout */
+#define STIME0_800_SEL_SHIFT 0
+
+#define STIME1_REG_800 0x49
+#define STIME1_800_GEN_MASK 0x0f /* General purpose timer */
+
+#define RESPID_REG_800 0x4a /* Response ID, bit fielded. 8
+ bits on narrow chips, 16 on WIDE */
+
+#define STEST0_REG_800 0x4c
+#define STEST0_800_SLT 0x08 /* Selection response logic test */
+#define STEST0_800_ART 0x04 /* Arbitration priority encoder test */
+#define STEST0_800_SOZ 0x02 /* Synchronous offset zero */
+#define STEST0_800_SOM 0x01 /* Synchronous offset maximum */
+
+#define STEST1_REG_800 0x4d
+#define STEST1_800_SCLK 0x80 /* Disable SCSI clock */
+
+#define STEST2_REG_800 0x4e
+#define STEST2_800_SCE 0x80 /* Enable SOCL/SODL */
+#define STEST2_800_ROF 0x40 /* Reset SCSI sync offset */
+#define STEST2_800_SLB 0x10 /* Enable SCSI loopback mode */
+#define STEST2_800_SZM 0x08 /* SCSI high impedance mode */
+#define STEST2_800_EXT 0x02 /* Extend REQ/ACK filter 30 to 60ns */
+#define STEST2_800_LOW 0x01 /* SCSI low level mode */
+
+#define STEST3_REG_800 0x4f
+#define STEST3_800_TE 0x80 /* Enable active negation */
+#define STEST3_800_STR 0x40 /* SCSI FIFO test read */
+#define STEST3_800_HSC 0x20 /* Halt SCSI clock */
+#define STEST3_800_DSI 0x10 /* Disable single initiator response */
+#define STEST3_800_TTM 0x04 /* Time test mode */
+#define STEST3_800_CSF 0x02 /* Clear SCSI FIFO */
+#define STEST3_800_STW 0x01 /* SCSI FIFO test write */
+
+#define OPTION_PARITY 0x1 /* Enable parity checking */
+#define OPTION_TAGGED_QUEUE 0x2 /* Enable SCSI-II tagged queuing */
+#define OPTION_700 0x8 /* Always run NCR53c700 scripts */
+#define OPTION_INTFLY 0x10 /* Use INTFLY interrupts */
+#define OPTION_DEBUG_INTR 0x20 /* Debug interrupts */
+#define OPTION_DEBUG_INIT_ONLY 0x40 /* Run initialization code and
+ simple test code, return
+ DID_NO_CONNECT if any SCSI
+ commands are attempted. */
+#define OPTION_DEBUG_READ_ONLY 0x80 /* Return DID_ERROR if any
+ SCSI write is attempted */
+#define OPTION_DEBUG_TRACE 0x100 /* Animated trace mode, print
+ each address and instruction
+ executed to debug buffer. */
+#define OPTION_DEBUG_SINGLE 0x200 /* stop after executing one
+ instruction */
+#define OPTION_SYNCHRONOUS 0x400 /* Enable sync SCSI. */
+#define OPTION_MEMORY_MAPPED 0x800 /* NCR registers have valid
+ memory mapping */
+#define OPTION_IO_MAPPED 0x1000 /* NCR registers have valid
+ I/O mapping */
+#define OPTION_DEBUG_PROBE_ONLY 0x2000 /* Probe only, don't even init */
+#define OPTION_DEBUG_TESTS_ONLY 0x4000 /* Probe, init, run selected tests */
+#define OPTION_DEBUG_TEST0 0x08000 /* Run test 0 */
+#define OPTION_DEBUG_TEST1 0x10000 /* Run test 1 */
+#define OPTION_DEBUG_TEST2 0x20000 /* Run test 2 */
+#define OPTION_DEBUG_DUMP 0x40000 /* Dump commands */
+#define OPTION_DEBUG_TARGET_LIMIT 0x80000 /* Only talk to target+luns specified */
+#define OPTION_DEBUG_NCOMMANDS_LIMIT 0x100000 /* Limit the number of commands */
+#define OPTION_DEBUG_SCRIPT 0x200000 /* Print when checkpoints are passed */
+#define OPTION_DEBUG_FIXUP 0x400000 /* print fixup values */
+#define OPTION_DEBUG_DSA 0x800000
+#define OPTION_DEBUG_CORRUPTION 0x1000000 /* Detect script corruption */
+#define OPTION_DEBUG_SDTR 0x2000000 /* Debug SDTR problem */
+#define OPTION_DEBUG_MISMATCH 0x4000000 /* Debug phase mismatches */
+#define OPTION_DISCONNECT 0x8000000 /* Allow disconnect */
+#define OPTION_DEBUG_DISCONNECT 0x10000000
+#define OPTION_ALWAYS_SYNCHRONOUS 0x20000000 /* Negotiate sync. transfers
+ on power up */
+#define OPTION_DEBUG_QUEUES 0x80000000
+#define OPTION_DEBUG_ALLOCATION 0x100000000LL
+#define OPTION_DEBUG_SYNCHRONOUS 0x200000000LL /* Sanity check SXFER and
+ SCNTL3 registers */
+#define OPTION_NO_ASYNC 0x400000000LL /* Don't automagically send
+ SDTR for async transfers when
+ we haven't been told to do
+ a synchronous transfer. */
+#define OPTION_NO_PRINT_RACE 0x800000000LL /* Don't print message when
+ the reselect/WAIT DISCONNECT
+ race condition hits */
+#if !defined(PERM_OPTIONS)
+#define PERM_OPTIONS 0
+#endif
+
+/*
+ * Some data which is accessed by the NCR chip must be 4-byte aligned.
+ * For some hosts the default is less than that (eg. 68K uses 2-byte).
+ * Alignment has only been forced where it is important; also if one
+ * 32 bit structure field is aligned then it is assumed that following
+ * 32 bit fields are also aligned. Take care when adding fields
+ * which are other than 32 bit.
+ */
+
+struct NCR53c7x0_synchronous {
+ u32 select_indirect /* Value used for indirect selection */
+ __attribute__ ((aligned (4)));
+ u32 sscf_710; /* Used to set SSCF bits for 710 */
+ u32 script[8]; /* Size ?? Script used when target is
+ reselected */
+ unsigned char synchronous_want[5]; /* Per target desired SDTR */
+/*
+ * Set_synchronous programs these, select_indirect and current settings after
+ * int_debug_should show a match.
+ */
+ unsigned char sxfer_sanity, scntl3_sanity;
+};
+
+#define CMD_FLAG_SDTR 1 /* Initiating synchronous
+ transfer negotiation */
+#define CMD_FLAG_WDTR 2 /* Initiating wide transfer
+ negotiation */
+#define CMD_FLAG_DID_SDTR 4 /* did SDTR */
+#define CMD_FLAG_DID_WDTR 8 /* did WDTR */
+
+struct NCR53c7x0_table_indirect {
+ u32 count;
+ void *address;
+};
+
+enum ncr_event {
+ EVENT_NONE = 0,
+/*
+ * Order is IMPORTANT, since these must correspond to the event interrupts
+ * in 53c7,8xx.scr
+ */
+
+ EVENT_ISSUE_QUEUE = 0x5000000, /* 0 Command was added to issue queue */
+ EVENT_START_QUEUE, /* 1 Command moved to start queue */
+ EVENT_SELECT, /* 2 Command completed selection */
+ EVENT_DISCONNECT, /* 3 Command disconnected */
+ EVENT_RESELECT, /* 4 Command reselected */
+ EVENT_COMPLETE, /* 5 Command completed */
+ EVENT_IDLE, /* 6 */
+ EVENT_SELECT_FAILED, /* 7 */
+ EVENT_BEFORE_SELECT, /* 8 */
+ EVENT_RESELECT_FAILED /* 9 */
+};
+
+struct NCR53c7x0_event {
+ enum ncr_event event; /* What type of event */
+ unsigned char target;
+ unsigned char lun;
+ struct timeval time;
+ u32 *dsa; /* What's in the DSA register now (virt) */
+/*
+ * A few things from that SCSI pid so we know what happened after
+ * the Scsi_Cmnd structure in question may have disappeared.
+ */
+ unsigned long pid; /* The SCSI PID which caused this
+ event */
+ unsigned char cmnd[12];
+};
+
+/*
+ * Things in the NCR53c7x0_cmd structure are split into two parts :
+ *
+ * 1. A fixed portion, for things which are not accessed directly by static NCR
+ * code (ie, are referenced only by the Linux side of the driver,
+ * or only by dynamically generated code).
+ *
+ * 2. The DSA portion, for things which are accessed directly by static NCR
+ * code.
+ *
+ * This is a little ugly, but it
+ * 1. Avoids conflicts between the NCR code's picture of the structure, and
+ * Linux code's idea of what it looks like.
+ *
+ * 2. Minimizes the pain in the Linux side of the code needed
+ * to calculate real dsa locations for things, etc.
+ *
+ */
+
+struct NCR53c7x0_cmd {
+ void *real; /* Real, unaligned address for
+ free function */
+ void (* free)(void *, int); /* Command to deallocate; NULL
+ for structures allocated with
+ scsi_register, etc. */
+ Scsi_Cmnd *cmd; /* Associated Scsi_Cmnd
+ structure, Scsi_Cmnd points
+ at NCR53c7x0_cmd using
+ host_scribble structure */
+
+ int size; /* scsi_malloc'd size of this
+ structure */
+
+ int flags; /* CMD_* flags */
+
+/*
+ * SDTR and WIDE messages are an either/or affair
+ * in this message, since we will go into message out and send
+ * _the whole mess_ without dropping out of message out to
+ * let the target go into message in after sending the first
+ * message.
+ */
+
+ unsigned char select[11]; /* Select message, includes
+ IDENTIFY
+ (optional) QUEUE TAG
+ (optional) SDTR or WDTR
+ */
+
+
+ volatile struct NCR53c7x0_cmd *next; /* Linux maintained lists (free,
+ running, eventually finished */
+
+
+ u32 *data_transfer_start; /* Start of data transfer routines */
+ u32 *data_transfer_end; /* Address after end of data transfer o
+ routines */
+/*
+ * The following three fields were moved from the DSA proper to here
+ * since only dynamically generated NCR code refers to them, meaning
+ * we don't need dsa_* absolutes, and it is simpler to let the
+ * host code refer to them directly.
+ */
+
+/*
+ * HARD CODED : residual and saved_residual need to agree with the sizes
+ * used in NCR53c7,8xx.scr.
+ *
+ * FIXME: we want to consider the case where we have odd-length
+ * scatter/gather buffers and a WIDE transfer, in which case
+ * we'll need to use the CHAIN MOVE instruction. Ick.
+ */
+ u32 residual[6] __attribute__ ((aligned (4)));
+ /* Residual data transfer which
+ allows pointer code to work
+ right.
+
+ [0-1] : Conditional call to
+ appropriate other transfer
+ routine.
+ [2-3] : Residual block transfer
+ instruction.
+ [4-5] : Jump to instruction
+ after splice.
+ */
+ u32 saved_residual[6]; /* Copy of old residual, so we
+ can get another partial
+ transfer and still recover
+ */
+
+ u32 saved_data_pointer; /* Saved data pointer */
+
+ u32 dsa_next_addr; /* _Address_ of dsa_next field
+ in this dsa for RISCy
+ style constant. */
+
+ u32 dsa_addr; /* Address of dsa; RISCy style
+ constant */
+
+ u32 dsa[0]; /* Variable length (depending
+ on host type, number of scatter /
+ gather buffers, etc). */
+};
+
+struct NCR53c7x0_break {
+ u32 *address, old_instruction[2];
+ struct NCR53c7x0_break *next;
+ unsigned char old_size; /* Size of old instruction */
+};
+
+/* Indicates that the NCR is not executing code */
+#define STATE_HALTED 0
+/*
+ * Indicates that the NCR is executing the wait for select / reselect
+ * script. Only used when running NCR53c700 compatible scripts, only
+ * state during which an ABORT is _not_ considered an error condition.
+ */
+#define STATE_WAITING 1
+/* Indicates that the NCR is executing other code. */
+#define STATE_RUNNING 2
+/*
+ * Indicates that the NCR was being aborted.
+ */
+#define STATE_ABORTING 3
+/* Indicates that the NCR was successfully aborted. */
+#define STATE_ABORTED 4
+/* Indicates that the NCR has been disabled due to a fatal error */
+#define STATE_DISABLED 5
+
+/*
+ * Where knowledge of SCSI SCRIPT(tm) specified values are needed
+ * in an interrupt handler, an interrupt handler exists for each
+ * different SCSI script so we don't have name space problems.
+ *
+ * Return values of these handlers are as follows :
+ */
+#define SPECIFIC_INT_NOTHING 0 /* don't even restart */
+#define SPECIFIC_INT_RESTART 1 /* restart at the next instruction */
+#define SPECIFIC_INT_ABORT 2 /* recoverable error, abort cmd */
+#define SPECIFIC_INT_PANIC 3 /* unrecoverable error, panic */
+#define SPECIFIC_INT_DONE 4 /* normal command completion */
+#define SPECIFIC_INT_BREAK 5 /* break point encountered */
+
+struct NCR53c7x0_hostdata {
+ int size; /* Size of entire Scsi_Host
+ structure */
+ int board; /* set to board type, useful if
+ we have host specific things,
+ ie, a general purpose I/O
+ bit is being used to enable
+ termination, etc. */
+
+ int chip; /* set to chip type; 700-66 is
+ 700-66, rest are last three
+ digits of part number */
+
+ char valid_ids[8]; /* Valid SCSI ID's for adapter */
+ /*
+ * PCI bus, device, function, only for NCR53c8x0 chips.
+ * pci_valid indicates that the PCI configuration information
+ * is valid, and we can twiddle MAX_LAT, etc. as recommended
+ * for maximum performance in the NCR documentation.
+ */
+ unsigned char pci_bus, pci_device_fn;
+ unsigned pci_valid:1;
+
+ u32 *dsp; /* dsp to restart with after
+ all stacked interrupts are
+ handled. */
+
+ unsigned dsp_changed:1; /* Has dsp changed within this
+ set of stacked interrupts ? */
+
+ unsigned char dstat; /* Most recent value of dstat */
+ unsigned dstat_valid:1;
+
+ unsigned expecting_iid:1; /* Expect IID interrupt */
+ unsigned expecting_sto:1; /* Expect STO interrupt */
+
+ /*
+ * The code stays cleaner if we use variables with function
+ * pointers and offsets that are unique for the different
+ * scripts rather than having a slew of switch(hostdata->chip)
+ * statements.
+ *
+ * It also means that the #defines from the SCSI SCRIPTS(tm)
+ * don't have to be visible outside of the script-specific
+ * instructions, preventing name space pollution.
+ */
+
+ void (* init_fixup)(struct Scsi_Host *host);
+ void (* init_save_regs)(struct Scsi_Host *host);
+ void (* dsa_fixup)(struct NCR53c7x0_cmd *cmd);
+ void (* soft_reset)(struct Scsi_Host *host);
+ int (* run_tests)(struct Scsi_Host *host);
+
+ /*
+ * Called when DSTAT_SIR is set, indicating an interrupt generated
+ * by the INT instruction, where values are unique for each SCSI
+ * script. Should return one of the SPEC_* values.
+ */
+
+ int (* dstat_sir_intr)(struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd);
+
+ int dsa_len; /* Size of DSA structure */
+
+ /*
+ * Location of DSA fields for the SCSI SCRIPT corresponding to this
+ * chip.
+ */
+
+ s32 dsa_start;
+ s32 dsa_end;
+ s32 dsa_next;
+ s32 dsa_prev;
+ s32 dsa_cmnd;
+ s32 dsa_select;
+ s32 dsa_msgout;
+ s32 dsa_cmdout;
+ s32 dsa_dataout;
+ s32 dsa_datain;
+ s32 dsa_msgin;
+ s32 dsa_msgout_other;
+ s32 dsa_write_sync;
+ s32 dsa_write_resume;
+ s32 dsa_check_reselect;
+ s32 dsa_status;
+ s32 dsa_saved_pointer;
+ s32 dsa_jump_dest;
+
+ /*
+ * Important entry points that generic fixup code needs
+ * to know about, fixed up.
+ */
+
+ s32 E_accept_message;
+ s32 E_command_complete;
+ s32 E_data_transfer;
+ s32 E_dsa_code_template;
+ s32 E_dsa_code_template_end;
+ s32 E_end_data_transfer;
+ s32 E_msg_in;
+ s32 E_initiator_abort;
+ s32 E_other_transfer;
+ s32 E_other_in;
+ s32 E_other_out;
+ s32 E_target_abort;
+ s32 E_debug_break;
+ s32 E_reject_message;
+ s32 E_respond_message;
+ s32 E_select;
+ s32 E_select_msgout;
+ s32 E_test_0;
+ s32 E_test_1;
+ s32 E_test_2;
+ s32 E_test_3;
+ s32 E_dsa_zero;
+ s32 E_cmdout_cmdout;
+ s32 E_wait_reselect;
+ s32 E_dsa_code_begin;
+
+ long long options; /* Bitfielded set of options enabled */
+ volatile u32 test_completed; /* Test completed */
+ int test_running; /* Test currently running */
+ s32 test_source
+ __attribute__ ((aligned (4)));
+ volatile s32 test_dest;
+
+ volatile int state; /* state of driver, only used for
+ OPTION_700 */
+
+ unsigned char dmode; /*
+ * set to the address of the DMODE
+ * register for this chip.
+ */
+ unsigned char istat; /*
+ * set to the address of the ISTAT
+ * register for this chip.
+ */
+
+ int scsi_clock; /*
+ * SCSI clock in HZ. 0 may be used
+ * for unknown, although this will
+ * disable synchronous negotiation.
+ */
+
+ volatile int intrs; /* Number of interrupts */
+ volatile int resets; /* Number of SCSI resets */
+ unsigned char saved_dmode;
+ unsigned char saved_ctest4;
+ unsigned char saved_ctest7;
+ unsigned char saved_dcntl;
+ unsigned char saved_scntl3;
+
+ unsigned char this_id_mask;
+
+ /* Debugger information */
+ struct NCR53c7x0_break *breakpoints, /* Linked list of all break points */
+ *breakpoint_current; /* Current breakpoint being stepped
+ through, NULL if we are running
+ normally. */
+#ifdef NCR_DEBUG
+ int debug_size; /* Size of debug buffer */
+ volatile int debug_count; /* Current data count */
+ volatile char *debug_buf; /* Output ring buffer */
+ volatile char *debug_write; /* Current write pointer */
+ volatile char *debug_read; /* Current read pointer */
+#endif /* def NCR_DEBUG */
+
+ /* XXX - primitive debugging junk, remove when working ? */
+ int debug_print_limit; /* Number of commands to print
+ out exhaustive debugging
+ information for if
+ OPTION_DEBUG_DUMP is set */
+
+ unsigned char debug_lun_limit[16]; /* If OPTION_DEBUG_TARGET_LIMIT
+ set, puke if commands are sent
+ to other target/lun combinations */
+
+ int debug_count_limit; /* Number of commands to execute
+ before puking to limit debugging
+ output */
+
+
+ volatile unsigned idle:1; /* set to 1 if idle */
+
+ /*
+ * Table of synchronous+wide transfer parameters set on a per-target
+ * basis.
+ */
+
+ volatile struct NCR53c7x0_synchronous sync[16]
+ __attribute__ ((aligned (4)));
+
+ volatile Scsi_Cmnd *issue_queue
+ __attribute__ ((aligned (4)));
+ /* waiting to be issued by
+ Linux driver */
+ volatile struct NCR53c7x0_cmd *running_list;
+ /* commands running, maintained
+ by Linux driver */
+
+ volatile struct NCR53c7x0_cmd *ncrcurrent; /* currently connected
+ nexus, ONLY valid for
+ NCR53c700/NCR53c700-66
+ */
+
+ volatile struct NCR53c7x0_cmd *spare; /* pointer to spare,
+ allocated at probe time,
+ which we can use for
+ initialization */
+ volatile struct NCR53c7x0_cmd *free;
+ int max_cmd_size; /* Maximum size of NCR53c7x0_cmd
+ based on number of
+ scatter/gather segments, etc.
+ */
+ volatile int num_cmds; /* Number of commands
+ allocated */
+ volatile int extra_allocate;
+ volatile unsigned char cmd_allocated[16]; /* Have we allocated commands
+ for this target yet? If not,
+ do so ASAP */
+ volatile unsigned char busy[16][8]; /* number of commands
+ executing on each target
+ */
+ /*
+ * Eventually, I'll switch to a coroutine for calling
+ * cmd->done(cmd), etc. so that we can overlap interrupt
+ * processing with this code for maximum performance.
+ */
+
+ volatile struct NCR53c7x0_cmd *finished_queue;
+
+ /* Shared variables between SCRIPT and host driver */
+ volatile u32 *schedule
+ __attribute__ ((aligned (4))); /* Array of JUMPs to dsa_begin
+ routines of various DSAs.
+ When not in use, replace
+ with jump to next slot */
+
+
+ volatile unsigned char msg_buf[16]; /* buffer for messages
+ other than the command
+ complete message */
+
+ /* Per-target default synchronous and WIDE messages */
+ volatile unsigned char synchronous_want[16][5];
+ volatile unsigned char wide_want[16][4];
+
+ /* Bit fielded set of targets we want to speak synchronously with */
+ volatile u16 initiate_sdtr;
+ /* Bit fielded set of targets we want to speak wide with */
+ volatile u16 initiate_wdtr;
+ /* Bit fielded list of targets we've talked to. */
+ volatile u16 talked_to;
+
+ /* Array of bit-fielded lun lists that we need to request_sense */
+ volatile unsigned char request_sense[16];
+
+ u32 addr_reconnect_dsa_head
+ __attribute__ ((aligned (4))); /* RISCy style constant,
+ address of following */
+ volatile u32 reconnect_dsa_head;
+ /* Data identifying nexus we are trying to match during reselection */
+ volatile unsigned char reselected_identify; /* IDENTIFY message */
+ volatile unsigned char reselected_tag; /* second byte of queue tag
+ message or 0 */
+
+ /* These were static variables before we moved them */
+
+ s32 NCR53c7xx_zero
+ __attribute__ ((aligned (4)));
+ s32 NCR53c7xx_sink;
+ u32 NOP_insn;
+ char NCR53c7xx_msg_reject;
+ char NCR53c7xx_msg_abort;
+ char NCR53c7xx_msg_nop;
+
+ /*
+ * Following item introduced by RGH to support NCRc710, which is
+ * VERY brain-dead when it come to memory moves
+ */
+
+ /* DSA save area used only by the NCR chip */
+ volatile unsigned long saved2_dsa
+ __attribute__ ((aligned (4)));
+
+ volatile unsigned long emulated_intfly
+ __attribute__ ((aligned (4)));
+
+ volatile int event_size, event_index;
+ volatile struct NCR53c7x0_event *events;
+
+ /* If we need to generate code to kill off the currently connected
+ command, this is where we do it. Should have a BMI instruction
+ to source or sink the current data, followed by a JUMP
+ to abort_connected */
+
+ u32 *abort_script;
+
+ int script_count; /* Size of script in words */
+ u32 script[0]; /* Relocated SCSI script */
+
+};
+
+#define IRQ_NONE 255
+#define DMA_NONE 255
+#define IRQ_AUTO 254
+#define DMA_AUTO 254
+
+#define BOARD_GENERIC 0
+
+#define NCR53c7x0_insn_size(insn) \
+ (((insn) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI ? 3 : 2)
+
+
+#define NCR53c7x0_local_declare() \
+ volatile unsigned char *NCR53c7x0_address_memory; \
+ unsigned int NCR53c7x0_address_io; \
+ int NCR53c7x0_memory_mapped
+
+#define NCR53c7x0_local_setup(host) \
+ NCR53c7x0_address_memory = (void *) (host)->base; \
+ NCR53c7x0_address_io = (unsigned int) (host)->io_port; \
+ NCR53c7x0_memory_mapped = ((struct NCR53c7x0_hostdata *) \
+ host->hostdata)-> options & OPTION_MEMORY_MAPPED
+
+#ifdef BIG_ENDIAN
+/* These could be more efficient, given that we are always memory mapped,
+ * but they don't give the same problems as the write macros, so leave
+ * them. */
+#define NCR53c7x0_read8(address) \
+ (NCR53c7x0_memory_mapped ? \
+ (unsigned int)readb((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) : \
+ inb(NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_read16(address) \
+ (NCR53c7x0_memory_mapped ? \
+ (unsigned int)readw((u32)NCR53c7x0_address_memory + ((u32)(address)^2)) : \
+ inw(NCR53c7x0_address_io + (address)))
+#else
+#define NCR53c7x0_read8(address) \
+ (NCR53c7x0_memory_mapped ? \
+ (unsigned int)readb((u32)NCR53c7x0_address_memory + (u32)(address)) : \
+ inb(NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_read16(address) \
+ (NCR53c7x0_memory_mapped ? \
+ (unsigned int)readw((u32)NCR53c7x0_address_memory + (u32)(address)) : \
+ inw(NCR53c7x0_address_io + (address)))
+#endif
+#define NCR53c7x0_read32(address) \
+ (NCR53c7x0_memory_mapped ? \
+ (unsigned int) readl((u32)NCR53c7x0_address_memory + (u32)(address)) : \
+ inl(NCR53c7x0_address_io + (address)))
+
+#ifdef BIG_ENDIAN
+/* If we are big-endian, then we are not Intel, so probably don't have
+ * an i/o map as well as a memory map. So, lets assume memory mapped.
+ * Also, I am having terrible problems trying to persuade the compiler
+ * not to lay down code which does a read after write for these macros.
+ * If you remove 'volatile' from writeb() and friends it is ok....
+ */
+
+#define NCR53c7x0_write8(address,value) \
+ *(volatile unsigned char *) \
+ ((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) = (value)
+
+#define NCR53c7x0_write16(address,value) \
+ *(volatile unsigned short *) \
+ ((u32)NCR53c7x0_address_memory + ((u32)(address)^2)) = (value)
+
+#define NCR53c7x0_write32(address,value) \
+ *(volatile unsigned long *) \
+ ((u32)NCR53c7x0_address_memory + ((u32)(address))) = (value)
+
+#else
+
+#define NCR53c7x0_write8(address,value) \
+ (NCR53c7x0_memory_mapped ? \
+ ({writeb((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) : \
+ outb((value), NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_write16(address,value) \
+ (NCR53c7x0_memory_mapped ? \
+ ({writew((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) : \
+ outw((value), NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_write32(address,value) \
+ (NCR53c7x0_memory_mapped ? \
+ ({writel((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) : \
+ outl((value), NCR53c7x0_address_io + (address)))
+
+#endif
+
+/* Patch arbitrary 32 bit words in the script */
+#define patch_abs_32(script, offset, symbol, value) \
+ for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof \
+ (u32)); ++i) { \
+ (script)[A_##symbol##_used[i] - (offset)] += (value); \
+ if (hostdata->options & OPTION_DEBUG_FIXUP) \
+ printk("scsi%d : %s reference %d at 0x%x in %s is now 0x%x\n",\
+ host->host_no, #symbol, i, A_##symbol##_used[i] - \
+ (int)(offset), #script, (script)[A_##symbol##_used[i] - \
+ (offset)]); \
+ }
+
+/* Patch read/write instruction immediate field */
+#define patch_abs_rwri_data(script, offset, symbol, value) \
+ for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof \
+ (u32)); ++i) \
+ (script)[A_##symbol##_used[i] - (offset)] = \
+ ((script)[A_##symbol##_used[i] - (offset)] & \
+ ~DBC_RWRI_IMMEDIATE_MASK) | \
+ (((value) << DBC_RWRI_IMMEDIATE_SHIFT) & \
+ DBC_RWRI_IMMEDIATE_MASK)
+
+/* Patch transfer control instruction data field */
+#define patch_abs_tci_data(script, offset, symbol, value) \
+ for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof \
+ (u32)); ++i) \
+ (script)[A_##symbol##_used[i] - (offset)] = \
+ ((script)[A_##symbol##_used[i] - (offset)] & \
+ ~DBC_TCI_DATA_MASK) | \
+ (((value) << DBC_TCI_DATA_SHIFT) & \
+ DBC_TCI_DATA_MASK)
+
+/* Patch field in dsa structure (assignment should be +=?) */
+#define patch_dsa_32(dsa, symbol, word, value) \
+ { \
+ (dsa)[(hostdata->##symbol - hostdata->dsa_start) / sizeof(u32) \
+ + (word)] = (value); \
+ if (hostdata->options & OPTION_DEBUG_DSA) \
+ printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n", \
+ #dsa, #symbol, hostdata->##symbol, \
+ (word), (u32) (value)); \
+ }
+
+/* Paranoid people could use panic() here. */
+#define FATAL(host) shutdown((host));
+
+#endif /* NCR53c710_C */
+#endif /* NCR53c710_H */
diff --git a/drivers/scsi/53c7xx.scr b/drivers/scsi/53c7xx.scr
new file mode 100644
index 000000000..2fc9db2dd
--- /dev/null
+++ b/drivers/scsi/53c7xx.scr
@@ -0,0 +1,1591 @@
+#undef DEBUG
+#undef EVENTS
+#undef NO_SELECTION_TIMEOUT
+#define BIG_ENDIAN
+
+; 53c710 driver. Modified from Drew Eckhardts driver
+; for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
+;
+; I have left the script for the 53c8xx family in here, as it is likely
+; to be useful to see what I changed when bug hunting.
+
+; NCR 53c810 driver, main script
+; Sponsored by
+; iX Multiuser Multitasking Magazine
+; hm@ix.de
+;
+; Copyright 1993, 1994, 1995 Drew Eckhardt
+; Visionary Computing
+; (Unix and Linux consulting and custom programming)
+; drew@PoohSticks.ORG
+; +1 (303) 786-7975
+;
+; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
+;
+; PRE-ALPHA
+;
+; For more information, please consult
+;
+; NCR 53C810
+; PCI-SCSI I/O Processor
+; Data Manual
+;
+; NCR 53C710
+; SCSI I/O Processor
+; Programmers Guide
+;
+; NCR Microelectronics
+; 1635 Aeroplaza Drive
+; Colorado Springs, CO 80916
+; 1+ (719) 578-3400
+;
+; Toll free literature number
+; +1 (800) 334-5454
+;
+; IMPORTANT : This code is self modifying due to the limitations of
+; the NCR53c7,8xx series chips. Persons debugging this code with
+; the remote debugger should take this into account, and NOT set
+; breakpoints in modified instructions.
+;
+; Design:
+; The NCR53c7,8xx family of SCSI chips are busmasters with an onboard
+; microcontroller using a simple instruction set.
+;
+; So, to minimize the effects of interrupt latency, and to maximize
+; throughput, this driver offloads the practical maximum amount
+; of processing to the SCSI chip while still maintaining a common
+; structure.
+;
+; Where tradeoffs were needed between efficiency on the older
+; chips and the newer NCR53c800 series, the NCR53c800 series
+; was chosen.
+;
+; While the NCR53c700 and NCR53c700-66 lacked the facilities to fully
+; automate SCSI transfers without host processor intervention, this
+; isn't the case with the NCR53c710 and newer chips which allow
+;
+; - reads and writes to the internal registers from within the SCSI
+; scripts, allowing the SCSI SCRIPTS(tm) code to save processor
+; state so that multiple threads of execution are possible, and also
+; provide an ALU for loop control, etc.
+;
+; - table indirect addressing for some instructions. This allows
+; pointers to be located relative to the DSA ((Data Structure
+; Address) register.
+;
+; These features make it possible to implement a mailbox style interface,
+; where the same piece of code is run to handle I/O for multiple threads
+; at once minimizing our need to relocate code. Since the NCR53c700/
+; NCR53c800 series have a unique combination of features, making a
+; a standard ingoing/outgoing mailbox system, costly, I've modified it.
+;
+; - Mailboxes are a mixture of code and data. This lets us greatly
+; simplify the NCR53c810 code and do things that would otherwise
+; not be possible.
+;
+; The saved data pointer is now implemented as follows :
+;
+; Control flow has been architected such that if control reaches
+; munge_save_data_pointer, on a restore pointers message or
+; reconnection, a jump to the address formerly in the TEMP register
+; will allow the SCSI command to resume execution.
+;
+
+;
+; Note : the DSA structures must be aligned on 32 bit boundaries,
+; since the source and destination of MOVE MEMORY instructions
+; must share the same alignment and this is the alignment of the
+; NCR registers.
+;
+
+; For some systems (MVME166, for example) dmode is always the same, so don't
+; waste time writing it
+
+#if 1
+#define DMODE_MEMORY_TO_NCR
+#define DMODE_MEMORY_TO_MEMORY
+#define DMODE_NCR_TO_MEMORY
+#else
+#define DMODE_MEMORY_TO_NCR MOVE dmode_memory_to_ncr TO DMODE
+#define DMODE_MEMORY_TO_MEMORY MOVE dmode_memory_to_memory TO DMODE
+#define DMODE_NCR_TO_MEMORY MOVE dmode_ncr_to_memory TO DMODE
+#endif
+
+ABSOLUTE dsa_temp_lun = 0 ; Patch to lun for current dsa
+ABSOLUTE dsa_temp_next = 0 ; Patch to dsa next for current dsa
+ABSOLUTE dsa_temp_addr_next = 0 ; Patch to address of dsa next address
+ ; for current dsa
+ABSOLUTE dsa_temp_sync = 0 ; Patch to address of per-target
+ ; sync routine
+ABSOLUTE dsa_sscf_710 = 0 ; Patch to address of per-target
+ ; sscf value (53c710)
+ABSOLUTE dsa_temp_target = 0 ; Patch to id for current dsa
+ABSOLUTE dsa_temp_addr_saved_pointer = 0; Patch to address of per-command
+ ; saved data pointer
+ABSOLUTE dsa_temp_addr_residual = 0 ; Patch to address of per-command
+ ; current residual code
+ABSOLUTE dsa_temp_addr_saved_residual = 0; Patch to address of per-command
+ ; saved residual code
+ABSOLUTE dsa_temp_addr_new_value = 0 ; Address of value for JUMP operand
+ABSOLUTE dsa_temp_addr_array_value = 0 ; Address to copy to
+ABSOLUTE dsa_temp_addr_dsa_value = 0 ; Address of this DSA value
+
+;
+; Once a device has initiated reselection, we need to compare it
+; against the singly linked list of commands which have disconnected
+; and are pending reselection. These commands are maintained in
+; an unordered singly linked list of DSA structures, through the
+; DSA pointers at their 'centers' headed by the reconnect_dsa_head
+; pointer.
+;
+; To avoid complications in removing commands from the list,
+; I minimize the amount of expensive (at eight operations per
+; addition @ 500-600ns each) pointer operations which must
+; be done in the NCR driver by precomputing them on the
+; host processor during dsa structure generation.
+;
+; The fixed-up per DSA code knows how to recognize the nexus
+; associated with the corresponding SCSI command, and modifies
+; the source and destination pointers for the MOVE MEMORY
+; instruction which is executed when reselected_ok is called
+; to remove the command from the list. Similarly, DSA is
+; loaded with the address of the next DSA structure and
+; reselected_check_next is called if a failure occurs.
+;
+; Perhaps more concisely, the net effect of the mess is
+;
+; for (dsa = reconnect_dsa_head, dest = &reconnect_dsa_head,
+; src = NULL; dsa; dest = &dsa->next, dsa = dsa->next) {
+; src = &dsa->next;
+; if (target_id == dsa->id && target_lun == dsa->lun) {
+; *dest = *src;
+; break;
+; }
+; }
+;
+; if (!dsa)
+; error (int_err_unexpected_reselect);
+; else
+; longjmp (dsa->jump_resume, 0);
+;
+;
+
+#if (CHIP != 700) && (CHIP != 70066)
+; Define DSA structure used for mailboxes
+ENTRY dsa_code_template
+dsa_code_template:
+ENTRY dsa_code_begin
+dsa_code_begin:
+; RGH: Don't care about TEMP and DSA here
+ DMODE_MEMORY_TO_NCR
+ MOVE MEMORY 4, dsa_temp_addr_dsa_value, addr_scratch
+ DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+ MOVE MEMORY 4, addr_scratch, saved_dsa
+ ; We are about to go and select the device, so must set SSCF bits
+ MOVE MEMORY 4, dsa_sscf_710, addr_scratch
+#ifdef BIG_ENDIAN
+ MOVE SCRATCH3 TO SFBR
+#else
+ MOVE SCRATCH0 TO SFBR
+#endif
+ MOVE SFBR TO SBCL
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#else
+ CALL scratch_to_dsa
+#endif
+ CALL select
+; Handle the phase mismatch which may have resulted from the
+; MOVE FROM dsa_msgout if we returned here. The CLEAR ATN
+; may or may not be necessary, and we should update script_asm.pl
+; to handle multiple pieces.
+ CLEAR ATN
+ CLEAR ACK
+
+; Replace second operand with address of JUMP instruction dest operand
+; in schedule table for this DSA. Becomes dsa_jump_dest in 53c7,8xx.c.
+ENTRY dsa_code_fix_jump
+dsa_code_fix_jump:
+ MOVE MEMORY 4, NOP_insn, 0
+ JUMP select_done
+
+; wrong_dsa loads the DSA register with the value of the dsa_next
+; field.
+;
+wrong_dsa:
+#if (CHIP == 710)
+; NOTE DSA is corrupt when we arrive here!
+#endif
+; Patch the MOVE MEMORY INSTRUCTION such that
+; the destination address is the address of the OLD
+; next pointer.
+;
+ MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 8
+ DMODE_MEMORY_TO_NCR
+;
+; Move the _contents_ of the next pointer into the DSA register as
+; the next I_T_L or I_T_L_Q tupple to check against the established
+; nexus.
+;
+ MOVE MEMORY 4, dsa_temp_next, addr_scratch
+ DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+ MOVE MEMORY 4, addr_scratch, saved_dsa
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#else
+ CALL scratch_to_dsa
+#endif
+ JUMP reselected_check_next
+
+ABSOLUTE dsa_save_data_pointer = 0
+ENTRY dsa_code_save_data_pointer
+dsa_code_save_data_pointer:
+#if (CHIP == 710)
+ ; When we get here, TEMP has been saved in jump_temp+4, DSA is corrupt
+ ; We MUST return with DSA correct
+ MOVE MEMORY 4, jump_temp+4, dsa_temp_addr_saved_pointer
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+ MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
+ CLEAR ACK
+#ifdef DEBUG
+ INT int_debug_saved
+#endif
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+ JUMP jump_temp
+#else
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_temp, dsa_temp_addr_saved_pointer
+ DMODE_MEMORY_TO_MEMORY
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+ MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
+ CLEAR ACK
+#ifdef DEBUG
+ INT int_debug_saved
+#endif
+ RETURN
+#endif
+ABSOLUTE dsa_restore_pointers = 0
+ENTRY dsa_code_restore_pointers
+dsa_code_restore_pointers:
+#if (CHIP == 710)
+ ; TEMP and DSA are corrupt when we get here, but who cares!
+ MOVE MEMORY 4, dsa_temp_addr_saved_pointer, jump_temp + 4
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+ MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
+ CLEAR ACK
+ ; Restore DSA, note we don't care about TEMP
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#ifdef DEBUG
+ INT int_debug_restored
+#endif
+ JUMP jump_temp
+#else
+ DMODE_MEMORY_TO_NCR
+ MOVE MEMORY 4, dsa_temp_addr_saved_pointer, addr_temp
+ DMODE_MEMORY_TO_MEMORY
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+ MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
+ CLEAR ACK
+#ifdef DEBUG
+ INT int_debug_restored
+#endif
+ RETURN
+#endif
+
+ABSOLUTE dsa_check_reselect = 0
+; dsa_check_reselect determines whether or not the current target and
+; lun match the current DSA
+ENTRY dsa_code_check_reselect
+dsa_code_check_reselect:
+#if (CHIP == 710)
+ /* Arrives here with DSA correct */
+ /* Assumes we are always ID 7 */
+ MOVE LCRC TO SFBR ; LCRC has our ID and his ID bits set
+ JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0x80
+#else
+ MOVE SSID TO SFBR ; SSID contains 3 bit target ID
+; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
+ JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0xf8
+#endif
+;
+; Hack - move to scratch first, since SFBR is not writeable
+; via the CPU and hence a MOVE MEMORY instruction.
+;
+ DMODE_MEMORY_TO_NCR
+ MOVE MEMORY 1, reselected_identify, addr_scratch
+ DMODE_MEMORY_TO_MEMORY
+#ifdef BIG_ENDIAN
+ ; BIG ENDIAN ON MVME166
+ MOVE SCRATCH3 TO SFBR
+#else
+ MOVE SCRATCH0 TO SFBR
+#endif
+; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
+; Are you sure about that? richard@sleepie.demon.co.uk
+ JUMP REL (wrong_dsa), IF NOT dsa_temp_lun, AND MASK 0xf8
+; Patch the MOVE MEMORY INSTRUCTION such that
+; the source address is the address of this dsa's
+; next pointer.
+ MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 4
+ CALL reselected_ok
+#if (CHIP == 710)
+; Restore DSA following memory moves in reselected_ok
+; dsa_temp_sync doesn't really care about DSA, but it has an
+; optional debug INT so a valid DSA is a good idea.
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+ CALL dsa_temp_sync
+; Release ACK on the IDENTIFY message _after_ we've set the synchronous
+; transfer parameters!
+ CLEAR ACK
+; Implicitly restore pointers on reselection, so a RETURN
+; will transfer control back to the right spot.
+ CALL REL (dsa_code_restore_pointers)
+ RETURN
+ENTRY dsa_zero
+dsa_zero:
+ENTRY dsa_code_template_end
+dsa_code_template_end:
+
+; Perform sanity check for dsa_fields_start == dsa_code_template_end -
+; dsa_zero, puke.
+
+ABSOLUTE dsa_fields_start = 0 ; Sanity marker
+ ; pad 48 bytes (fix this RSN)
+ABSOLUTE dsa_next = 48 ; len 4 Next DSA
+ ; del 4 Previous DSA address
+ABSOLUTE dsa_cmnd = 56 ; len 4 Scsi_Cmnd * for this thread.
+ABSOLUTE dsa_select = 60 ; len 4 Device ID, Period, Offset for
+ ; table indirect select
+ABSOLUTE dsa_msgout = 64 ; len 8 table indirect move parameter for
+ ; select message
+ABSOLUTE dsa_cmdout = 72 ; len 8 table indirect move parameter for
+ ; command
+ABSOLUTE dsa_dataout = 80 ; len 4 code pointer for dataout
+ABSOLUTE dsa_datain = 84 ; len 4 code pointer for datain
+ABSOLUTE dsa_msgin = 88 ; len 8 table indirect move for msgin
+ABSOLUTE dsa_status = 96 ; len 8 table indirect move for status byte
+ABSOLUTE dsa_msgout_other = 104 ; len 8 table indirect for normal message out
+ ; (Synchronous transfer negotiation, etc).
+ABSOLUTE dsa_end = 112
+
+ABSOLUTE schedule = 0 ; Array of JUMP dsa_begin or JUMP (next),
+ ; terminated by a call to JUMP wait_reselect
+
+; Linked lists of DSA structures
+ABSOLUTE reconnect_dsa_head = 0 ; Link list of DSAs which can reconnect
+ABSOLUTE addr_reconnect_dsa_head = 0 ; Address of variable containing
+ ; address of reconnect_dsa_head
+
+; These select the source and destination of a MOVE MEMORY instruction
+ABSOLUTE dmode_memory_to_memory = 0x0
+ABSOLUTE dmode_memory_to_ncr = 0x0
+ABSOLUTE dmode_ncr_to_memory = 0x0
+
+ABSOLUTE addr_scratch = 0x0
+ABSOLUTE addr_temp = 0x0
+#if (CHIP == 710)
+ABSOLUTE saved_dsa = 0x0
+ABSOLUTE emulfly = 0x0
+ABSOLUTE addr_dsa = 0x0
+#endif
+#endif /* CHIP != 700 && CHIP != 70066 */
+
+; Interrupts -
+; MSB indicates type
+; 0 handle error condition
+; 1 handle message
+; 2 handle normal condition
+; 3 debugging interrupt
+; 4 testing interrupt
+; Next byte indicates specific error
+
+; XXX not yet implemented, I'm not sure if I want to -
+; Next byte indicates the routine the error occurred in
+; The LSB indicates the specific place the error occurred
+
+ABSOLUTE int_err_unexpected_phase = 0x00000000 ; Unexpected phase encountered
+ABSOLUTE int_err_selected = 0x00010000 ; SELECTED (nee RESELECTED)
+ABSOLUTE int_err_unexpected_reselect = 0x00020000
+ABSOLUTE int_err_check_condition = 0x00030000
+ABSOLUTE int_err_no_phase = 0x00040000
+ABSOLUTE int_msg_wdtr = 0x01000000 ; WDTR message received
+ABSOLUTE int_msg_sdtr = 0x01010000 ; SDTR received
+ABSOLUTE int_msg_1 = 0x01020000 ; single byte special message
+ ; received
+
+ABSOLUTE int_norm_select_complete = 0x02000000 ; Select complete, reprogram
+ ; registers.
+ABSOLUTE int_norm_reselect_complete = 0x02010000 ; Nexus established
+ABSOLUTE int_norm_command_complete = 0x02020000 ; Command complete
+ABSOLUTE int_norm_disconnected = 0x02030000 ; Disconnected
+ABSOLUTE int_norm_aborted =0x02040000 ; Aborted *dsa
+ABSOLUTE int_norm_reset = 0x02050000 ; Generated BUS reset.
+ABSOLUTE int_norm_emulateintfly = 0x02060000 ; 53C710 Emulated intfly
+ABSOLUTE int_debug_break = 0x03000000 ; Break point
+#ifdef DEBUG
+ABSOLUTE int_debug_scheduled = 0x03010000 ; new I/O scheduled
+ABSOLUTE int_debug_idle = 0x03020000 ; scheduler is idle
+ABSOLUTE int_debug_dsa_loaded = 0x03030000 ; dsa reloaded
+ABSOLUTE int_debug_reselected = 0x03040000 ; NCR reselected
+ABSOLUTE int_debug_head = 0x03050000 ; issue head overwritten
+ABSOLUTE int_debug_disconnected = 0x03060000 ; disconnected
+ABSOLUTE int_debug_disconnect_msg = 0x03070000 ; got message to disconnect
+ABSOLUTE int_debug_dsa_schedule = 0x03080000 ; in dsa_schedule
+ABSOLUTE int_debug_reselect_check = 0x03090000 ; Check for reselection of DSA
+ABSOLUTE int_debug_reselected_ok = 0x030a0000 ; Reselection accepted
+#endif
+ABSOLUTE int_debug_panic = 0x030b0000 ; Panic driver
+#ifdef DEBUG
+ABSOLUTE int_debug_saved = 0x030c0000 ; save/restore pointers
+ABSOLUTE int_debug_restored = 0x030d0000
+ABSOLUTE int_debug_sync = 0x030e0000 ; Sanity check synchronous
+ ; parameters.
+ABSOLUTE int_debug_datain = 0x030f0000 ; going into data in phase
+ ; now.
+ABSOLUTE int_debug_check_dsa = 0x03100000 ; Sanity check DSA against
+ ; SDID.
+#endif
+
+ABSOLUTE int_test_1 = 0x04000000 ; Test 1 complete
+ABSOLUTE int_test_2 = 0x04010000 ; Test 2 complete
+ABSOLUTE int_test_3 = 0x04020000 ; Test 3 complete
+
+
+; These should start with 0x05000000, with low bits incrementing for
+; each one.
+
+#ifdef EVENTS
+ABSOLUTE int_EVENT_SELECT = 0
+ABSOLUTE int_EVENT_DISCONNECT = 0
+ABSOLUTE int_EVENT_RESELECT = 0
+ABSOLUTE int_EVENT_COMPLETE = 0
+ABSOLUTE int_EVENT_IDLE = 0
+ABSOLUTE int_EVENT_SELECT_FAILED = 0
+ABSOLUTE int_EVENT_BEFORE_SELECT = 0
+ABSOLUTE int_EVENT_RESELECT_FAILED = 0
+#endif
+
+ABSOLUTE NCR53c7xx_msg_abort = 0 ; Pointer to abort message
+ABSOLUTE NCR53c7xx_msg_reject = 0 ; Pointer to reject message
+ABSOLUTE NCR53c7xx_zero = 0 ; long with zero in it, use for source
+ABSOLUTE NCR53c7xx_sink = 0 ; long to dump worthless data in
+ABSOLUTE NOP_insn = 0 ; NOP instruction
+
+; Pointer to message, potentially multi-byte
+ABSOLUTE msg_buf = 0
+
+; Pointer to holding area for reselection information
+ABSOLUTE reselected_identify = 0
+ABSOLUTE reselected_tag = 0
+
+; Request sense command pointer, it's a 6 byte command, should
+; be constant for all commands since we always want 16 bytes of
+; sense and we don't need to change any fields as we did under
+; SCSI-I when we actually cared about the LUN field.
+;EXTERNAL NCR53c7xx_sense ; Request sense command
+
+#if (CHIP != 700) && (CHIP != 70066)
+; dsa_schedule
+; PURPOSE : after a DISCONNECT message has been received, and pointers
+; saved, insert the current DSA structure at the head of the
+; disconnected queue and fall through to the scheduler.
+;
+; CALLS : OK
+;
+; INPUTS : dsa - current DSA structure, reconnect_dsa_head - list
+; of disconnected commands
+;
+; MODIFIES : SCRATCH, reconnect_dsa_head
+;
+; EXITS : always passes control to schedule
+
+ENTRY dsa_schedule
+dsa_schedule:
+#ifdef DEBUG
+ INT int_debug_dsa_schedule
+#endif
+
+;
+; Calculate the address of the next pointer within the DSA
+; structure of the command that is currently disconnecting
+;
+#if (CHIP == 710)
+ ; Read what should be the current DSA from memory - actual DSA
+ ; register is probably corrupt
+ MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+ CALL dsa_to_scratch
+#endif
+ MOVE SCRATCH0 + dsa_next TO SCRATCH0
+ MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
+ MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
+ MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
+
+; Point the next field of this DSA structure at the current disconnected
+; list
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_scratch, dsa_schedule_insert + 8
+ DMODE_MEMORY_TO_MEMORY
+dsa_schedule_insert:
+ MOVE MEMORY 4, reconnect_dsa_head, 0
+
+; And update the head pointer.
+#if (CHIP == 710)
+ ; Read what should be the current DSA from memory - actual DSA
+ ; register is probably corrupt
+ MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+ CALL dsa_to_scratch
+#endif
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_scratch, reconnect_dsa_head
+ DMODE_MEMORY_TO_MEMORY
+/* Temporarily, see what happens. */
+#ifndef ORIGINAL
+#if (CHIP != 710)
+ MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+ CLEAR ACK
+#endif
+#if (CHIP == 710)
+ ; Time to correct DSA following memory move
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+ WAIT DISCONNECT
+#ifdef EVENTS
+ INT int_EVENT_DISCONNECT;
+#endif
+#ifdef DEBUG
+ INT int_debug_disconnected
+#endif
+ JUMP schedule
+#endif
+
+;
+; select
+;
+; PURPOSE : establish a nexus for the SCSI command referenced by DSA.
+; On success, the current DSA structure is removed from the issue
+; queue. Usually, this is entered as a fall-through from schedule,
+; although the contingent allegiance handling code will write
+; the select entry address to the DSP to restart a command as a
+; REQUEST SENSE. A message is sent (usually IDENTIFY, although
+; additional SDTR or WDTR messages may be sent). COMMAND OUT
+; is handled.
+;
+; INPUTS : DSA - SCSI command, issue_dsa_head
+;
+; CALLS : NOT OK
+;
+; MODIFIES : SCRATCH, issue_dsa_head
+;
+; EXITS : on reselection or selection, go to select_failed
+; otherwise, RETURN so control is passed back to
+; dsa_begin.
+;
+
+ENTRY select
+select:
+
+#ifdef EVENTS
+ INT int_EVENT_BEFORE_SELECT
+#endif
+
+#ifdef DEBUG
+ INT int_debug_scheduled
+#endif
+ CLEAR TARGET
+
+; XXX
+;
+; In effect, SELECTION operations are backgrounded, with execution
+; continuing until code which waits for REQ or a fatal interrupt is
+; encountered.
+;
+; So, for more performance, we could overlap the code which removes
+; the command from the NCRs issue queue with the selection, but
+; at this point I don't want to deal with the error recovery.
+;
+
+#if (CHIP != 700) && (CHIP != 70066)
+#if (CHIP == 710)
+ ; Enable selection timer
+#ifdef NO_SELECTION_TIMEOUT
+ MOVE CTEST7 & 0xff TO CTEST7
+#else
+ MOVE CTEST7 & 0xef TO CTEST7
+#endif
+#endif
+ SELECT ATN FROM dsa_select, select_failed
+ JUMP select_msgout, WHEN MSG_OUT
+ENTRY select_msgout
+select_msgout:
+#if (CHIP == 710)
+ ; Disable selection timer
+ MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+ MOVE FROM dsa_msgout, WHEN MSG_OUT
+#else
+ENTRY select_msgout
+ SELECT ATN 0, select_failed
+select_msgout:
+ MOVE 0, 0, WHEN MSGOUT
+#endif
+
+#ifdef EVENTS
+ INT int_EVENT_SELECT
+#endif
+ RETURN
+
+;
+; select_done
+;
+; PURPOSE: continue on to normal data transfer; called as the exit
+; point from dsa_begin.
+;
+; INPUTS: dsa
+;
+; CALLS: OK
+;
+;
+
+select_done:
+#if (CHIP == 710)
+; NOTE DSA is corrupt when we arrive here!
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+
+#ifdef DEBUG
+ENTRY select_check_dsa
+select_check_dsa:
+ INT int_debug_check_dsa
+#endif
+
+; After a successful selection, we should get either a CMD phase or
+; some transfer request negotiation message.
+
+ JUMP cmdout, WHEN CMD
+ INT int_err_unexpected_phase, WHEN NOT MSG_IN
+
+select_msg_in:
+ CALL msg_in, WHEN MSG_IN
+ JUMP select_msg_in, WHEN MSG_IN
+
+cmdout:
+ INT int_err_unexpected_phase, WHEN NOT CMD
+#if (CHIP == 700)
+ INT int_norm_selected
+#endif
+ENTRY cmdout_cmdout
+cmdout_cmdout:
+#if (CHIP != 700) && (CHIP != 70066)
+ MOVE FROM dsa_cmdout, WHEN CMD
+#else
+ MOVE 0, 0, WHEN CMD
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+
+;
+; data_transfer
+; other_out
+; other_in
+; other_transfer
+;
+; PURPOSE : handle the main data transfer for a SCSI command in
+; several parts. In the first part, data_transfer, DATA_IN
+; and DATA_OUT phases are allowed, with the user provided
+; code (usually dynamically generated based on the scatter/gather
+; list associated with a SCSI command) called to handle these
+; phases.
+;
+; After control has passed to one of the user provided
+; DATA_IN or DATA_OUT routines, back calls are made to
+; other_transfer_in or other_transfer_out to handle non-DATA IN
+; and DATA OUT phases respectively, with the state of the active
+; data pointer being preserved in TEMP.
+;
+; On completion, the user code passes control to other_transfer
+; which causes DATA_IN and DATA_OUT to result in unexpected_phase
+; interrupts so that data overruns may be trapped.
+;
+; INPUTS : DSA - SCSI command
+;
+; CALLS : OK in data_transfer_start, not ok in other_out and other_in, ok in
+; other_transfer
+;
+; MODIFIES : SCRATCH
+;
+; EXITS : if STATUS IN is detected, signifying command completion,
+; the NCR jumps to command_complete. If MSG IN occurs, a
+; CALL is made to msg_in. Otherwise, other_transfer runs in
+; an infinite loop.
+;
+
+ENTRY data_transfer
+data_transfer:
+ JUMP cmdout_cmdout, WHEN CMD
+ CALL msg_in, WHEN MSG_IN
+ INT int_err_unexpected_phase, WHEN MSG_OUT
+ JUMP do_dataout, WHEN DATA_OUT
+ JUMP do_datain, WHEN DATA_IN
+ JUMP command_complete, WHEN STATUS
+ JUMP data_transfer
+ENTRY end_data_transfer
+end_data_transfer:
+
+;
+; FIXME: On NCR53c700 and NCR53c700-66 chips, do_dataout/do_datain
+; should be fixed up whenever the nexus changes so it can point to the
+; correct routine for that command.
+;
+
+#if (CHIP != 700) && (CHIP != 70066)
+; Nasty jump to dsa->dataout
+do_dataout:
+#if (CHIP == 710)
+ MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+ CALL dsa_to_scratch
+#endif
+ MOVE SCRATCH0 + dsa_dataout TO SCRATCH0
+ MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
+ MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
+ MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_scratch, dataout_to_jump + 4
+ DMODE_MEMORY_TO_MEMORY
+dataout_to_jump:
+ MOVE MEMORY 4, 0, dataout_jump + 4
+#if (CHIP == 710)
+ ; Time to correct DSA following memory move
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+dataout_jump:
+ JUMP 0
+
+; Nasty jump to dsa->dsain
+do_datain:
+#if (CHIP == 710)
+ MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+ CALL dsa_to_scratch
+#endif
+ MOVE SCRATCH0 + dsa_datain TO SCRATCH0
+ MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
+ MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
+ MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_scratch, datain_to_jump + 4
+ DMODE_MEMORY_TO_MEMORY
+ENTRY datain_to_jump
+datain_to_jump:
+ MOVE MEMORY 4, 0, datain_jump + 4
+#if (CHIP == 710)
+ ; Time to correct DSA following memory move
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+#ifdef DEBUG
+ INT int_debug_datain
+#endif
+datain_jump:
+ JUMP 0
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+
+
+; Note that other_out and other_in loop until a non-data phase
+; is discovered, so we only execute return statements when we
+; can go on to the next data phase block move statement.
+
+ENTRY other_out
+other_out:
+#if 0
+ INT 0x03ffdead
+#endif
+ INT int_err_unexpected_phase, WHEN CMD
+ JUMP msg_in_restart, WHEN MSG_IN
+ INT int_err_unexpected_phase, WHEN MSG_OUT
+ INT int_err_unexpected_phase, WHEN DATA_IN
+ JUMP command_complete, WHEN STATUS
+ JUMP other_out, WHEN NOT DATA_OUT
+#if (CHIP == 710)
+; TEMP should be OK, as we got here from a call in the user dataout code.
+#endif
+ RETURN
+
+ENTRY other_in
+other_in:
+#if 0
+ INT 0x03ffdead
+#endif
+ INT int_err_unexpected_phase, WHEN CMD
+ JUMP msg_in_restart, WHEN MSG_IN
+ INT int_err_unexpected_phase, WHEN MSG_OUT
+ INT int_err_unexpected_phase, WHEN DATA_OUT
+ JUMP command_complete, WHEN STATUS
+ JUMP other_in, WHEN NOT DATA_IN
+#if (CHIP == 710)
+; TEMP should be OK, as we got here from a call in the user datain code.
+#endif
+ RETURN
+
+
+ENTRY other_transfer
+other_transfer:
+ INT int_err_unexpected_phase, WHEN CMD
+ CALL msg_in, WHEN MSG_IN
+ INT int_err_unexpected_phase, WHEN MSG_OUT
+ INT int_err_unexpected_phase, WHEN DATA_OUT
+ INT int_err_unexpected_phase, WHEN DATA_IN
+ JUMP command_complete, WHEN STATUS
+ JUMP other_transfer
+
+;
+; msg_in_restart
+; msg_in
+; munge_msg
+;
+; PURPOSE : process messages from a target. msg_in is called when the
+; caller hasn't read the first byte of the message. munge_message
+; is called when the caller has read the first byte of the message,
+; and left it in SFBR. msg_in_restart is called when the caller
+; hasn't read the first byte of the message, and wishes RETURN
+; to transfer control back to the address of the conditional
+; CALL instruction rather than to the instruction after it.
+;
+; Various int_* interrupts are generated when the host system
+; needs to intervene, as is the case with SDTR, WDTR, and
+; INITIATE RECOVERY messages.
+;
+; When the host system handles one of these interrupts,
+; it can respond by reentering at reject_message,
+; which rejects the message and returns control to
+; the caller of msg_in or munge_msg, accept_message
+; which clears ACK and returns control, or reply_message
+; which sends the message pointed to by the DSA
+; msgout_other table indirect field.
+;
+; DISCONNECT messages are handled by moving the command
+; to the reconnect_dsa_queue.
+#if (CHIP == 710)
+; NOTE: DSA should be valid when we get here - we cannot save both it
+; and TEMP in this routine.
+#endif
+;
+; INPUTS : DSA - SCSI COMMAND, SFBR - first byte of message (munge_msg
+; only)
+;
+; CALLS : NO. The TEMP register isn't backed up to allow nested calls.
+;
+; MODIFIES : SCRATCH, DSA on DISCONNECT
+;
+; EXITS : On receipt of SAVE DATA POINTER, RESTORE POINTERS,
+; and normal return from message handlers running under
+; Linux, control is returned to the caller. Receipt
+; of DISCONNECT messages pass control to dsa_schedule.
+;
+ENTRY msg_in_restart
+msg_in_restart:
+; XXX - hackish
+;
+; Since it's easier to debug changes to the statically
+; compiled code, rather than the dynamically generated
+; stuff, such as
+;
+; MOVE x, y, WHEN data_phase
+; CALL other_z, WHEN NOT data_phase
+; MOVE x, y, WHEN data_phase
+;
+; I'd like to have certain routines (notably the message handler)
+; restart on the conditional call rather than the next instruction.
+;
+; So, subtract 8 from the return address
+
+ MOVE TEMP0 + 0xf8 TO TEMP0
+ MOVE TEMP1 + 0xff TO TEMP1 WITH CARRY
+ MOVE TEMP2 + 0xff TO TEMP2 WITH CARRY
+ MOVE TEMP3 + 0xff TO TEMP3 WITH CARRY
+
+ENTRY msg_in
+msg_in:
+ MOVE 1, msg_buf, WHEN MSG_IN
+
+munge_msg:
+ JUMP munge_extended, IF 0x01 ; EXTENDED MESSAGE
+ JUMP munge_2, IF 0x20, AND MASK 0xdf ; two byte message
+;
+; XXX - I've seen a handful of broken SCSI devices which fail to issue
+; a SAVE POINTERS message before disconnecting in the middle of
+; a transfer, assuming that the DATA POINTER will be implicitly
+; restored.
+;
+; Historically, I've often done an implicit save when the DISCONNECT
+; message is processed. We may want to consider having the option of
+; doing that here.
+;
+ JUMP munge_save_data_pointer, IF 0x02 ; SAVE DATA POINTER
+ JUMP munge_restore_pointers, IF 0x03 ; RESTORE POINTERS
+ JUMP munge_disconnect, IF 0x04 ; DISCONNECT
+ INT int_msg_1, IF 0x07 ; MESSAGE REJECT
+ INT int_msg_1, IF 0x0f ; INITIATE RECOVERY
+#ifdef EVENTS
+ INT int_EVENT_SELECT_FAILED
+#endif
+ JUMP reject_message
+
+munge_2:
+ JUMP reject_message
+;
+; The SCSI standard allows targets to recover from transient
+; error conditions by backing up the data pointer with a
+; RESTORE POINTERS message.
+;
+; So, we must save and restore the _residual_ code as well as
+; the current instruction pointer. Because of this messiness,
+; it is simpler to put dynamic code in the dsa for this and to
+; just do a simple jump down there.
+;
+
+munge_save_data_pointer:
+#if (CHIP == 710)
+ ; We have something in TEMP here, so first we must save that
+ MOVE TEMP0 TO SFBR
+ MOVE SFBR TO SCRATCH0
+ MOVE TEMP1 TO SFBR
+ MOVE SFBR TO SCRATCH1
+ MOVE TEMP2 TO SFBR
+ MOVE SFBR TO SCRATCH2
+ MOVE TEMP3 TO SFBR
+ MOVE SFBR TO SCRATCH3
+ MOVE MEMORY 4, addr_scratch, jump_temp + 4
+ ; Now restore DSA
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+ MOVE DSA0 + dsa_save_data_pointer TO SFBR
+ MOVE SFBR TO SCRATCH0
+ MOVE DSA1 + 0xff TO SFBR WITH CARRY
+ MOVE SFBR TO SCRATCH1
+ MOVE DSA2 + 0xff TO SFBR WITH CARRY
+ MOVE SFBR TO SCRATCH2
+ MOVE DSA3 + 0xff TO SFBR WITH CARRY
+ MOVE SFBR TO SCRATCH3
+
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_scratch, jump_dsa_save + 4
+ DMODE_MEMORY_TO_MEMORY
+jump_dsa_save:
+ JUMP 0
+
+munge_restore_pointers:
+#if (CHIP == 710)
+ ; The code at dsa_restore_pointers will RETURN, but we don't care
+ ; about TEMP here, as it will overwrite it anyway.
+#endif
+ MOVE DSA0 + dsa_restore_pointers TO SFBR
+ MOVE SFBR TO SCRATCH0
+ MOVE DSA1 + 0xff TO SFBR WITH CARRY
+ MOVE SFBR TO SCRATCH1
+ MOVE DSA2 + 0xff TO SFBR WITH CARRY
+ MOVE SFBR TO SCRATCH2
+ MOVE DSA3 + 0xff TO SFBR WITH CARRY
+ MOVE SFBR TO SCRATCH3
+
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_scratch, jump_dsa_restore + 4
+ DMODE_MEMORY_TO_MEMORY
+jump_dsa_restore:
+ JUMP 0
+
+
+munge_disconnect:
+#ifdef DEBUG
+ INT int_debug_disconnect_msg
+#endif
+
+/*
+ * Before, we overlapped processing with waiting for disconnect, but
+ * debugging was beginning to appear messy. Temporarily move things
+ * to just before the WAIT DISCONNECT.
+ */
+
+#ifdef ORIGINAL
+#if (CHIP == 710)
+; Following clears Unexpected Disconnect bit. What do we do?
+#else
+ MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+ CLEAR ACK
+#endif
+
+#if (CHIP != 700) && (CHIP != 70066)
+ JUMP dsa_schedule
+#else
+ WAIT DISCONNECT
+ INT int_norm_disconnected
+#endif
+
+munge_extended:
+ CLEAR ACK
+ INT int_err_unexpected_phase, WHEN NOT MSG_IN
+ MOVE 1, msg_buf + 1, WHEN MSG_IN
+ JUMP munge_extended_2, IF 0x02
+ JUMP munge_extended_3, IF 0x03
+ JUMP reject_message
+
+munge_extended_2:
+ CLEAR ACK
+ MOVE 1, msg_buf + 2, WHEN MSG_IN
+ JUMP reject_message, IF NOT 0x02 ; Must be WDTR
+ CLEAR ACK
+ MOVE 1, msg_buf + 3, WHEN MSG_IN
+ INT int_msg_wdtr
+
+munge_extended_3:
+ CLEAR ACK
+ MOVE 1, msg_buf + 2, WHEN MSG_IN
+ JUMP reject_message, IF NOT 0x01 ; Must be SDTR
+ CLEAR ACK
+ MOVE 2, msg_buf + 3, WHEN MSG_IN
+ INT int_msg_sdtr
+
+ENTRY reject_message
+reject_message:
+ SET ATN
+ CLEAR ACK
+ MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT
+ RETURN
+
+ENTRY accept_message
+accept_message:
+ CLEAR ATN
+ CLEAR ACK
+ RETURN
+
+ENTRY respond_message
+respond_message:
+ SET ATN
+ CLEAR ACK
+ MOVE FROM dsa_msgout_other, WHEN MSG_OUT
+ RETURN
+
+;
+; command_complete
+;
+; PURPOSE : handle command termination when STATUS IN is detected by reading
+; a status byte followed by a command termination message.
+;
+; Normal termination results in an INTFLY instruction, and
+; the host system can pick out which command terminated by
+; examining the MESSAGE and STATUS buffers of all currently
+; executing commands;
+;
+; Abnormal (CHECK_CONDITION) termination results in an
+; int_err_check_condition interrupt so that a REQUEST SENSE
+; command can be issued out-of-order so that no other command
+; clears the contingent allegiance condition.
+;
+;
+; INPUTS : DSA - command
+;
+; CALLS : OK
+;
+; EXITS : On successful termination, control is passed to schedule.
+; On abnormal termination, the user will usually modify the
+; DSA fields and corresponding buffers and return control
+; to select.
+;
+
+ENTRY command_complete
+command_complete:
+ MOVE FROM dsa_status, WHEN STATUS
+#if (CHIP != 700) && (CHIP != 70066)
+ MOVE SFBR TO SCRATCH0 ; Save status
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+ENTRY command_complete_msgin
+command_complete_msgin:
+ MOVE FROM dsa_msgin, WHEN MSG_IN
+; Indicate that we should be expecting a disconnect
+#if (CHIP != 710)
+ MOVE SCNTL2 & 0x7f TO SCNTL2
+#else
+ ; Above code cleared the Unexpected Disconnect bit, what do we do?
+#endif
+ CLEAR ACK
+#if (CHIP != 700) && (CHIP != 70066)
+ WAIT DISCONNECT
+
+;
+; The SCSI specification states that when a UNIT ATTENTION condition
+; is pending, as indicated by a CHECK CONDITION status message,
+; the target shall revert to asynchronous transfers. Since
+; synchronous transfers parameters are maintained on a per INITIATOR/TARGET
+; basis, and returning control to our scheduler could work on a command
+; running on another lun on that target using the old parameters, we must
+; interrupt the host processor to get them changed, or change them ourselves.
+;
+; Once SCSI-II tagged queueing is implemented, things will be even more
+; hairy, since contingent allegiance conditions exist on a per-target/lun
+; basis, and issuing a new command with a different tag would clear it.
+; In these cases, we must interrupt the host processor to get a request
+; added to the HEAD of the queue with the request sense command, or we
+; must automatically issue the request sense command.
+
+#if 0
+ MOVE SCRATCH0 TO SFBR
+ JUMP command_failed, IF 0x02
+#endif
+#if (CHIP == 710)
+#if defined(MVME166_INTFLY)
+; For MVME166 (ie CHIP=710) we will force an INTFLY by triggering a software
+; interupt (SW7). We can use SCRATCH, as we are about to jump to
+; schedule, which corrupts it anyway. Will probably remove this later,
+; but want to check performance effects first.
+
+#define INTFLY_ADDR 0xfff40070
+
+ MOVE 0 TO SCRATCH0
+ MOVE 0x80 TO SCRATCH1
+ MOVE 0 TO SCRATCH2
+ MOVE 0 TO SCRATCH3
+ MOVE MEMORY 4, addr_scratch, INTFLY_ADDR
+#else
+ INT int_norm_emulateintfly
+#endif
+#else
+ INTFLY
+#endif
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+#if (CHIP == 710)
+ ; Time to correct DSA following memory move
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+#ifdef EVENTS
+ INT int_EVENT_COMPLETE
+#endif
+#if (CHIP != 700) && (CHIP != 70066)
+ JUMP schedule
+command_failed:
+ INT int_err_check_condition
+#else
+ INT int_norm_command_complete
+#endif
+
+;
+; wait_reselect
+;
+; PURPOSE : This is essentially the idle routine, where control lands
+; when there are no new processes to schedule. wait_reselect
+; waits for reselection, selection, and new commands.
+;
+; When a successful reselection occurs, with the aid
+; of fixed up code in each DSA, wait_reselect walks the
+; reconnect_dsa_queue, asking each dsa if the target ID
+; and LUN match its.
+;
+; If a match is found, a call is made back to reselected_ok,
+; which through the miracles of self modifying code, extracts
+; the found DSA from the reconnect_dsa_queue and then
+; returns control to the DSAs thread of execution.
+;
+; INPUTS : NONE
+;
+; CALLS : OK
+;
+; MODIFIES : DSA,
+;
+; EXITS : On successful reselection, control is returned to the
+; DSA which called reselected_ok. If the WAIT RESELECT
+; was interrupted by a new commands arrival signaled by
+; SIG_P, control is passed to schedule. If the NCR is
+; selected, the host system is interrupted with an
+; int_err_selected which is usually responded to by
+; setting DSP to the target_abort address.
+
+ENTRY wait_reselect
+wait_reselect:
+#ifdef EVENTS
+ int int_EVENT_IDLE
+#endif
+#ifdef DEBUG
+ int int_debug_idle
+#endif
+ WAIT RESELECT wait_reselect_failed
+
+reselected:
+#ifdef EVENTS
+ int int_EVENT_RESELECT
+#endif
+ CLEAR TARGET
+ DMODE_MEMORY_TO_MEMORY
+ ; Read all data needed to reestablish the nexus -
+ MOVE 1, reselected_identify, WHEN MSG_IN
+ ; We used to CLEAR ACK here.
+#if (CHIP != 700) && (CHIP != 70066)
+#ifdef DEBUG
+ int int_debug_reselected
+#endif
+
+ ; Point DSA at the current head of the disconnected queue.
+ DMODE_MEMORY_TO_NCR
+ MOVE MEMORY 4, reconnect_dsa_head, addr_scratch
+ DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+ MOVE MEMORY 4, addr_scratch, saved_dsa
+#else
+ CALL scratch_to_dsa
+#endif
+
+ ; Fix the update-next pointer so that the reconnect_dsa_head
+ ; pointer is the one that will be updated if this DSA is a hit
+ ; and we remove it from the queue.
+
+ MOVE MEMORY 4, addr_reconnect_dsa_head, reselected_ok_patch + 8
+#if (CHIP == 710)
+ ; Time to correct DSA following memory move
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+
+ENTRY reselected_check_next
+reselected_check_next:
+#ifdef DEBUG
+ INT int_debug_reselect_check
+#endif
+ ; Check for a NULL pointer.
+ MOVE DSA0 TO SFBR
+ JUMP reselected_not_end, IF NOT 0
+ MOVE DSA1 TO SFBR
+ JUMP reselected_not_end, IF NOT 0
+ MOVE DSA2 TO SFBR
+ JUMP reselected_not_end, IF NOT 0
+ MOVE DSA3 TO SFBR
+ JUMP reselected_not_end, IF NOT 0
+ INT int_err_unexpected_reselect
+
+reselected_not_end:
+ ;
+ ; XXX the ALU is only eight bits wide, and the assembler
+ ; wont do the dirt work for us. As long as dsa_check_reselect
+ ; is negative, we need to sign extend with 1 bits to the full
+ ; 32 bit width of the address.
+ ;
+ ; A potential work around would be to have a known alignment
+ ; of the DSA structure such that the base address plus
+ ; dsa_check_reselect doesn't require carrying from bytes
+ ; higher than the LSB.
+ ;
+
+ MOVE DSA0 TO SFBR
+ MOVE SFBR + dsa_check_reselect TO SCRATCH0
+ MOVE DSA1 TO SFBR
+ MOVE SFBR + 0xff TO SCRATCH1 WITH CARRY
+ MOVE DSA2 TO SFBR
+ MOVE SFBR + 0xff TO SCRATCH2 WITH CARRY
+ MOVE DSA3 TO SFBR
+ MOVE SFBR + 0xff TO SCRATCH3 WITH CARRY
+
+ DMODE_NCR_TO_MEMORY
+ MOVE MEMORY 4, addr_scratch, reselected_check + 4
+ DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+ ; Time to correct DSA following memory move
+ MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+reselected_check:
+ JUMP 0
+
+
+;
+;
+#if (CHIP == 710)
+; We have problems here - the memory move corrupts TEMP and DSA. This
+; routine is called from DSA code, and patched from many places. Scratch
+; is probably free when it is called.
+; We have to:
+; copy temp to scratch, one byte at a time
+; write scratch to patch a jump in place of the return
+; do the move memory
+; jump to the patched in return address
+; DSA is corrupt when we get here, and can be left corrupt
+
+ENTRY reselected_ok
+reselected_ok:
+ MOVE TEMP0 TO SFBR
+ MOVE SFBR TO SCRATCH0
+ MOVE TEMP1 TO SFBR
+ MOVE SFBR TO SCRATCH1
+ MOVE TEMP2 TO SFBR
+ MOVE SFBR TO SCRATCH2
+ MOVE TEMP3 TO SFBR
+ MOVE SFBR TO SCRATCH3
+ MOVE MEMORY 4, addr_scratch, reselected_ok_jump + 4
+reselected_ok_patch:
+ MOVE MEMORY 4, 0, 0
+reselected_ok_jump:
+ JUMP 0
+#else
+ENTRY reselected_ok
+reselected_ok:
+reselected_ok_patch:
+ MOVE MEMORY 4, 0, 0 ; Patched : first word
+ ; is address of
+ ; successful dsa_next
+ ; Second word is last
+ ; unsuccessful dsa_next,
+ ; starting with
+ ; dsa_reconnect_head
+ ; We used to CLEAR ACK here.
+#ifdef DEBUG
+ INT int_debug_reselected_ok
+#endif
+#ifdef DEBUG
+ INT int_debug_check_dsa
+#endif
+ RETURN ; Return control to where
+#endif
+#else
+ INT int_norm_reselected
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+
+selected:
+ INT int_err_selected;
+
+;
+; A select or reselect failure can be caused by one of two conditions :
+; 1. SIG_P was set. This will be the case if the user has written
+; a new value to a previously NULL head of the issue queue.
+;
+; 2. The NCR53c810 was selected or reselected by another device.
+;
+; 3. The bus was already busy since we were selected or reselected
+; before starting the command.
+
+wait_reselect_failed:
+#ifdef EVENTS
+ INT int_EVENT_RESELECT_FAILED
+#endif
+; Check selected bit.
+#if (CHIP == 710)
+ ; Must work out how to tell if we are selected....
+#else
+ MOVE SIST0 & 0x20 TO SFBR
+ JUMP selected, IF 0x20
+#endif
+; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
+ MOVE CTEST2 & 0x40 TO SFBR
+ JUMP schedule, IF 0x40
+; Check connected bit.
+; FIXME: this needs to change if we support target mode
+ MOVE ISTAT & 0x08 TO SFBR
+ JUMP reselected, IF 0x08
+; FIXME : Something bogus happened, and we shouldn't fail silently.
+#if 0
+ JUMP schedule
+#else
+ INT int_debug_panic
+#endif
+
+
+select_failed:
+#if (CHIP == 710)
+ ; Disable selection timer
+ MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+#ifdef EVENTS
+ int int_EVENT_SELECT_FAILED
+#endif
+; Otherwise, mask the selected and reselected bits off SIST0
+#if (CHIP ==710)
+ ; Let's assume we don't get selected for now
+ MOVE SSTAT0 & 0x10 TO SFBR
+#else
+ MOVE SIST0 & 0x30 TO SFBR
+ JUMP selected, IF 0x20
+#endif
+ JUMP reselected, IF 0x10
+; If SIGP is set, the user just gave us another command, and
+; we should restart or return to the scheduler.
+; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
+ MOVE CTEST2 & 0x40 TO SFBR
+ JUMP select, IF 0x40
+; Check connected bit.
+; FIXME: this needs to change if we support target mode
+; FIXME: is this really necessary?
+ MOVE ISTAT & 0x08 TO SFBR
+ JUMP reselected, IF 0x08
+; FIXME : Something bogus happened, and we shouldn't fail silently.
+#if 0
+ JUMP schedule
+#else
+ INT int_debug_panic
+#endif
+
+;
+; test_1
+; test_2
+;
+; PURPOSE : run some verification tests on the NCR. test_1
+; copies test_src to test_dest and interrupts the host
+; processor, testing for cache coherency and interrupt
+; problems in the processes.
+;
+; test_2 runs a command with offsets relative to the
+; DSA on entry, and is useful for miscellaneous experimentation.
+;
+
+; Verify that interrupts are working correctly and that we don't
+; have a cache invalidation problem.
+
+ABSOLUTE test_src = 0, test_dest = 0
+ENTRY test_1
+test_1:
+ MOVE MEMORY 4, test_src, test_dest
+ INT int_test_1
+
+;
+; Run arbitrary commands, with test code establishing a DSA
+;
+
+ENTRY test_2
+test_2:
+ CLEAR TARGET
+#if (CHIP == 710)
+ ; Enable selection timer
+#ifdef NO_SELECTION_TIMEOUT
+ MOVE CTEST7 & 0xff TO CTEST7
+#else
+ MOVE CTEST7 & 0xef TO CTEST7
+#endif
+#endif
+ SELECT ATN FROM 0, test_2_fail
+ JUMP test_2_msgout, WHEN MSG_OUT
+ENTRY test_2_msgout
+test_2_msgout:
+#if (CHIP == 710)
+ ; Disable selection timer
+ MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+ MOVE FROM 8, WHEN MSG_OUT
+ MOVE FROM 16, WHEN CMD
+ MOVE FROM 24, WHEN DATA_IN
+ MOVE FROM 32, WHEN STATUS
+ MOVE FROM 40, WHEN MSG_IN
+#if (CHIP != 710)
+ MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+ CLEAR ACK
+ WAIT DISCONNECT
+test_2_fail:
+#if (CHIP == 710)
+ ; Disable selection timer
+ MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+ INT int_test_2
+
+ENTRY debug_break
+debug_break:
+ INT int_debug_break
+
+;
+; initiator_abort
+; target_abort
+;
+; PURPOSE : Abort the currently established nexus from with initiator
+; or target mode.
+;
+;
+
+ENTRY target_abort
+target_abort:
+ SET TARGET
+ DISCONNECT
+ CLEAR TARGET
+ JUMP schedule
+
+ENTRY initiator_abort
+initiator_abort:
+ SET ATN
+;
+; The SCSI-I specification says that targets may go into MSG out at
+; their leisure upon receipt of the ATN single. On all versions of the
+; specification, we can't change phases until REQ transitions true->false,
+; so we need to sink/source one byte of data to allow the transition.
+;
+; For the sake of safety, we'll only source one byte of data in all
+; cases, but to accommodate the SCSI-I dain bramage, we'll sink an
+; arbitrary number of bytes.
+ JUMP spew_cmd, WHEN CMD
+ JUMP eat_msgin, WHEN MSG_IN
+ JUMP eat_datain, WHEN DATA_IN
+ JUMP eat_status, WHEN STATUS
+ JUMP spew_dataout, WHEN DATA_OUT
+ JUMP sated
+spew_cmd:
+ MOVE 1, NCR53c7xx_zero, WHEN CMD
+ JUMP sated
+eat_msgin:
+ MOVE 1, NCR53c7xx_sink, WHEN MSG_IN
+ JUMP eat_msgin, WHEN MSG_IN
+ JUMP sated
+eat_status:
+ MOVE 1, NCR53c7xx_sink, WHEN STATUS
+ JUMP eat_status, WHEN STATUS
+ JUMP sated
+eat_datain:
+ MOVE 1, NCR53c7xx_sink, WHEN DATA_IN
+ JUMP eat_datain, WHEN DATA_IN
+ JUMP sated
+spew_dataout:
+ MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT
+sated:
+#if (CHIP != 710)
+ MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+ MOVE 1, NCR53c7xx_msg_abort, WHEN MSG_OUT
+ WAIT DISCONNECT
+ INT int_norm_aborted
+
+#if (CHIP != 710)
+;
+; dsa_to_scratch
+; scratch_to_dsa
+;
+; PURPOSE :
+; The NCR chips cannot do a move memory instruction with the DSA register
+; as the source or destination. So, we provide a couple of subroutines
+; that let us switch between the DSA register and scratch register.
+;
+; Memory moves to/from the DSPS register also don't work, but we
+; don't use them.
+;
+;
+
+
+dsa_to_scratch:
+ MOVE DSA0 TO SFBR
+ MOVE SFBR TO SCRATCH0
+ MOVE DSA1 TO SFBR
+ MOVE SFBR TO SCRATCH1
+ MOVE DSA2 TO SFBR
+ MOVE SFBR TO SCRATCH2
+ MOVE DSA3 TO SFBR
+ MOVE SFBR TO SCRATCH3
+ RETURN
+
+scratch_to_dsa:
+ MOVE SCRATCH0 TO SFBR
+ MOVE SFBR TO DSA0
+ MOVE SCRATCH1 TO SFBR
+ MOVE SFBR TO DSA1
+ MOVE SCRATCH2 TO SFBR
+ MOVE SFBR TO DSA2
+ MOVE SCRATCH3 TO SFBR
+ MOVE SFBR TO DSA3
+ RETURN
+#endif
+
+#if (CHIP == 710)
+; Little patched jump, used to overcome problems with TEMP getting
+; corrupted on memory moves.
+
+jump_temp:
+ JUMP 0
+#endif
diff --git a/drivers/scsi/ChangeLog.ncr53c8xx b/drivers/scsi/ChangeLog.ncr53c8xx
index ccf31d453..edc8f395c 100644
--- a/drivers/scsi/ChangeLog.ncr53c8xx
+++ b/drivers/scsi/ChangeLog.ncr53c8xx
@@ -1,3 +1,75 @@
+Sun May 11 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 2.1b
+ - Cosmetic changes.
+ - Some heavy testings under pre-linux-2.1.37-6
+
+Sun May 4 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 2.1a
+ - PFEN wrongly used for PREFETCH feature bit testing.
+ Changed to _F_PFEN.
+ - 2 SCR_COPY that need NO FLUSH bit to be removed had been missed
+ in tp->getscr[] script (loads SXFER and SCNTL3 on reselection).
+
+Sat May 3 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 2.1
+ - Use the NO FLUSH option for MOVE MEMORY (COPY) each time it is
+ possible. More than 100 COPY with NO FLUSH and 6 with FLUSH for
+ my configuration (max queued command / device = 8).
+ This option bit is removed from the script instance for chips
+ that donnot support prefetching.
+ - Rewrite the ncr_exception() routine more simple (I think) and
+ remove useless code.
+ - Change the data_in and data_out script management.
+ Use the bottom part of these scripts instead of the beginning.
+ That avoids to zero the scatter/gather array when a command is
+ queued (1k) and to deal with some weird IID on MOVE 0 bytes when
+ a target wants to transfer more bytes than expected.
+ - Misc. improvements in the init code.
+ - Remove IOMAPPED/MMIO automatic switching option.
+ Was useless and reported not reliable.
+ - Fix a double read of DSTAT and remove DFE testing in the
+ Phase mismatch service routine.
+ - Etc...
+
+Fri Apr 26 20:00 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 2.0a
+ - Add support if the Diamond FirePort 40 (SYM53C875J chip)
+
+Mon Apr 22 22:00 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 2.0
+ - incorporate __initdata and __initfunc directives in order to
+ allow 'init' to free unused memory after driver initialisations.
+ Patch sent by Roberto Fichera.
+ - rewrite the init code of the driver. Now a feature descriptor
+ is used for each real chip types. The code is a lot more clean,
+ since the driver uses device and revision ids only in the
+ detection procedure.
+ - add 'pcifix' boot command line. This command allows to fix up PCI
+ config space for new chips which support features based on the
+ cache line size and 'write and invalidate'.
+ - incorporate in the driver, the code used for error recovery
+ testing. This code is normally not compiled; have to define
+ SCSI_NCR_DEBUG_ERROR_RECOVERY in order to compile it.
+ - take into account actual SCSI bus mode for 53C895 LVD/SE controller.
+ In single ended mode only fast20 is supported.
+ (Just to not be late since such controllers are not yet available)
+
+
+Sat Apr 20 21:00 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 1.18f
+ - fix an old bug included in the initial port (version 0.0).
+ The driver allocated 10 bytes of static data and uses 12 bytes.
+ No danger, since data are generally aligned on 4 bytes boundary
+ and so byte 10 and 11 are free (I hope ...)
+
+Wed Apr 16 12:00 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 1.18e
+ - reset all when an unexpected data cycle is detected while
+ disconnecting.
+ - make changes to abort() ans reset() functions according to
+ Leonard's documentation.
+ - small fix in some message for hard errors.
+
Sat Apr 5 13:00 1997 Gerard Roudier (groudier@club-internet.fr)
* revision 1.18d
- Probe NCR pci device ids in reverse order if asked by user from
diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in
index 580c3d161..ce08d4873 100644
--- a/drivers/scsi/Config.in
+++ b/drivers/scsi/Config.in
@@ -87,6 +87,9 @@ if [ "$CONFIG_PCI" = "y" ]; then
dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
fi
dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
+if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_AM53C974" != "y" ]; then
+ dep_tristate 'Tekram DC-390(T) (AMD PCscsi) SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI
+fi
dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI
dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
if [ "$CONFIG_SCSI_U14_34F" != "n" ]; then
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index f06ef1204..02c066202 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -95,6 +95,30 @@ else
endif
endif
+ifeq ($(CONFIG_A4000T_SCSI),y)
+L_OBJS += amiga7xx.o 53c7xx.o
+else
+ ifeq ($(CONFIG_A4000T_SCSI),m)
+ M_OBJS += amiga7xx.o 53c7xx.o
+ endif
+endif
+
+ifeq ($(CONFIG_A4091_SCSI),y)
+L_OBJS += amiga7xx.o 53c7xx.o
+else
+ ifeq ($(CONFIG_A4091_SCSI),m)
+ M_OBJS += amiga7xx.o 53c7xx.o
+ endif
+endif
+
+ifeq ($(CONFIG_WARPENGINE_SCSI),y)
+L_OBJS += amiga7xx.o 53c7xx.o
+else
+ ifeq ($(CONFIG_WARPENGINE_SCSI),m)
+ M_OBJS += amiga7xx.o 53c7xx.o
+ endif
+endif
+
ifeq ($(CONFIG_A3000_SCSI),y)
L_OBJS += a3000.o wd33c93.o
else
@@ -193,6 +217,14 @@ else
endif
endif
+ifeq ($(CONFIG_SCSI_DC390T),y)
+L_OBJS += tmscsim.o
+else
+ ifeq ($(CONFIG_SCSI_DC390T),m)
+ M_OBJS += tmscsim.o
+ endif
+endif
+
ifeq ($(CONFIG_SCSI_AM53C974),y)
L_OBJS += AM53C974.o
else
@@ -418,6 +450,16 @@ seagate.o: seagate.c
mv scriptu.h 53c8xx_u.h
rm fake.c
+53c7xx.o : 53c7xx_d.h 53c7xx.c
+ $(CC) $(CFLAGS) -c 53c7xx.c
+
+53c7xx_d.h 53c7xx_u.h : 53c7xx.scr script_asm.pl
+ ln -sf 53c7xx.scr fake.c
+ $(CPP) -traditional -DCHIP=710 fake.c | grep -v '^#' | perl -s script_asm.pl -ncr7x0_family
+ mv script.h 53c7xx_d.h
+ mv scriptu.h 53c7xx_u.h
+ rm fake.c
+
ncr53c8xx.o : ncr53c8xx.c
$(CC) $(CFLAGS) -c ncr53c8xx.c
diff --git a/drivers/scsi/README.ncr53c8xx b/drivers/scsi/README.ncr53c8xx
index 53b690f7c..d93492a83 100644
--- a/drivers/scsi/README.ncr53c8xx
+++ b/drivers/scsi/README.ncr53c8xx
@@ -1,10 +1,10 @@
-The linux NCR53C8XX driver README file
+The Linux NCR53C8XX driver README file
Written by Gerard Roudier <groudier@club-internet.fr>
21 Rue Carnot
95170 DEUIL LA BARRE - FRANCE
-6 April 1997
+9 May 1997
===============================================================================
1. Introduction
@@ -22,6 +22,7 @@ Written by Gerard Roudier <groudier@club-internet.fr>
8.5 Set debug mode
8.6 Clear profile counters
8.7 Set flag (no_sync)
+ 8.8 Debug error recovery
9. Configuration parameters
10. Boot setup commands
10.1 Syntax
@@ -203,7 +204,6 @@ General information:
IO port address 0x6000, IRQ number 10
Using memory mapped IO at virtual address 0x282c000
Synchronous transfer period 25, max commands per lun 4
-
Profiling information:
num_trans = 18014
num_kbytes = 671314
@@ -390,6 +390,57 @@ Available commands:
- setflag all
will allow disconnection for all devices on the SCSI bus.
+
+8.8 Debug error recovery
+
+ debug_error_recovery <error to trigger>
+
+ Available error type to trigger:
+ sge: SCSI gross error
+ abort: abort command from the middle-level driver
+ reset: reset command from the middle-level driver
+ parity: scsi parity detected in DATA IN phase
+ none: restore driver normal behaviour
+
+ The code corresponding to this feature is normally not compiled.
+ Its purpose is driver testing only. In order to compile the code
+ that allows to trigger error recovery you must define at compile time
+ SCSI_NCR_DEBUG_ERROR_RECOVERY.
+ If you have compiled the driver with this option, nothing will happen
+ as long as you donnot use the control command 'debug_error_recovery'
+ with sge, abort, reset or parity as argument.
+ If you select an error type, it will be triggered by the driver every
+ 30 seconds.
+
+8.9 PCI configuration fix-up
+
+ pcifix <option bits>
+
+ Available option bits:
+ 0x1: Set PCI cache-line size register if not set.
+ 0x2: Set write and invalidate bit in PCI command register.
+
+ Use 'pcifix:3' in order to allow the driver to fix both PCI features.
+
+ These options only apply to new SYMBIOS chips 810A, 825A, 860 and 875
+ and are only supported for Pentium and 486 class processors.
+ Recent SYMBIOS 53C8XX scsi processors are able to use PCI read multiple
+ and PCI write and invalidate commands. These features require the
+ cache line size register to be properly set in the PCI configuration
+ space of the chips. On the other hand, chips will use PCI write and
+ invalidate commands only if the corresponding bit is set to 1 in the
+ PCI command register.
+
+ Not all PCI bioses set the PCI cache line register and the PCI write and
+ invalidate bit in the PCI configuration space of 53C8XX chips.
+ Optimized PCI accesses may be broken for some PCI/memory controllers or
+ make problems with some PCI boards.
+
+ This fix-up works flawlessly on my system.
+ (MB Triton HX / 53C875 / 53C810A)
+ I use these options at my own risks as you will do if you decide to
+ use them too.
+
9. Configuration parameters
If the firmware of all your devices is perfect enough, all the
@@ -736,9 +787,9 @@ Driver and common files:
You must untar the distribution with the following command:
- tar zxvf ncrBsd2Linux-1.18d-src.tar.gz
+ tar zxvf ncrBsd2Linux-2.1b-src.tar.gz
-The sub-directory ncr53c8xx-1.18d will be created. Change to this directory.
+The sub-directory ncr53c8xx-2.1b will be created. Change to this directory.
12.2 Installation procedure
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index a8638cc97..0290331ce 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -3,6 +3,7 @@
#include <linux/blk.h>
#include <linux/sched.h>
#include <linux/version.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/page.h>
@@ -190,7 +191,7 @@ static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
static int num_a2091 = 0;
-int a2091_detect(Scsi_Host_Template *tpnt)
+__initfunc(int a2091_detect(Scsi_Host_Template *tpnt))
{
static unsigned char called = 0;
struct Scsi_Host *instance;
@@ -243,13 +244,11 @@ Scsi_Host_Template driver_template = A2091_SCSI;
int a2091_release(struct Scsi_Host *instance)
{
#ifdef MODULE
-DMA(instance)->CNTR = 0;
-zorro_unconfig_board(instance->unique_id, 0);
-if (--num_a2091 == 0)
- free_irq(IRQ_AMIGA_PORTS, a2091_intr);
-wd33c93_release();
+ DMA(instance)->CNTR = 0;
+ zorro_unconfig_board(instance->unique_id, 0);
+ if (--num_a2091 == 0)
+ free_irq(IRQ_AMIGA_PORTS, a2091_intr);
+ wd33c93_release();
#endif
-return 1;
+ return 1;
}
-
-
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index 93aa6efa7..fdc7fd41d 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -3,6 +3,7 @@
#include <linux/blk.h>
#include <linux/sched.h>
#include <linux/version.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/page.h>
@@ -166,7 +167,7 @@ static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
}
}
-int a3000_detect(Scsi_Host_Template *tpnt)
+__initfunc(int a3000_detect(Scsi_Host_Template *tpnt))
{
static unsigned char called = 0;
diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
new file mode 100644
index 000000000..2e4b1aa3e
--- /dev/null
+++ b/drivers/scsi/amiga7xx.c
@@ -0,0 +1,107 @@
+/*
+ * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux.
+ * Amiga MacroSystemUS WarpEngine SCSI controller.
+ * Amiga Technologies A4000T SCSI controller.
+ * Amiga Technologies/DKB A4091 SCSI controller.
+ *
+ * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ * plus modifications of the 53c7xx.c driver to support the Amiga.
+ */
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/zorro.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "53c7xx.h"
+#include "amiga7xx.h"
+
+#include<linux/stat.h>
+
+struct proc_dir_entry proc_scsi_amiga7xx = {
+ PROC_SCSI_AMIGA7XX, 8, "Amiga7xx",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+int amiga7xx_detect(Scsi_Host_Template *tpnt)
+{
+ static unsigned char called = 0;
+ int key;
+ int num = 0;
+ unsigned long address;
+ long long options;
+ struct ConfigDev *cd;
+
+ if (called || !MACH_IS_AMIGA)
+ return 0;
+
+ tpnt->proc_dir = &proc_scsi_amiga7xx;
+
+#ifdef CONFIG_WARPENGINE_SCSI
+ if ((key = zorro_find(MANUF_MACROSYSTEMS, PROD_WARP_ENGINE, 0, 0)))
+ {
+ cd = zorro_get_board(key);
+ address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
+ cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, NULL);
+
+ options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+
+ clock = 50000000; /* 50MHz SCSI Clock */
+
+ ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address + 0x40000),
+ 0, IRQ_AMIGA_PORTS & ~IRQ_MACHSPEC, DMA_NONE,
+ options, clock);
+
+ zorro_config_board(key, 0);
+ num++;
+ }
+#endif
+
+#ifdef CONFIG_A4000T_SCSI
+ if (AMIGAHW_PRESENT(A4000_SCSI))
+ {
+ options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+
+ clock = 50000000; /* 50MHz SCSI Clock */
+
+ ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)ZTWO_VADDR(0xDD0040),
+ 0, IRQ_AMIGA_PORTS, DMA_NONE,
+ options, clock);
+ num++;
+ }
+#endif
+
+#ifdef CONFIG_A4091_SCSI
+ while ( (key = zorro_find(MANUF_COMMODORE, PROD_A4091, 0, 0)) ||
+ (key = zorro_find(MANUF_COMMODORE2, PROD_A4091_2, 0, 0)) )
+ {
+ cd = zorro_get_board(key);
+ address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
+ cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, NULL);
+
+ options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+
+ clock = 50000000; /* 50MHz SCSI Clock */
+
+ ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address+0x800000),
+ 0, IRQ_AMIGA_PORTS & ~IRQ_MACHSPEC, DMA_NONE,
+ options, clock);
+
+ zorro_config_board(key, 0);
+ num++;
+ }
+#endif
+
+ called = 1;
+ return num;
+}
diff --git a/drivers/scsi/amiga7xx.h b/drivers/scsi/amiga7xx.h
new file mode 100644
index 000000000..ca85dca7b
--- /dev/null
+++ b/drivers/scsi/amiga7xx.h
@@ -0,0 +1,52 @@
+#ifndef AMIGA7XX_H
+
+#include <linux/types.h>
+
+int amiga7xx_detect(Scsi_Host_Template *);
+const char *NCR53c7x0_info(void);
+int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int NCR53c7xx_abort(Scsi_Cmnd *);
+int NCR53c7x0_release (Scsi_Host_Template *);
+int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 3
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 24
+#endif
+
+#if defined(HOSTS_C) || defined(MODULE)
+#include <scsi/scsicam.h>
+
+extern struct proc_dir_entry proc_scsi_amiga7xx;
+
+#define AMIGA7XX_SCSI {/* next */ NULL, \
+ /* usage_count */ NULL, \
+ /* proc_dir_entry */ NULL, \
+ /* proc_info */ NULL, \
+ /* name */ "Amiga NCR53c710 SCSI", \
+ /* detect */ amiga7xx_detect, \
+ /* release */ NULL, \
+ /* info */ NULL, \
+ /* command */ NULL, \
+ /* queuecommand */ NCR53c7xx_queue_command, \
+ /* abort */ NCR53c7xx_abort, \
+ /* reset */ NCR53c7xx_reset, \
+ /* slave_attach */ NULL, \
+ /* bios_param */ scsicam_bios_param, \
+ /* can_queue */ 24, \
+ /* this_id */ 7, \
+ /* sg_tablesize */ 127, \
+ /* cmd_per_lun */ 3, \
+ /* present */ 0, \
+ /* unchecked_isa_dma */ 0, \
+ /* use_clustering */ DISABLE_CLUSTERING }
+#endif
+#endif /* AMIGA7XX_H */
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 497b47f67..c77e5cd71 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -323,7 +323,7 @@ typedef struct {
static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
-static void init_tags( void )
+__initfunc(static void init_tags( void ))
{
int target, lun;
TAG_ALLOC *ta;
@@ -665,7 +665,7 @@ static __inline__ void queue_main(void)
}
-static void NCR5380_all_init (void)
+static inline void NCR5380_all_init (void)
{
static int done = 0;
if (!done) {
@@ -684,7 +684,7 @@ static void NCR5380_all_init (void)
* Inputs : instance, pointer to this instance. Unused.
*/
-static void NCR5380_print_options (struct Scsi_Host *instance)
+__initfunc(static void NCR5380_print_options (struct Scsi_Host *instance))
{
printk(" generic options"
#ifdef AUTOSENSE
@@ -848,7 +848,7 @@ lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
*
*/
-static void NCR5380_init (struct Scsi_Host *instance, int flags)
+__initfunc(static void NCR5380_init (struct Scsi_Host *instance, int flags))
{
int i;
SETUP_HOSTDATA(instance);
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index d0de9dcdb..15dfb01f1 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -89,6 +89,7 @@
#include <linux/blk.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/atarihw.h>
@@ -765,7 +766,7 @@ int atari_scsi_release (struct Scsi_Host *sh)
}
#endif
-void atari_scsi_setup( char *str, int *ints )
+__initfunc(void atari_scsi_setup( char *str, int *ints ))
{
/* Format of atascsi parameter is:
* atascsi=<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
@@ -869,7 +870,7 @@ int atari_scsi_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
}
-static void atari_scsi_reset_boot( void )
+__initfunc(static void atari_scsi_reset_boot( void ))
{
unsigned long end;
@@ -1025,6 +1026,10 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
{
unsigned long possible_len, limit;
+ if (is_hades)
+ /* Hades has no SCSI DMA at all :-( Always force use of PIO */
+ return( 0 );
+
if (IS_A_TT())
/* TT SCSI DMA can transfer arbitrary #bytes */
return( wanted_len );
diff --git a/drivers/scsi/dc390.h b/drivers/scsi/dc390.h
new file mode 100644
index 000000000..bfe20c96b
--- /dev/null
+++ b/drivers/scsi/dc390.h
@@ -0,0 +1,147 @@
+/***********************************************************************
+ * FILE NAME : DC390.H *
+ * BY : C.L. Huang *
+ * Description: Device Driver for Tekram DC-390(T) PCI SCSI *
+ * Bus Master Host Adapter *
+ ***********************************************************************/
+
+/* Kernel version autodetection */
+
+#include <linux/version.h>
+/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */
+#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,50)
+#define VERSION_ELF_1_2_13
+#elseif LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,95)
+#define VERSION_1_3_85
+#else
+#define VERSION_2_0_0
+#endif
+
+/*
+ * AMD 53C974 driver, header file
+ */
+
+#ifndef DC390_H
+#define DC390_H
+
+#if defined(HOSTS_C) || defined(MODULE)
+
+#ifdef VERSION_2_0_0
+#include <scsi/scsicam.h>
+#else
+#include <linux/scsicam.h>
+#endif
+
+extern int DC390_detect(Scsi_Host_Template *psht);
+extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
+extern int DC390_abort(Scsi_Cmnd *cmd);
+
+#ifdef VERSION_2_0_0
+extern int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags);
+#else
+extern int DC390_reset(Scsi_Cmnd *cmd);
+#endif
+
+#ifdef VERSION_ELF_1_2_13
+extern int DC390_bios_param(Disk *disk, int devno, int geom[]);
+#else
+extern int DC390_bios_param(Disk *disk, kdev_t devno, int geom[]);
+#endif
+
+#ifdef MODULE
+static int DC390_release(struct Scsi_Host *);
+#else
+#define DC390_release NULL
+#endif
+
+#ifndef VERSION_ELF_1_2_13
+extern struct proc_dir_entry proc_scsi_tmscsim;
+extern int tmscsim_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
+#endif
+
+#ifdef VERSION_2_0_0
+
+#define DC390_T { \
+ NULL, /* *next */ \
+ NULL, /* *usage_count */ \
+ &proc_scsi_tmscsim, /* *proc_dir */ \
+ tmscsim_proc_info, /* (*proc_info)() */ \
+ "Tekram DC390(T) V1.10 Dec-05-1996", /* *name */ \
+ DC390_detect, \
+ DC390_release, /* (*release)() */ \
+ NULL, /* *(*info)() */ \
+ NULL, /* (*command)() */ \
+ DC390_queue_command, \
+ DC390_abort, \
+ DC390_reset, \
+ NULL, /* slave attach */\
+ DC390_bios_param, \
+ 10,/* can queue(-1) */ \
+ 7, /* id(-1) */ \
+ SG_ALL, \
+ 2, /* cmd per lun(2) */ \
+ 0, /* present */ \
+ 0, /* unchecked isa dma */ \
+ DISABLE_CLUSTERING \
+ }
+#endif
+
+
+#ifdef VERSION_1_3_85
+
+#define DC390_T { \
+ NULL, /* *next */ \
+ NULL, /* *usage_count */ \
+ &proc_scsi_tmscsim, /* *proc_dir */ \
+ tmscsim_proc_info, /* (*proc_info)() */ \
+ "Tekram DC390(T) V1.10 Dec-05-1996", /* *name */ \
+ DC390_detect, \
+ DC390_release, /* (*release)() */ \
+ NULL, /* *(*info)() */ \
+ NULL, /* (*command)() */ \
+ DC390_queue_command, \
+ DC390_abort, \
+ DC390_reset, \
+ NULL, /* slave attach */\
+ DC390_bios_param, \
+ 10,/* can queue(-1) */ \
+ 7, /* id(-1) */ \
+ SG_ALL, \
+ 2, /* cmd per lun(2) */ \
+ 0, /* present */ \
+ 0, /* unchecked isa dma */ \
+ DISABLE_CLUSTERING \
+ }
+#endif
+
+
+#ifdef VERSION_ELF_1_2_13
+
+#define DC390_T { \
+ NULL, \
+ NULL, \
+ "Tekram DC390(T) V1.10 Dec-05-1996",\
+ DC390_detect, \
+ DC390_release, \
+ NULL, /* info */ \
+ NULL, /* command, deprecated */ \
+ DC390_queue_command, \
+ DC390_abort, \
+ DC390_reset, \
+ NULL, /* slave attach */\
+ DC390_bios_param, \
+ 10,/* can queue(-1) */ \
+ 7, /* id(-1) */ \
+ 16,/* old (SG_ALL) */ \
+ 2, /* cmd per lun(2) */ \
+ 0, /* present */ \
+ 0, /* unchecked isa dma */ \
+ DISABLE_CLUSTERING \
+ }
+#endif
+
+#endif /* defined(HOSTS_C) || defined(MODULE) */
+
+#endif /* DC390_H */
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index fb82d349a..cfff8bfa3 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -1,6 +1,13 @@
/*
* eata.c - Low-level driver for EATA/DMA SCSI host adapters.
*
+ * 17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38
+ * Use of serial_number_at_timeout in abort and reset processing.
+ * Use of the __initfunc and __initdata macro in setup code.
+ * Minor cleanups in the list_statistics code.
+ * Increased controller busy timeout in order to better support
+ * slow SCSI devices.
+ *
* 24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26
* When loading as a module, parameter passing is now supported
* both in 2.0 and in 2.1 style.
@@ -202,8 +209,7 @@
* lc:n disables linked commands;
* tc:y enables tagged commands;
* tc:n disables tagged commands;
- * tm:0 use head/simple/ordered queue tag sequences for reads and ordered
- * queue tags for writes;
+ * tm:0 use head/simple/ordered queue tag sequences;
* tm:1 use only simple queue tags;
* tm:2 use only head of queue tags;
* tm:3 use only ordered queue tags;
@@ -232,10 +238,12 @@
* between increasing or decreasing by minimizing the seek distance between
* the sector of the commands just completed and the sector of the first
* command in the list to be sorted.
- * Trivial math assures that if there are (Q-1) outstanding request for
- * random seeks over S sectors, the unsorted average seek distance is S/2,
- * while the sorted average seek distance is S/(Q-1). The seek distance is
- * hence divided by a factor (Q-1)/2.
+ * Trivial math assures that the unsorted average seek distance when doing
+ * random seeks over S sectors is S/3.
+ * When (Q-1) requests are uniformly distributed over S sectors, the average
+ * distance between two adjacent requests is S/((Q-1) + 1), so the sorted
+ * average seek distance for (Q-1) random requests over S sectors is S/Q.
+ * The elevator sorting hence divides the seek distance by a factor Q/3.
* The above pure geometric remarks are valid in all cases and the
* driver effectively reduces the seek distance by the predicted factor
* when there are Q concurrent read i/o operations on the device, but this
@@ -286,10 +294,18 @@ MODULE_AUTHOR("Dario Ballabio");
#include <asm/dma.h>
#include <asm/irq.h>
#include "eata.h"
-#include<linux/stat.h>
-#include<linux/config.h>
-#include<linux/bios32.h>
-#include<linux/pci.h>
+#include <linux/stat.h>
+#include <linux/config.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,36)
+#include <linux/init.h>
+#else
+#define __initfunc(A) A
+#define __initdata
+#define __init
+#endif
struct proc_dir_entry proc_scsi_eata2x = {
PROC_SCSI_EATA2X, 6, "eata2x",
@@ -517,7 +533,7 @@ static struct Scsi_Host *sh[MAX_BOARDS + 1];
static const char *driver_name = "EATA";
static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
-static unsigned int io_port[] = {
+static unsigned int io_port[] __initdata = {
/* Space for MAX_INT_PARAM ports usable while loading as a module */
SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
@@ -638,8 +654,7 @@ static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
return;
}
-static inline int wait_on_busy(unsigned int iobase) {
- unsigned int loop = MAXLOOP;
+static inline int wait_on_busy(unsigned int iobase, unsigned int loop) {
while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED)
if (--loop == 0) return TRUE;
@@ -649,7 +664,7 @@ static inline int wait_on_busy(unsigned int iobase) {
static inline int do_dma(unsigned int iobase, unsigned int addr, unchar cmd) {
- if (wait_on_busy(iobase)) return TRUE;
+ if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP))) return TRUE;
if ((addr = V2DEV(addr))) {
outb((char) (addr >> 24), iobase + REG_LOW);
@@ -678,8 +693,8 @@ static inline int read_pio(unsigned int iobase, ushort *start, ushort *end) {
return FALSE;
}
-static inline int port_detect(unsigned int port_base, unsigned int j,
- Scsi_Host_Template *tpnt) {
+__initfunc (static inline int port_detect \
+ (unsigned int port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
unsigned char irq, dma_channel, subversion, i;
unsigned char protocol_rev;
struct eata_info info;
@@ -882,7 +897,7 @@ static inline int port_detect(unsigned int port_base, unsigned int j,
sh[j]->max_lun = info.max_lun + 1;
}
- if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "NO DMA");
+ if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST");
else sprintf(dma_name, "DMA %u", dma_channel);
for (i = 0; i < sh[j]->can_queue; i++)
@@ -941,7 +956,7 @@ static inline int port_detect(unsigned int port_base, unsigned int j,
return TRUE;
}
-void eata2x_setup(char *str, int *ints) {
+__initfunc (void eata2x_setup(char *str, int *ints)) {
int i, argc = ints[0];
char *cur = str, *pc;
@@ -974,7 +989,7 @@ void eata2x_setup(char *str, int *ints) {
return;
}
-static void add_pci_ports(void) {
+__initfunc (static void add_pci_ports(void)) {
#if defined(CONFIG_PCI)
@@ -1009,7 +1024,7 @@ static void add_pci_ports(void) {
return;
}
-int eata2x_detect(Scsi_Host_Template *tpnt) {
+__initfunc (int eata2x_detect(Scsi_Host_Template *tpnt)) {
unsigned long flags;
unsigned int j = 0, k;
@@ -1166,6 +1181,9 @@ int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
cpp->reqsen = TRUE;
cpp->dispri = TRUE;
+#if 0
+ if (SCpnt->device->type == TYPE_TAPE) cpp->hbaci = TRUE;
+#endif
cpp->one = TRUE;
cpp->channel = SCpnt->channel;
cpp->target = SCpnt->target;
@@ -1182,14 +1200,12 @@ int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
else if (tag_mode == TAG_SIMPLE) cpp->mess[0] = SIMPLE_QUEUE_TAG;
else if (tag_mode == TAG_HEAD) cpp->mess[0] = HEAD_OF_QUEUE_TAG;
else if (tag_mode == TAG_ORDERED) cpp->mess[0] = ORDERED_QUEUE_TAG;
- else if ((SCpnt->device->current_tag % SCpnt->device->queue_depth) == 0)
+ else if (SCpnt->device->current_tag == 0)
cpp->mess[0] = ORDERED_QUEUE_TAG;
- else if ((SCpnt->device->current_tag % SCpnt->device->queue_depth) == 1)
+ else if (SCpnt->device->current_tag == 1)
cpp->mess[0] = HEAD_OF_QUEUE_TAG;
- else if (cpp->din)
- cpp->mess[0] = SIMPLE_QUEUE_TAG;
else
- cpp->mess[0] = ORDERED_QUEUE_TAG;
+ cpp->mess[0] = SIMPLE_QUEUE_TAG;
cpp->mess[1] = SCpnt->device->current_tag++;
}
@@ -1208,7 +1224,7 @@ int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
if (linked_comm && SCpnt->device->queue_depth > 2
&& TLDEV(SCpnt->device->type)) {
HD(j)->cp_stat[i] = READY;
- flush_dev(SCpnt->device, 0, j, FALSE);
+ flush_dev(SCpnt->device, SCpnt->request.sector, j, FALSE);
restore_flags(flags);
return 0;
}
@@ -1238,7 +1254,8 @@ int eata2x_abort(Scsi_Cmnd *SCarg) {
cli();
j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
- if (SCarg->host_scribble == NULL) {
+ if (SCarg->host_scribble == NULL
+ || SCarg->serial_number != SCarg->serial_number_at_timeout) {
printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
restore_flags(flags);
@@ -1252,7 +1269,7 @@ int eata2x_abort(Scsi_Cmnd *SCarg) {
if (i >= sh[j]->can_queue)
panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: abort, timeout error.\n", BN(j));
restore_flags(flags);
return SCSI_ABORT_ERROR;
@@ -1321,13 +1338,19 @@ int eata2x_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
if (SCarg->host_scribble == NULL)
printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
+ if (SCarg->serial_number != SCarg->serial_number_at_timeout) {
+ printk("%s: reset, pid %ld, reset not running.\n", BN(j), SCarg->pid);
+ restore_flags(flags);
+ return SCSI_RESET_NOT_RUNNING;
+ }
+
if (HD(j)->in_reset) {
printk("%s: reset, exit, already in reset.\n", BN(j));
restore_flags(flags);
return SCSI_RESET_ERROR;
}
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: reset, exit, timeout error.\n", BN(j));
restore_flags(flags);
return SCSI_RESET_ERROR;
@@ -1480,7 +1503,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
unsigned int rev = FALSE, s = TRUE, r = TRUE;
unsigned int input_only = TRUE, overlap = FALSE;
unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
- unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0;
+ unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
@@ -1491,8 +1514,8 @@ static inline void reorder(unsigned int j, unsigned long cursec,
printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\
" av %ldK as %ldK.\n", flushcount, batchcount, inputcount,
ovlcount, readycount, readysorted, sortcount, revcount,
- seeknosort / (readycount - batchcount + 1),
- seeksorted / (readycount - batchcount + 1));
+ seeknosort / (readycount + 1),
+ seeksorted / (readycount + 1));
if (n_ready <= 1) return;
@@ -1520,6 +1543,10 @@ static inline void reorder(unsigned int j, unsigned long cursec,
}
+ if (link_statistics) {
+ if (cursec > sl[0]) seek += cursec - sl[0]; else seek += sl[0] - cursec;
+ }
+
if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
@@ -1537,10 +1564,11 @@ static inline void reorder(unsigned int j, unsigned long cursec,
if (overlap) sort(pl, il, n_ready, FALSE);
if (link_statistics) {
+ if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
batchcount++; readycount += n_ready, seeknosort += seek / 1024;
if (input_only) inputcount++;
if (overlap) { ovlcount++; seeksorted += seek / 1024; }
- else seeksorted += (maxsec - minsec) / 1024;
+ else seeksorted += (iseek + maxsec - minsec) / 1024;
if (rev && !r) { revcount++; readysorted += n_ready; }
if (!rev && !s) { sortcount++; readysorted += n_ready; }
}
diff --git a/drivers/scsi/eata.h b/drivers/scsi/eata.h
index 82791396a..cba391414 100644
--- a/drivers/scsi/eata.h
+++ b/drivers/scsi/eata.h
@@ -12,7 +12,7 @@ int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int eata2x_abort(Scsi_Cmnd *);
int eata2x_reset(Scsi_Cmnd *, unsigned int);
-#define EATA_VERSION "3.00.09"
+#define EATA_VERSION "3.10.00"
#define EATA { \
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index 76da3403f..165a68e60 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -3,6 +3,7 @@
#include <linux/blk.h>
#include <linux/sched.h>
#include <linux/version.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/page.h>
@@ -198,7 +199,7 @@ static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
static int num_gvp11 = 0;
-int gvp11_detect(Scsi_Host_Template *tpnt)
+__initfunc(int gvp11_detect(Scsi_Host_Template *tpnt))
{
static unsigned char called = 0;
struct Scsi_Host *instance;
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 41e5dab80..9bf8c5ec3 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -42,6 +42,10 @@
#include "hosts.h"
+#if defined(CONFIG_A4000T_SCSI) || defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4091_SCSI)
+#include "amiga7xx.h"
+#endif
+
#ifdef CONFIG_A3000_SCSI
#include "a3000.h"
#endif
@@ -158,6 +162,10 @@
#include "NCR53c406a.h"
#endif
+#ifdef CONFIG_SCSI_DC390T
+#include "dc390.h"
+#endif
+
#ifdef CONFIG_SCSI_AM53C974
#include "AM53C974.h"
#endif
@@ -221,6 +229,9 @@ Scsi_Host_Template * scsi_hosts = NULL;
static Scsi_Host_Template builtin_scsi_hosts[] =
{
#ifdef CONFIG_AMIGA
+#if defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4000T_SCSI) || defined(CONFIG_A4091_SCSI)
+ AMIGA7XX_SCSI,
+#endif
#ifdef CONFIG_A3000_SCSI
A3000_SCSI,
#endif
@@ -314,6 +325,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
#ifdef CONFIG_SCSI_EATA
EATA,
#endif
+#ifdef CONFIG_SCSI_DC390T
+ DC390_T,
+#endif
#ifdef CONFIG_SCSI_AM53C974
AM53C974,
#endif
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 7cbb86070..efd6568f1 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -242,7 +242,7 @@ static void idescsi_pc_intr (ide_drive_t *drive)
printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
#endif /* IDESCSI_DEBUG_LOG */
- if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+ if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
#if IDESCSI_DEBUG_LOG
printk ("ide-scsi: %s: DMA complete\n", drive->name);
#endif /* IDESCSI_DEBUG_LOG */
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index a029cef95..e62795b11 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -40,7 +40,7 @@
*/
/*
-** 16 April 1997, version 1.18e
+** 9 May 1997, version 2.1b
**
** Supported SCSI-II features:
** Synchronous negotiation
@@ -56,7 +56,7 @@
** 53C820 (Wide, NCR BIOS in flash bios required)
** 53C825 (Wide, ~53C820 with on board rom BIOS)
** 53C860 (Narrow fast 20, BIOS required)
-** 53C875 (Wide fast 40 with on board rom BIOS)
+** 53C875 (Wide fast 20 with on board rom BIOS)
** 53C895 (Ultra2 80 MB/s with on board rom BIOS)
**
** Other features:
@@ -65,7 +65,6 @@
** Shared IRQ (since linux-1.3.72)
*/
-#define SCSI_NCR_DEBUG
#define SCSI_NCR_DEBUG_FLAGS (0)
#define NCR_DATE "pl24 96/12/14"
@@ -103,6 +102,11 @@
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/stat.h>
+#ifdef __mips__
+#include <asm/bootinfo.h>
+#include <asm/pgtable.h>
+#include <asm/sni.h>
+#endif /* __mips__ */
#include <linux/version.h>
#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
@@ -111,6 +115,17 @@
#include "../block/blk.h"
#endif
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
+#include <linux/init.h>
+#else
+#ifndef __initdata
+#define __initdata
+#endif
+#ifndef __initfunc
+#define __initfunc(__arginit) __arginit
+#endif
+#endif
+
#include "scsi.h"
#include "hosts.h"
#include "constants.h"
@@ -133,15 +148,6 @@ typedef u32 u_int32;
*/
/*
-** Proc info and user command support
-*/
-
-#ifdef SCSI_NCR_PROC_INFO_SUPPORT
-#define SCSI_NCR_PROFILE
-#define SCSI_NCR_USER_COMMAND
-#endif
-
-/*
** SCSI address of this device.
** The boot routines should have set it.
** If not, use this.
@@ -212,8 +218,6 @@ typedef u32 u_int32;
#if defined(SCSI_NCR_IOMAPPED)
#define NCR_IOMAPPED
-#else
-#define NCR_MEMORYMAPPED
#endif
/*
@@ -264,6 +268,8 @@ typedef int vm_size_t;
** In the original Bsd driver, vtophys() is called to translate
** data addresses to IO bus addresses. In order to minimize
** change, I decide to define vtophys() as virt_to_bus().
+*
+* FIXME: Bus addresses are _not_ physical addresses.
*/
#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
@@ -292,6 +298,7 @@ static inline vm_offset_t remap_pci_mem(u_long base, u_long size)
return (vm_offset_t) (page_remapped ? (page_remapped + page_offs) : 0UL);
}
+
static inline void unmap_pci_mem(vm_offset_t vaddr, u_long size)
{
if (vaddr)
@@ -422,6 +429,8 @@ static int guess_xfer_direction(int opcode);
** Head of list of NCR boards
**
** Host is retrieved by its irq level.
+** If interrupts are shared, the internal host control block
+** address (struct ncb) is used as device id.
*/
static struct Scsi_Host *first_host = NULL;
@@ -470,6 +479,7 @@ struct ncr_driver_setup {
unsigned ultra_scsi : 2;
unsigned force_sync_nego: 1;
unsigned reverse_probe: 1;
+ unsigned pci_fix_up: 2;
u_char verbose;
u_char default_tags;
u_short default_sync;
@@ -482,8 +492,13 @@ struct ncr_driver_setup {
u_char irqm;
};
-static struct ncr_driver_setup driver_setup = SCSI_NCR_DRIVER_SETUP;
-static struct ncr_driver_setup driver_safe_setup= SCSI_NCR_DRIVER_SAFE_SETUP;
+static struct ncr_driver_setup
+ driver_setup = SCSI_NCR_DRIVER_SETUP;
+
+#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+static struct ncr_driver_setup
+ driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP;
+#endif
/*
** Other Linux definitions
@@ -503,7 +518,8 @@ static void ncr53c8xx_intr(int irq, struct pt_regs * regs);
static void ncr53c8xx_timeout(unsigned long np);
-#define bootverbose (driver_setup.verbose)
+//#define bootverbose (driver_setup.verbose)
+#define bootverbose 2
/*==========================================================
**
@@ -531,7 +547,7 @@ static void ncr53c8xx_timeout(unsigned long np);
** Can be changed at runtime too.
*/
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
#define DEBUG_FLAGS ncr_debug
#else
#define DEBUG_FLAGS SCSI_NCR_DEBUG_FLAGS
@@ -572,54 +588,54 @@ static void ncr53c8xx_timeout(unsigned long np);
** IO mapped input / ouput
*/
-#define IOM_INB(r) inb (np->port + offsetof(struct ncr_reg, r))
-#define IOM_INB_OFF(o) inb (np->port + (o))
-#define IOM_INW(r) inw (np->port + offsetof(struct ncr_reg, r))
-#define IOM_INL(r) inl (np->port + offsetof(struct ncr_reg, r))
-#define IOM_INL_OFF(o) inl (np->port + (o))
+#define IOM_INB(r) inb (np->port + offsetof(struct ncr_reg, r))
+#define IOM_INB_OFF(o) inb (np->port + (o))
+#define IOM_INW(r) inw (np->port + offsetof(struct ncr_reg, r))
+#define IOM_INL(r) inl (np->port + offsetof(struct ncr_reg, r))
+#define IOM_INL_OFF(o) inl (np->port + (o))
-#define IOM_OUTB(r, val) outb ((val), np->port+offsetof(struct ncr_reg,r))
-#define IOM_OUTW(r, val) outw ((val), np->port+offsetof(struct ncr_reg,r))
-#define IOM_OUTL(r, val) outl ((val), np->port+offsetof(struct ncr_reg,r))
-#define IOM_OUTL_OFF(o, val) outl ((val), np->port + (o))
+#define IOM_OUTB(r, val) outb ((val), np->port+offsetof(struct ncr_reg,r))
+#define IOM_OUTW(r, val) outw ((val), np->port+offsetof(struct ncr_reg,r))
+#define IOM_OUTL(r, val) outl ((val), np->port+offsetof(struct ncr_reg,r))
+#define IOM_OUTL_OFF(o, val) outl ((val), np->port + (o))
/*
** MEMORY mapped IO input / output
*/
-#define MMIO_INB(r) readb(&np->reg->r)
-#define MMIO_INB_OFF(o) readb((char *)np->reg + (o))
-#define MMIO_INW(r) readw(&np->reg->r)
-#define MMIO_INL(r) readl(&np->reg->r)
-#define MMIO_INL_OFF(o) readl((char *)np->reg + (o))
+#define MMIO_INB(r) (*(volatile u8 *)(&np->reg->r))
+#define MMIO_INB_OFF(o) (*(volatile u8 *)((char *)np->reg + (o)))
+#define MMIO_INW(r) (*(volatile u16 *)(&np->reg->r))
+#define MMIO_INL(r) (*(volatile u32 *)(&np->reg->r))
+#define MMIO_INL_OFF(o) (*(volatile u32 *)((char *)np->reg + (o)))
-#define MMIO_OUTB(r, val) writeb((val), &np->reg->r)
-#define MMIO_OUTW(r, val) writew((val), &np->reg->r)
-#define MMIO_OUTL(r, val) writel((val), &np->reg->r)
-#define MMIO_OUTL_OFF(o, val) writel((val), (char *)np->reg + (o))
+#define MMIO_OUTB(r, val) (*(volatile u8 *) &np->reg->r = (val))
+#define MMIO_OUTW(r, val) (*(volatile u16 *) &np->reg->r = (val))
+#define MMIO_OUTL(r, val) (*(volatile u32 *) &np->reg->r = (val))
+#define MMIO_OUTL_OFF(o, val) (*(volatile u32 *) ((char *)np->reg + (o)) = (val))
/*
-** IO mapped only input / output
+** IO mapped input / output
*/
#if defined(NCR_IOMAPPED)
-#define INB(r) IOM_INB(r)
-#define INB_OFF(o) IOM_INB_OFF(o)
-#define INW(r) IOM_INW(r)
-#define INL(r) IOM_INL(r)
-#define INL_OFF(o) IOM_INL_OFF(o)
+#define INB(r) IOM_INB(r)
+#define INB_OFF(o) IOM_INB_OFF(o)
+#define INW(r) IOM_INW(r)
+#define INL(r) IOM_INL(r)
+#define INL_OFF(o) IOM_INL_OFF(o)
-#define OUTB(r, val) IOM_OUTB(r, val)
-#define OUTW(r, val) IOM_OUTW(r, val)
-#define OUTL(r, val) IOM_OUTL(r, val)
-#define OUTL_OFF(o, val) IOM_OUTL_OFF(o, val)
+#define OUTB(r, val) IOM_OUTB(r, val)
+#define OUTW(r, val) IOM_OUTW(r, val)
+#define OUTL(r, val) IOM_OUTL(r, val)
+#define OUTL_OFF(o, val) IOM_OUTL_OFF(o, val)
/*
** MEMORY mapped only input / output
*/
-#elif defined(NCR_MEMORYMAPPED)
+#else
#define INB(r) MMIO_INB(r)
#define INB_OFF(o) MMIO_INB_OFF(o)
@@ -632,23 +648,6 @@ static void ncr53c8xx_timeout(unsigned long np);
#define OUTL(r, val) MMIO_OUTL(r, val)
#define OUTL_OFF(o, val) MMIO_OUTL_OFF(o, val)
-/*
-** IO mapped or MEMORY mapped
-*/
-
-#else
-
-#define INB(r) (np->reg ? MMIO_INB(r) : IOM_INB(r))
-#define INB_OFF(o) (np->reg ? MMIO_INB_OFF(o) : IOM_INB_OFF(o))
-#define INW(r) (np->reg ? MMIO_INW(r) : IOM_INW(r))
-#define INL(r) (np->reg ? MMIO_INL(r) : IOM_INL(r))
-#define INL_OFF(o) (np->reg ? MMIO_INL_OFF(o) : IOM_INL_OFF(o))
-
-#define OUTB(r, val) (np->reg ? MMIO_OUTB(r, val) : IOM_OUTB(r, val))
-#define OUTW(r, val) (np->reg ? MMIO_OUTW(r, val) : IOM_OUTW(r, val))
-#define OUTL(r, val) (np->reg ? MMIO_OUTL(r, val) : IOM_OUTL(r, val))
-#define OUTL_OFF(o, val) (np->reg ? MMIO_OUTL_OFF(o, val) : IOM_OUTL_OFF(o, val))
-
#endif
/*
@@ -657,6 +656,10 @@ static void ncr53c8xx_timeout(unsigned long np);
#define OUTONB(r, m) OUTB(r, INB(r) | (m))
#define OUTOFFB(r, m) OUTB(r, INB(r) & ~(m))
+#define OUTONW(r, m) OUTW(r, INW(r) | (m))
+#define OUTOFFW(r, m) OUTW(r, INW(r) & ~(m))
+#define OUTONL(r, m) OUTL(r, INL(r) | (m))
+#define OUTOFFL(r, m) OUTL(r, INL(r) & ~(m))
/*==========================================================
**
@@ -700,7 +703,8 @@ static void ncr53c8xx_timeout(unsigned long np);
#define SIR_IGN_RESIDUE (11)
#define SIR_MISSING_SAVE (12)
#define SIR_DATA_IO_IS_OUT (13)
-#define SIR_MAX (13)
+#define SIR_DATA_IO_IS_IN (14)
+#define SIR_MAX (14)
/*==========================================================
**
@@ -798,6 +802,10 @@ struct usrcmd {
#define UC_SETFLAG 15
#define UC_CLEARPROF 16
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+#define UC_DEBUG_ERROR_RECOVERY 17
+#endif
+
#define UF_TRACE (0x01)
#define UF_NODISC (0x02)
@@ -813,7 +821,6 @@ struct tstamp {
u_long end;
u_long select;
u_long command;
- u_long data;
u_long status;
u_long disconnect;
u_long reselect;
@@ -1340,13 +1347,20 @@ struct ncb {
**-----------------------------------------------
*/
int unit; /* Unit number */
- int chip; /* Chip number */
+ char chip_name[8]; /* Chip name */
+ char inst_name[16]; /* Instance name */
+ u_int features; /* Chip features map */
struct timer_list timer; /* Timer link header */
int ncr_cache; /* Cache test variable */
Scsi_Cmnd *waiting_list; /* Waiting list header for commands */
/* that we can't put into the squeue */
u_long settle_time; /* Reset in progess */
u_char release_stage; /* Synchronisation stage on release */
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ u_char debug_error_recovery;
+ u_char stalling;
+ u_char assert_atn;
+#endif
/*-----------------------------------------------
** Added field to support differences
@@ -1359,9 +1373,6 @@ struct ncb {
*/
u_short device_id;
u_char revision_id;
-#define ChipDevice ((np)->device_id)
-#define ChipVersion ((np)->revision_id & 0xf0)
-
u_char sv_scntl3;
u_char sv_dmode;
u_char sv_dcntl;
@@ -1370,6 +1381,7 @@ struct ncb {
u_char sv_ctest5;
u_char sv_gpcntl;
u_char sv_stest2;
+ u_char sv_stest4;
u_char rv_dmode;
u_char rv_dcntl;
@@ -1377,6 +1389,9 @@ struct ncb {
u_char rv_ctest4;
u_char rv_ctest5;
u_char rv_stest2;
+
+ u_char maxburst;
+ u_char scsi_mode;
u_char multiplier;
/*-----------------------------------------------
@@ -1616,8 +1631,8 @@ struct script {
ncrcmd resel_tmp [ 5];
ncrcmd resel_lun [ 18];
ncrcmd resel_tag [ 24];
- ncrcmd data_io [ 2]; /* MUST be just before data_in */
- ncrcmd data_in [MAX_SCATTER * 4 + 7];
+ ncrcmd data_io [ 6];
+ ncrcmd data_in [MAX_SCATTER * 4 + 4];
};
/*
@@ -1642,7 +1657,7 @@ struct scripth {
ncrcmd getcc2 [ 14];
#endif
ncrcmd getcc3 [ 10];
- ncrcmd data_out [MAX_SCATTER * 4 + 7];
+ ncrcmd data_out [MAX_SCATTER * 4 + 4];
ncrcmd aborttag [ 4];
ncrcmd abort [ 22];
ncrcmd snooptest [ 9];
@@ -1664,10 +1679,10 @@ static void ncr_exception (ncb_p np);
static void ncr_free_ccb (ncb_p np, ccb_p cp, u_long t, u_long l);
static void ncr_getclock (ncb_p np, int mult);
static void ncr_selectclock (ncb_p np, u_char scntl3);
-static void ncr_save_bios_setting (ncb_p np);
static ccb_p ncr_get_ccb (ncb_p np, u_long t,u_long l);
static void ncr_init (ncb_p np, char * msg, u_long code);
-static int ncr_intr (ncb_p np);
+static int ncr_int_sbmc (ncb_p np);
+static int ncr_int_par (ncb_p np);
static void ncr_int_ma (ncb_p np);
static void ncr_int_sir (ncb_p np);
static void ncr_int_sto (ncb_p np);
@@ -1675,7 +1690,7 @@ static u_long ncr_lookup (char* id);
static void ncr_negotiate (struct ncb* np, struct tcb* tp);
static void ncr_opennings (ncb_p np, lcb_p lp, Scsi_Cmnd * xp);
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
static void ncb_profile (ncb_p np, ccb_p cp);
#endif
@@ -1694,12 +1709,12 @@ static void ncr_timeout (ncb_p np);
static void ncr_wakeup (ncb_p np, u_long code);
static void ncr_start_reset (ncb_p np, int settle_delay);
-#ifdef SCSI_NCR_USER_COMMAND
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
static void ncr_usercmd (ncb_p np);
#endif
-static int ncr_attach (Scsi_Host_Template *tpnt, int unit, u_short device_id,
- u_char revision_id, int chip, u_int base, u_int io_port,
+static int ncr_attach (Scsi_Host_Template *tpnt, int unit,
+ ncr_chip *chip, u_int base, u_int io_port,
int irq, int bus, u_char device_fn);
static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd);
@@ -1720,24 +1735,13 @@ static void process_waiting_list(ncb_p np, int sts);
**==========================================================
*/
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
static int ncr_debug = SCSI_NCR_DEBUG_FLAGS;
#endif
-/*==========================================================
-**
-**
-** Global static data: auto configure
-**
-**
-**==========================================================
-*/
-
-static char *ncr_name (ncb_p np)
+static inline char *ncr_name (ncb_p np)
{
- static char name[16];
- sprintf(name, "ncr53c%d-%d", np->chip, np->unit);
- return (name);
+ return np->inst_name;
}
@@ -1783,10 +1787,10 @@ static char *ncr_name (ncb_p np)
* Kernel variables referenced in the scripts.
* THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY.
*/
-static void *script_kvars[] =
+static void *script_kvars[] __initdata =
{ (void *)&jiffies };
-static struct script script0 = {
+static struct script script0 __initdata = {
/*--------------------------< START >-----------------------*/ {
/*
** Claim to be still alive ...
@@ -1881,7 +1885,7 @@ static struct script script0 = {
** patch the launch field.
** should look like an idle process.
*/
- SCR_COPY (4),
+ SCR_COPY_F (4),
RADDR (dsa),
PADDR (skip2),
SCR_COPY (8),
@@ -1987,7 +1991,7 @@ static struct script script0 = {
** We patch the address part of a
** COPY command with the DSA-register.
*/
- SCR_COPY (4),
+ SCR_COPY_F (4),
RADDR (dsa),
PADDR (loadpos),
/*
@@ -2376,7 +2380,7 @@ static struct script script0 = {
/*
** and copy back the header to the ccb.
*/
- SCR_COPY (4),
+ SCR_COPY_F (4),
RADDR (dsa),
PADDR (cleanup0),
SCR_COPY (sizeof (struct head)),
@@ -2482,7 +2486,7 @@ static struct script script0 = {
**
** CAUTION: only little endian architectures supported! XXX
*/
- SCR_COPY (1),
+ SCR_COPY_F (1),
NADDR (header.savep),
PADDR (disconnect0),
}/*-------------------------< DISCONNECT0 >--------------*/,{
@@ -2491,7 +2495,7 @@ static struct script script0 = {
/*
** neither this
*/
- SCR_COPY (1),
+ SCR_COPY_F (1),
NADDR (header.goalp),
PADDR (disconnect1),
}/*-------------------------< DISCONNECT1 >--------------*/,{
@@ -2587,7 +2591,7 @@ static struct script script0 = {
** This NOP will be patched with LED OFF
** SCR_REG_REG (gpreg, SCR_OR, 0x01)
*/
- SCR_JUMP ^ IFFALSE (0),
+ SCR_NO_OP,
0,
/*
** make the DSA invalid.
@@ -2609,7 +2613,7 @@ static struct script script0 = {
** This NOP will be patched with LED ON
** SCR_REG_REG (gpreg, SCR_AND, 0xfe)
*/
- SCR_JUMP ^ IFFALSE (0),
+ SCR_NO_OP,
0,
/*
** ... zu nichts zu gebrauchen ?
@@ -2635,7 +2639,7 @@ static struct script script0 = {
** This NOP will be patched with LED ON
** SCR_REG_REG (gpreg, SCR_AND, 0xfe)
*/
- SCR_JUMP ^ IFFALSE (0),
+ SCR_NO_OP,
0,
/*
** If it's not connected :(
@@ -2758,10 +2762,14 @@ static struct script script0 = {
** to low-level scsi drivers, we must trust the target
** for actual data direction when we cannot guess it.
** The programmed interrupt patches savep, lastp, goalp,
-** etc.., and restarts the scsi script at data_out.
+** etc.., and restarts the scsi script at data_out/in.
*/
SCR_INT ^ IFTRUE (WHEN (SCR_DATA_OUT)),
SIR_DATA_IO_IS_OUT,
+ SCR_INT ^ IFTRUE (WHEN (SCR_DATA_IN)),
+ SIR_DATA_IO_IS_IN,
+ SCR_JUMP,
+ PADDR (no_data),
}/*-------------------------< DATA_IN >--------------------*/,{
/*
@@ -2769,15 +2777,7 @@ static struct script script0 = {
** #define MAX_SCATTER parameter,
** it is filled in at runtime.
**
-** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
-** PADDR (no_data),
-** SCR_COPY (sizeof (u_long)),
-** KVAR(SCRIPT_KVAR_JIFFIES),
-** NADDR (header.stamp.data),
-** SCR_MOVE_TBL ^ SCR_DATA_IN,
-** offsetof (struct dsb, data[ 0]),
-**
-** ##===========< i=1; i<MAX_SCATTER >=========
+** ##===========< i=0; i<MAX_SCATTER >=========
** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
** || PADDR (checkatn),
** || SCR_MOVE_TBL ^ SCR_DATA_IN,
@@ -2793,7 +2793,7 @@ static struct script script0 = {
}/*--------------------------------------------------------*/
};
-static struct scripth scripth0 = {
+static struct scripth scripth0 __initdata = {
/*-------------------------< TRYLOOP >---------------------*/{
/*
** Load an entry of the start queue into dsa
@@ -3109,7 +3109,7 @@ static struct scripth scripth0 = {
** We patch the address part of a COPY command
** with the address of the dsa register ...
*/
- SCR_COPY (4),
+ SCR_COPY_F (4),
RADDR (dsa),
PADDRH (getcc1),
/*
@@ -3247,15 +3247,7 @@ static struct scripth scripth0 = {
** #define MAX_SCATTER parameter,
** it is filled in at runtime.
**
-** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT)),
-** PADDR (no_data),
-** SCR_COPY (sizeof (u_long)),
-** KVAR(SCRIPT_KVAR_JIFFIES),
-** NADDR (header.stamp.data),
-** SCR_MOVE_TBL ^ SCR_DATA_OUT,
-** offsetof (struct dsb, data[ 0]),
-**
-** ##===========< i=1; i<MAX_SCATTER >=========
+** ##===========< i=0; i<MAX_SCATTER >=========
** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
** || PADDR (dispatch),
** || SCR_MOVE_TBL ^ SCR_DATA_OUT,
@@ -3269,7 +3261,7 @@ static struct scripth scripth0 = {
**
**---------------------------------------------------------
*/
-0 /* was (u_long)&ident ? */
+0
}/*-------------------------< ABORTTAG >-------------------*/,{
/*
** Abort a bad reselection.
@@ -3343,7 +3335,9 @@ static struct scripth scripth0 = {
**==========================================================
*/
+__initfunc(
void ncr_script_fill (struct script * scr, struct scripth * scrh)
+)
{
int i;
ncrcmd *p;
@@ -3363,15 +3357,7 @@ void ncr_script_fill (struct script * scr, struct scripth * scrh)
p = scr->data_in;
- *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN));
- *p++ =PADDR (no_data);
- *p++ =SCR_COPY (sizeof (u_long));
- *p++ =KVAR(SCRIPT_KVAR_JIFFIES);
- *p++ =NADDR (header.stamp.data);
- *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
- *p++ =offsetof (struct dsb, data[ 0]);
-
- for (i=1; i<MAX_SCATTER; i++) {
+ for (i=0; i<MAX_SCATTER; i++) {
*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
*p++ =PADDR (checkatn);
*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
@@ -3387,15 +3373,7 @@ void ncr_script_fill (struct script * scr, struct scripth * scrh)
p = scrh->data_out;
- *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT));
- *p++ =PADDR (no_data);
- *p++ =SCR_COPY (sizeof (u_long));
- *p++ =KVAR(SCRIPT_KVAR_JIFFIES);
- *p++ =NADDR (header.stamp.data);
- *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
- *p++ =offsetof (struct dsb, data[ 0]);
-
- for (i=1; i<MAX_SCATTER; i++) {
+ for (i=0; i<MAX_SCATTER; i++) {
*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
*p++ =PADDR (dispatch);
*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
@@ -3419,11 +3397,14 @@ void ncr_script_fill (struct script * scr, struct scripth * scrh)
**==========================================================
*/
+__initfunc(
static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
+)
{
ncrcmd opcode, new, old, tmp1, tmp2;
ncrcmd *start, *end;
int relocs;
+ int opchanged = 0;
start = src;
end = src + len/4;
@@ -3470,6 +3451,14 @@ static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int le
ncr_name(np), (int) (src-start-1));
DELAY (1000000);
}
+ /*
+ ** If PREFETCH feature not enabled, remove
+ ** the NO FLUSH bit if present.
+ */
+ if ((opcode & SCR_NO_FLUSH) && !(np->features & _F_PFEN)) {
+ dst[-1] = (opcode & ~SCR_NO_FLUSH);
+ ++opchanged;
+ }
break;
case 0x0:
@@ -3546,6 +3535,9 @@ static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int le
*dst++ = *src++;
};
+ if (bootverbose > 1 && opchanged)
+ printf("%s: NO FLUSH bit removed from %d script instructions\n",
+ ncr_name(np), opchanged);
}
/*==========================================================
@@ -3595,6 +3587,218 @@ static void PRINT_ADDR(Scsi_Cmnd *cmd)
if (np) PRINT_LUN(np, cmd->target, cmd->lun);
}
+/*===============================================================
+**
+** Prepare io register values used by ncr_init() according
+** to selected and supported features.
+**
+** NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128
+** transfers. 32,64,128 are only supported by 875 and 895 chips.
+** We use log base 2 (burst length) as internal code, with
+** value 0 meaning "burst disabled".
+**
+**===============================================================
+*/
+
+/*
+ * Burst length from burst code.
+ */
+#define burst_length(bc) (!(bc))? 0 : 1 << (bc)
+
+/*
+ * Burst code from io register bits.
+ */
+#define burst_code(dmode, ctest4, ctest5) \
+ (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
+
+/*
+ * Set initial io register bits from burst code.
+ */
+static inline void ncr_init_burst(ncb_p np, u_char bc)
+{
+ np->rv_ctest4 &= ~0x80;
+ np->rv_dmode &= ~(0x3 << 6);
+ np->rv_ctest5 &= ~0x4;
+
+ if (!bc) {
+ np->rv_ctest4 |= 0x80;
+ }
+ else {
+ --bc;
+ np->rv_dmode |= ((bc & 0x3) << 6);
+ np->rv_ctest5 |= (bc & 0x4);
+ }
+}
+
+__initfunc(
+static int ncr_prepare_setting(ncb_p np)
+)
+{
+ u_char burst_max;
+
+ /*
+ ** Save assumed BIOS setting
+ */
+
+ np->sv_scntl3 = INB(nc_scntl3) & 0x07;
+ np->sv_dmode = INB(nc_dmode) & 0xce;
+ np->sv_dcntl = INB(nc_dcntl) & 0xa8;
+ np->sv_ctest3 = INB(nc_ctest3) & 0x01;
+ np->sv_ctest4 = INB(nc_ctest4) & 0x80;
+ np->sv_ctest5 = INB(nc_ctest5) & 0x24;
+ np->sv_gpcntl = INB(nc_gpcntl);
+ np->sv_stest2 = INB(nc_stest2) & 0x20;
+ np->sv_stest4 = INB(nc_stest4);
+
+ /*
+ ** Get the frequency of the chip's clock.
+ ** Find the right value for scntl3.
+ */
+
+ if (np->features & _F_QUAD)
+ np->multiplier = 4;
+ else if (np->features & _F_DBLR)
+ np->multiplier = 2;
+ else
+ np->multiplier = 1;
+
+ np->clock_khz = (np->features & _F_CLK80)? 80000 : 40000;
+ np->clock_khz *= np->multiplier;
+
+ if (np->clock_khz != 40000)
+ ncr_getclock(np, np->multiplier);
+
+ if (np->clock_khz <= 25000) np->rv_scntl3 = 0x01;
+ else if (np->clock_khz <= 37500) np->rv_scntl3 = 0x02;
+ else if (np->clock_khz <= 50000) np->rv_scntl3 = 0x03;
+ else if (np->clock_khz <= 75000) np->rv_scntl3 = 0x04;
+ else if (np->clock_khz <= 100000) np->rv_scntl3 = 0x05;
+ else if (np->clock_khz <= 150000) np->rv_scntl3 = 0x06;
+ else np->rv_scntl3 = 0x07;
+
+ /*
+ ** Get on-board RAM bus address when supported
+ */
+ if (np->features & _F_RAM) {
+ OUTONB(nc_ctest2, 0x8);
+ np->paddr2 = INL(nc_scr0);
+ OUTOFFB(nc_ctest2, 0x8);
+ }
+
+ /*
+ ** Prepare initial value of other IO registers
+ */
+#if defined SCSI_NCR_TRUST_BIOS_SETTING
+ np->rv_dmode = np->sv_dmode;
+ np->rv_dcntl = np->sv_dcntl;
+ np->rv_ctest3 = np->sv_ctest3;
+ np->rv_ctest4 = np->sv_ctest4;
+ np->rv_ctest5 = np->sv_ctest5;
+ burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
+#else
+ np->rv_dmode = 0;
+ np->rv_dcntl = 0;
+ np->rv_ctest3 = 0;
+ np->rv_ctest4 = 0;
+ np->rv_ctest5 = 0;
+ np->rv_stest2 = 0;
+
+ /*
+ ** Select burst length (dwords)
+ */
+ burst_max = driver_setup.burst_max;
+ if (burst_max == 255)
+ burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
+ if (burst_max > 7)
+ burst_max = 7;
+ if (burst_max > np->maxburst)
+ burst_max = np->maxburst;
+
+ /*
+ ** Select all supported special features
+ */
+ if (np->features & _F_ERL)
+ np->rv_dmode |= ERL; /* Enable Read Line */
+ if (np->features & _F_BOF)
+ np->rv_dmode |= BOF; /* Burst Opcode Fetch */
+ if (np->features & _F_ERMP)
+ np->rv_dmode |= ERMP; /* Enable Read Multiple */
+ if (np->features & _F_PFEN)
+ np->rv_dcntl |= PFEN; /* Prefetch Enable */
+ if (np->features & _F_CLSE)
+ np->rv_dcntl |= CLSE; /* Cache Line Size Enable */
+ if (np->features & _F_WRIE)
+ np->rv_ctest3 |= WRIE; /* Write and Invalidate */
+ if (np->features & _F_DFS)
+ np->rv_ctest5 |= DFS; /* Dma Fifo Size */
+
+ /*
+ ** Select some other
+ */
+ if (driver_setup.master_parity)
+ np->rv_ctest4 |= MPEE; /* Master parity checking */
+
+#endif /* SCSI_NCR_TRUST_BIOS_SETTING */
+
+ /*
+ * Prepare initial io register bits for burst length
+ */
+ ncr_init_burst(np, burst_max);
+
+ /*
+ ** Set differential mode.
+ */
+ switch(driver_setup.diff_support) {
+ case 3:
+ if (INB(nc_gpreg) & 0x08)
+ break;
+ case 2:
+ np->rv_stest2 |= 0x20;
+ break;
+ case 1:
+ np->rv_stest2 |= (np->sv_stest2 & 0x20);
+ break;
+ default:
+ break;
+ }
+
+ /*
+ ** Set irq mode.
+ */
+ switch(driver_setup.irqm) {
+ case 2:
+ np->rv_dcntl |= IRQM;
+ break;
+ case 1:
+ np->rv_stest2 |= (np->sv_dcntl & IRQM);
+ break;
+ default:
+ break;
+ }
+
+ /*
+ ** Announce all that stuff to user.
+ */
+ if (bootverbose > 1) {
+ printf ("%s: initial value of SCNTL3 = %02x, final = %02x\n",
+ ncr_name(np), np->sv_scntl3, np->rv_scntl3);
+ printf ("%s: initial value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
+ ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
+ printf ("%s: final value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
+ ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
+ if (np->rv_stest2 & 0x20)
+ printf ("%s: DIFF mode set\n", ncr_name(np));
+ }
+
+ if (bootverbose && np->paddr2)
+ printf ("%s: on-board RAM at 0x%lx\n", ncr_name(np), np->paddr2);
+
+ if (bootverbose && np->ns_sync < 25)
+ printf ("%s: Ultra%s SCSI support enabled\n", ncr_name(np),
+ np->ns_sync < 12 ? "-2": "");
+
+ return 0;
+}
/*
** Host attach and initialisations.
@@ -3602,25 +3806,23 @@ static void PRINT_ADDR(Scsi_Cmnd *cmd)
** Allocate host data and ncb structure.
** Request IO region and remap MMIO region.
** Do chip initialization.
-** Try with mmio.
-** If mmio not possible (misconfigured cache),
-** retry with io mapped.
** If all is OK, install interrupt handling and
** start the timer daemon.
*/
-static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ushort device_id,
- u_char revision_id, int chip, u_int base, u_int io_port,
+__initfunc(
+static int ncr_attach (Scsi_Host_Template *tpnt, int unit,
+ ncr_chip *chip, u_int base, u_int io_port,
int irq, int bus, u_char device_fn)
-
+)
{
struct host_data *host_data;
ncb_p np;
struct Scsi_Host *instance = 0;
u_long flags = 0;
-printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
- unit, chip, revision_id, base, io_port, irq);
+printf("ncr53c8xx: unit=%d chip=%s rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
+ unit, chip->name, chip->revision_id, base, io_port, irq);
/*
** Allocate host_data structure
@@ -3645,10 +3847,21 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
np->ccb = (ccb_p) (((u_long) &host_data->_ccb_data) & CCB_ALIGN_MASK);
bzero (np->ccb, sizeof (*np->ccb));
- np->unit = unit;
- np->chip = chip;
- np->device_id = device_id;
- np->revision_id = revision_id;
+ /*
+ ** Store input informations in the host data structure.
+ */
+ strncpy(np->chip_name, chip->name, sizeof(np->chip_name) - 1);
+ np->unit = unit;
+ sprintf(np->inst_name, "ncr53c%s-%d", np->chip_name, np->unit);
+ np->device_id = chip->device_id;
+ np->revision_id = chip->revision_id;
+ np->features = chip->features;
+ np->maxwide = (np->features & _F_WIDE)? 1 : 0;
+ np->ns_sync = 25;
+ np->clock_khz = 40000;
+ np->clock_divn = chip->nr_divisor;
+ np->maxoffs = chip->offset_max;
+ np->maxburst = chip->burst_max;
np->script0 =
(struct script *) (((u_long) &host_data->script_data) & SCR_ALIGN_MASK);
@@ -3673,9 +3886,7 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
np->vaddr = remap_pci_mem((u_long) base, (u_long) 128);
if (!np->vaddr) {
printf("%s: can't map memory mapped IO region\n", ncr_name(np));
-#ifdef NCR_MEMORYMAPPED
goto attach_error;
-#endif
}
else
if (bootverbose > 1)
@@ -3699,97 +3910,16 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
np->port = io_port;
/*
- ** Save initial value of some io registers.
- */
-
- ncr_save_bios_setting(np);
-
- /*
** Do chip dependent initialization.
*/
-
- np->maxwide = 0;
- np->rv_scntl3 = 0x13; /* default: 40MHz clock */
- np->ns_sync = 25;
- np->clock_khz = 40000;
- np->clock_divn = 4;
- np->maxoffs = 8;
- np->multiplier = 1;
-
- /*
- ** Get the frequency of the chip's clock.
- ** Find the right value for scntl3.
- */
-
- switch (device_id) {
- case PCI_DEVICE_ID_NCR_53C825:
- np->maxwide = 1;
- break;
- case PCI_DEVICE_ID_NCR_53C860:
- if (driver_setup.ultra_scsi) {
- np->rv_scntl3 = 0x15;
- np->clock_khz = 80000;
- np->ns_sync = 12;
- }
- else
- np->rv_scntl3 = 0x35; /* always assume 80MHz clock for 860 */
- np->clock_divn = 5;
- break;
- case PCI_DEVICE_ID_NCR_53C875:
- case PCI_DEVICE_ID_NCR_53C885:
- np->maxwide = 1;
- if (driver_setup.special_features)
- np->maxoffs = 16;
- np->clock_divn = 5;
- if (device_id == PCI_DEVICE_ID_NCR_53C875)
- ncr_getclock(np, revision_id >= 2 ? 2 : 1);
- else
- ncr_getclock(np, 2);
- break;
- case PCI_DEVICE_ID_NCR_53C895:
- case PCI_DEVICE_ID_NCR_53C896:
- np->maxwide = 1;
- if (driver_setup.special_features)
- np->maxoffs = 31;
- np->clock_divn = 7;
- ncr_getclock(np, 4);
- break;
- }
-
- /*
- ** Get on-board RAM bus address when supported
- */
- switch (device_id) {
- case PCI_DEVICE_ID_NCR_53C825:
- if (revision_id < 0x10)
- break;
- case PCI_DEVICE_ID_NCR_53C875:
- case PCI_DEVICE_ID_NCR_53C885:
- case PCI_DEVICE_ID_NCR_53C895:
- case PCI_DEVICE_ID_NCR_53C896:
- if (driver_setup.special_features) {
- OUTONB(nc_ctest2, 0x8);
- np->paddr2 = INL(nc_scr0);
- OUTOFFB(nc_ctest2, 0x8);
- }
- break;
- }
-
- if (bootverbose && np->paddr2)
- printf ("%s: on-board RAM at 0x%lx\n", ncr_name(np), np->paddr2);
-
- if (bootverbose && np->ns_sync < 25)
- printf ("%s: Ultra%s SCSI support enabled\n", ncr_name(np),
- np->ns_sync < 12 ? "-2": "");
+ (void)ncr_prepare_setting(np);
#ifndef NCR_IOMAPPED
if (np->paddr2 && sizeof(struct script) <= 4096) {
np->vaddr2 = remap_pci_mem((u_long) np->paddr2, (u_long) 4096);
if (!np->vaddr2) {
printf("%s: can't map memory mapped IO region\n", ncr_name(np));
-#ifdef NCR_MEMORYMAPPED
goto attach_error;
-#endif
}
else
if (bootverbose > 1)
@@ -3831,16 +3961,23 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
np->ccb->p_ccb = vtophys (np->ccb);
/*
+ ** Patch the script for LED support.
+ */
+
+ if (driver_setup.led_pin & (~np->sv_gpcntl) & 0x01) {
+ np->features |= _F_LED0;
+ np->script0->reselect[0] = SCR_REG_REG(gpreg, SCR_OR, 0x01);
+ np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
+ np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
+ }
+
+ /*
** init data structure
*/
np->jump_tcb.l_cmd = SCR_JUMP;
np->jump_tcb.l_paddr = NCB_SCRIPTH_PHYS (np, abort);
-#if !defined(NCR_IOMAPPED) && !defined(NCR_MEMORYMAPPED)
-retry_chip_init:
-#endif
-
/*
** Get SCSI addr of host adapter (set by bios?).
*/
@@ -3864,14 +4001,6 @@ retry_chip_init:
*/
if (ncr_snooptest (np)) {
-#if !defined(NCR_IOMAPPED) && !defined(NCR_MEMORYMAPPED)
- if (np->reg) {
-printf("%s: cache misconfigured, retrying with IO mapped at 0x%lx\n",
- ncr_name(np), (u_long) np->port);
- np->reg = 0;
- goto retry_chip_init;
- }
-#endif
printf ("CACHE INCORRECTLY CONFIGURED.\n");
goto attach_error;
};
@@ -3962,18 +4091,25 @@ printf("%s: cache misconfigured, retrying with IO mapped at 0x%lx\n",
attach_error:
if (!instance) return -1;
+ printf("%s: detaching...\n", ncr_name(np));
#ifndef NCR_IOMAPPED
if (np->vaddr) {
+#ifdef DEBUG_NCR53C8XX
printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
+#endif
unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
}
if (np->vaddr2) {
+#ifdef DEBUG_NCR53C8XX
printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
+#endif
unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
}
#endif
if (np->port) {
+#ifdef DEBUG_NCR53C8XX
printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+#endif
release_region(np->port, 128);
}
scsi_unregister(instance);
@@ -3984,47 +4120,6 @@ attach_error:
/*==========================================================
**
**
-** Process pending device interrupts.
-**
-**
-**==========================================================
-*/
-int ncr_intr(np)
- ncb_p np;
-{
- int n = 0;
- u_long flags;
-
- save_flags(flags); cli();
-
- if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
-
-#ifdef SCSI_NCR_PARANOIA
- if (INB(nc_istat) & (INTF|SIP|DIP)) {
- /*
- ** Repeat until no outstanding ints
- */
- do {
-#endif
- ncr_exception (np);
-#ifdef SCSI_NCR_PARANOIA
- } while (INB(nc_istat) & (INTF|SIP|DIP));
-
- n=1;
- np->ticks = 5 * HZ;
- };
-#endif
-
- if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
-
- restore_flags(flags);
-
- return (n);
-}
-
-/*==========================================================
-**
-**
** Start execution of a SCSI command.
** This is called from the generic SCSI driver.
**
@@ -4107,7 +4202,7 @@ int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
**
**----------------------------------------------------
*/
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
bzero (&cp->phys.header.stamp, sizeof (struct tstamp));
cp->phys.header.stamp.start = jiffies;
#endif
@@ -4337,25 +4432,30 @@ int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
*/
cp->segments = segments;
+ if (!cp->data_len)
+ xfer_direction = XferNone;
switch (xfer_direction) {
+ u_long endp;
default:
case XferBoth:
- cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_io);
- cp->phys.header.goalp = cp->phys.header.savep +8 +20 +segments*16;
- break;
+ cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_io);
+ cp->phys.header.goalp = cp->phys.header.savep;
+ break;
case XferIn:
- cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_in);
- cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
- break;
+ endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16;
+ cp->phys.header.goalp = endp + 8;
+ cp->phys.header.savep = endp - segments*16;
+ break;
case XferOut:
- cp->phys.header.savep = NCB_SCRIPTH_PHYS (np, data_out);
- cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
- break;
+ endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
+ cp->phys.header.goalp = endp + 8;
+ cp->phys.header.savep = endp - segments*16;
+ break;
case XferNone:
- cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data);
- cp->phys.header.goalp = cp->phys.header.savep;
- break;
+ cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data);
+ cp->phys.header.goalp = cp->phys.header.savep;
+ break;
}
cp->phys.header.lastp = cp->phys.header.savep;
@@ -4463,6 +4563,9 @@ int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
** Script processor may be waiting for reselect.
** Wake it up.
*/
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ if (!np->stalling)
+#endif
OUTB (nc_istat, SIGP);
/*
@@ -4530,6 +4633,11 @@ int ncr_reset_bus (Scsi_Cmnd *cmd, int sync_reset)
u_long flags;
int found;
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ if (np->stalling)
+ np->stalling = 0;
+#endif
+
save_flags(flags); cli();
/*
* Return immediately if reset is in progress.
@@ -4607,6 +4715,11 @@ static int ncr_abort_command (Scsi_Cmnd *cmd)
int found;
int retv;
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ if (np->stalling == 2)
+ np->stalling = 0;
+#endif
+
save_flags(flags); cli();
/*
* First, look for the scsi command in the waiting list
@@ -4663,6 +4776,9 @@ static int ncr_abort_command (Scsi_Cmnd *cmd)
** processor will sleep on SEL_WAIT_RESEL.
** Let's wake it up, since it may have to work.
*/
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ if (!np->stalling)
+#endif
OUTB (nc_istat, SIGP);
restore_flags(flags);
@@ -4697,7 +4813,7 @@ static int ncr_detach(ncb_p np, int irq)
** Set release_stage to 1 and wait that ncr_timeout() set it to 2.
*/
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: stopping the timer\n", ncr_name(np));
#endif
np->release_stage = 1;
@@ -4710,7 +4826,7 @@ static int ncr_detach(ncb_p np, int irq)
** Disable chip interrupts
*/
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: disabling chip interrupts\n", ncr_name(np));
#endif
OUTW (nc_sien , 0);
@@ -4720,7 +4836,7 @@ static int ncr_detach(ncb_p np, int irq)
** Free irq
*/
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: freeing irq %d\n", ncr_name(np), irq);
#endif
#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
@@ -4758,17 +4874,17 @@ static int ncr_detach(ncb_p np, int irq)
*/
#ifndef NCR_IOMAPPED
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
#endif
unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
#endif
unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
#endif
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
#endif
release_region(np->port, 128);
@@ -4783,7 +4899,7 @@ static int ncr_detach(ncb_p np, int irq)
printf("%s: shall free an active ccb (host_status=%d)\n",
ncr_name(np), cp->host_status);
}
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp);
#endif
m_free(cp, sizeof(*cp));
@@ -4798,7 +4914,7 @@ static int ncr_detach(ncb_p np, int irq)
for (lun = 0 ; lun < MAX_LUN ; lun++) {
lp = tp->lp[lun];
if (lp) {
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp);
#endif
m_free(lp, sizeof(*lp));
@@ -4851,7 +4967,7 @@ void ncr_complete (ncb_p np, ccb_p cp)
** timestamp
** Optional, spare some CPU time
*/
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
ncb_profile (np, cp);
#endif
@@ -5158,46 +5274,6 @@ void ncr_wakeup (ncb_p np, u_long code)
};
}
-/*===============================================================
-**
-** NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128
-** transfers. 32,64,128 are only supported by 875 and 895 chips.
-** We use log base 2 (burst length) as internal code, with
-** value 0 meaning "burst disabled".
-**
-**===============================================================
-*/
-
-/*
- * Burst length from burst code.
- */
-#define burst_length(bc) (!(bc))? 0 : 1 << (bc)
-
-/*
- * Burst code from io register bits.
- */
-#define burst_code(dmode, ctest4, ctest5) \
- (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
-
-/*
- * Set initial io register bits from burst code.
- */
-static void ncr_init_burst(ncb_p np, u_char bc)
-{
- np->rv_ctest4 &= ~0x80;
- np->rv_dmode &= ~(0x3 << 6);
- np->rv_ctest5 &= ~0x4;
-
- if (!bc) {
- np->rv_ctest4 |= 0x80;
- }
- else {
- --bc;
- np->rv_dmode |= ((bc & 0x3) << 6);
- np->rv_ctest5 |= (bc & 0x4);
- }
-}
-
/*==========================================================
**
**
@@ -5212,7 +5288,6 @@ void ncr_init (ncb_p np, char * msg, u_long code)
int i;
u_long usrsync;
u_char usrwide;
- u_char burst_max;
/*
** Reset chip.
@@ -5236,7 +5311,6 @@ void ncr_init (ncb_p np, char * msg, u_long code)
/*
** Start at first entry.
*/
-
np->squeueput = 0;
np->script0->startpos[0] = NCB_SCRIPTH_PHYS (np, tryloop);
np->script0->start0 [0] = SCR_INT ^ IFFALSE (0);
@@ -5249,161 +5323,30 @@ void ncr_init (ncb_p np, char * msg, u_long code)
/*
** Init chip.
*/
-#if defined SCSI_NCR_TRUST_BIOS_SETTING
- np->rv_dmode = np->sv_dmode;
- np->rv_dcntl = np->sv_dcntl;
- np->rv_ctest3 = np->sv_ctest3;
- np->rv_ctest4 = np->sv_ctest4;
- np->rv_ctest5 = np->sv_ctest5;
- burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
-#else
- np->rv_dmode = 0;
- np->rv_dcntl = 0;
- np->rv_ctest3 = 0;
- np->rv_ctest4 = 0;
- burst_max = driver_setup.burst_max;
- if (burst_max == 255)
- burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
- if (burst_max > 7)
- burst_max = 7;
-
-/** NCR53C810 **/
- if (ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion == 0) {
- burst_max = burst_max < 4 ? burst_max : 4;
- if (driver_setup.special_features)
- np->rv_dmode = ERL; /* read line */
- }
- else
-/** NCR53C815 **/
- if (ChipDevice == PCI_DEVICE_ID_NCR_53C815) {
- burst_max = burst_max < 4 ? burst_max : 4;
- if (driver_setup.special_features)
- np->rv_dmode = BOF | ERL; /* burst opcode fetch, read line */
- }
- else
-/** NCR53C825 **/
- if (ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion == 0) {
- burst_max = burst_max < 4 ? burst_max : 4;
- if (driver_setup.special_features)
- np->rv_dmode = BOF | ERL; /* burst opcode fetch, read line */
- }
- else
-/** NCR53C810A or NCR53C860 **/
- if ((ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion >= 0x10) ||
- ChipDevice == PCI_DEVICE_ID_NCR_53C860) {
- burst_max = burst_max < 4 ? burst_max : 4;
- if (driver_setup.special_features) {
- np->rv_dmode = BOF | ERMP | ERL;
- /* burst op-code fetch, read multiple */
- /* read line */
- np->rv_dcntl = PFEN | CLSE;
- /* prefetch, cache line size */
- np->rv_ctest3 = WRIE; /* write and invalidate */
- }
- }
- else
-/** NCR53C825A or NCR53C875 or NCR53C885 or NCR53C895 or NCR53C896 **/
- if ((ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion >= 0x10) ||
- ChipDevice == PCI_DEVICE_ID_NCR_53C875 ||
- ChipDevice == PCI_DEVICE_ID_NCR_53C885 ||
- ChipDevice == PCI_DEVICE_ID_NCR_53C895 ||
- ChipDevice == PCI_DEVICE_ID_NCR_53C896) {
- if (!driver_setup.special_features)
- burst_max = burst_max < 4 ? burst_max : 4;
- else {
- burst_max = burst_max < 7 ? burst_max : 7;
- np->rv_dmode = BOF | ERMP | ERL;
- /* burst op-code fetch, read multiple */
- /* read line, burst 128 (ctest5&4) */
- np->rv_dcntl = PFEN | CLSE;
- /* prefetch, cache line size */
- np->rv_ctest3 = WRIE; /* write and invalidate */
- np->rv_ctest5 = DFS; /* large dma fifo (0x20) */
- }
- }
-/** OTHERS **/
- else {
- burst_max = burst_max < 4 ? burst_max : 4;
- }
-#endif /* SCSI_NCR_TRUST_BIOS_SETTING */
- /*
- * Prepare initial io register bits for burst length
- */
- ncr_init_burst(np, burst_max);
-
- /*
- ** Set differential mode.
- */
- switch(driver_setup.diff_support) {
- case 3:
- if (INB(nc_gpreg) & 0x08)
- break;
- case 2:
- np->rv_stest2 |= 0x20;
- break;
- case 1:
- np->rv_stest2 |= (np->sv_stest2 & 0x20);
- break;
- default:
- break;
- }
-
- /*
- ** Set irq mode.
- */
- switch(driver_setup.irqm) {
- case 2:
- np->rv_dcntl |= IRQM;
- break;
- case 1:
- np->rv_stest2 |= (np->sv_dcntl & IRQM);
- break;
- default:
- break;
- }
-
- if (bootverbose > 1) {
- printf ("%s: initial value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
- ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
- }
- if (bootverbose > 1) {
- printf ("%s: final value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
- ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
- if (np->rv_stest2 & 0x20)
- printf ("%s: setting up differential mode\n", ncr_name(np));
- }
-
- OUTB (nc_istat, 0x00 ); /* Remove Reset, abort ... */
+ OUTB (nc_istat, 0x00 ); /* Remove Reset, abort */
if (driver_setup.scsi_parity)
- OUTB (nc_scntl0, 0xca ); /* full arb., ena parity, par->ATN */
+ OUTB (nc_scntl0, 0xca); /* full arb., ena parity, par->ATN */
else
- OUTB (nc_scntl0, 0xc0 ); /* full arb., (no parity) */
+ OUTB (nc_scntl0, 0xc0); /* full arb., (no parity) */
- OUTB (nc_scntl1, 0x00 ); /* odd parity, and remove CRST!! */
+ OUTB (nc_scntl1, 0x00); /* odd parity, and remove CRST!! */
- ncr_selectclock(np, np->rv_scntl3);
+ ncr_selectclock(np, np->rv_scntl3); /* Select SCSI clock */
- OUTB (nc_scid , RRE|np->myaddr);/* host adapter SCSI address */
- OUTW (nc_respid, 1ul<<np->myaddr);/* id to respond to */
- OUTB (nc_istat , SIGP ); /* Signal Process */
- OUTB (nc_dmode , np->rv_dmode); /* Burst length = 2 .. 16 transfers */
+ OUTB (nc_scid , RRE|np->myaddr); /* Adapter SCSI address */
+ OUTW (nc_respid, 1ul<<np->myaddr); /* Id to respond to */
+ OUTB (nc_istat , SIGP ); /* Signal Process */
+ OUTB (nc_dmode , np->rv_dmode); /* Burst length, dma mode */
+ OUTB (nc_ctest5, np->rv_ctest5); /* Large fifo + large burst */
- if (driver_setup.special_features && np->rv_ctest5)
- OUTB (nc_ctest5, np->rv_ctest5); /* large fifo + large burst */
+ OUTB (nc_dcntl , NOCOM|np->rv_dcntl); /* Protect SFBR */
+ OUTB (nc_ctest3, np->rv_ctest3); /* Write and invalidate */
+ OUTB (nc_ctest4, np->rv_ctest4); /* Master parity checking */
- OUTB (nc_dcntl , NOCOM|np->rv_dcntl);/* no single step mode, protect SFBR*/
- OUTB (nc_ctest3, np->rv_ctest3); /* write and invalidate */
-
- if (driver_setup.master_parity)
- OUTB (nc_ctest4, MPEE|np->rv_ctest4); /* enable master parity checking */
- else
- OUTB (nc_ctest4, 0x00|np->rv_ctest4); /* disable master parity checking */
-
- OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */
- OUTB (nc_stest3, TE ); /* TolerANT enable */
- OUTB (nc_stime0, 0x0d ); /* HTH = disable STO = 0.4 sec. */
- /* 0.25 sec recommended for scsi 1 */
+ OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */
+ OUTB (nc_stest3, TE); /* TolerANT enable */
+ OUTB (nc_stime0, 0x0d ); /* HTH disabled STO 0.4 sec. */
/*
** Reinitialize usrsync.
@@ -5436,31 +5379,11 @@ void ncr_init (ncb_p np, char * msg, u_long code)
np->disc = 0;
/*
- ** Fill in target structure.
+ ** Enable GPIO0 pin for writing if LED support.
*/
- for (i=0;i<MAX_TARGET;i++) {
- tcb_p tp = &np->target[i];
-
- tp->sval = 0;
- tp->wval = np->rv_scntl3;
-
- tp->usrsync = usrsync;
- tp->usrwide = usrwide;
-
- ncr_negotiate (np, tp);
- }
-
- /*
- ** Enable GPIO0 pin for writing.
- ** Patch the script for LED support.
- */
-
- if (driver_setup.led_pin & (~np->sv_gpcntl) & 0x01) {
+ if (np->features & _F_LED0) {
OUTOFFB (nc_gpcntl, 0x01);
- np->script0->reselect[0] = SCR_REG_REG(gpreg, SCR_OR, 0x01);
- np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
- np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
}
/*
@@ -5480,6 +5403,31 @@ void ncr_init (ncb_p np, char * msg, u_long code)
OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID);
/*
+ ** For 895/6 enable SBMC interrupt and save current SCSI bus mode.
+ */
+ if (np->features & _F_ULTRA2) {
+ OUTONW (nc_sien, SBMC);
+ np->scsi_mode = INB (nc_stest4) & SMODE;
+ }
+
+ /*
+ ** Fill in target structure.
+ ** Prepare sync negotiation according to actual SCSI bus mode.
+ */
+
+ for (i=0;i<MAX_TARGET;i++) {
+ tcb_p tp = &np->target[i];
+
+ tp->sval = 0;
+ tp->wval = np->rv_scntl3;
+
+ tp->usrsync = usrsync;
+ tp->usrwide = usrwide;
+
+ ncr_negotiate (np, tp);
+ }
+
+ /*
** Start script processor.
*/
@@ -5502,14 +5450,12 @@ static void ncr_negotiate (struct ncb* np, struct tcb* tp)
u_long minsync = tp->usrsync;
- if (driver_setup.ultra_scsi >= 2) {
- if (minsync < 10) minsync=10;
- }
- else if (driver_setup.ultra_scsi == 1) {
- if (minsync < 12) minsync=12;
- }
- else {
- if (minsync < 25) minsync=25;
+ /*
+ ** SCSI bus mode limit
+ */
+
+ if (np->scsi_mode && np->scsi_mode == SMODE_SE) {
+ if (minsync < 12) minsync = 12;
}
/*
@@ -5628,7 +5574,7 @@ static int ncr_getsync(ncb_p np, u_char fac, u_char *fakp, u_char *scntl3p)
*fakp = fak - 4;
*scntl3p = ((idiv+1) << 4) + (fac < 25 ? ULTRA : 0);
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printf("fac=%d idiv=%d per=%d fak=%x ", fac, idiv, per, *fakp);
#endif
@@ -5867,7 +5813,7 @@ static void ncr_settags (tcb_p tp, lcb_p lp)
**----------------------------------------------------
*/
-#ifdef SCSI_NCR_USER_COMMAND
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
static void ncr_usercmd (ncb_p np)
{
@@ -5897,7 +5843,7 @@ static void ncr_usercmd (ncb_p np)
break;
case UC_SETDEBUG:
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
ncr_debug = np->user.data;
#endif
break;
@@ -5929,12 +5875,106 @@ static void ncr_usercmd (ncb_p np)
case UC_CLEARPROF:
bzero(&np->profile, sizeof(np->profile));
break;
+#ifdef UC_DEBUG_ERROR_RECOVERY
+ case UC_DEBUG_ERROR_RECOVERY:
+ np->debug_error_recovery = np->user.data;
+ break;
+#endif
}
np->user.cmd=0;
}
#endif
+/*=====================================================================
+**
+** Embedded error recovery debugging code.
+**
+**=====================================================================
+**
+** This code is conditionned by SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT.
+** It only can be enabled after boot-up with a control command.
+**
+** Every 30 seconds the timer handler of the driver decides to
+** change the behaviour of the driver in order to trigger errors.
+**
+** If last command was "debug_error_recovery sge", the driver
+** sets sync offset of all targets that use sync transfers to 2,
+** and so hopes a SCSI gross error at the next read operation.
+**
+** If last command was "debug_error_recovery abort", the driver
+** does not signal new scsi commands to the script processor, until
+** it is asked to abort or reset a command by the mid-level driver.
+**
+** If last command was "debug_error_recovery reset", the driver
+** does not signal new scsi commands to the script processor, until
+** it is asked to reset a command by the mid-level driver.
+**
+** If last command was "debug_error_recovery parity", the driver
+** will assert ATN on the next DATA IN phase mismatch, and so will
+** behave as if a parity error had been detected.
+**
+** The command "debug_error_recovery none" makes the driver behave
+** normaly.
+**
+**=====================================================================
+*/
+
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+static void ncr_trigger_errors (ncb_p np)
+{
+ /*
+ ** If np->debug_error_recovery is not zero, we want to
+ ** simulate common errors in order to test error recovery.
+ */
+ do {
+ static u_long last = 0l;
+
+ if (!np->debug_error_recovery)
+ break;
+ if (!last)
+ last = jiffies;
+ else if (jiffies < last + 30*HZ)
+ break;
+ last = jiffies;
+ /*
+ * This one triggers SCSI gross errors.
+ */
+ if (np->debug_error_recovery == 1) {
+ int i;
+ printf("%s: testing error recovery from SCSI gross error...\n", ncr_name(np));
+ for (i = 0 ; i < MAX_TARGET ; i++) {
+ if (np->target[i].sval & 0x1f) {
+ np->target[i].sval &= ~0x1f;
+ np->target[i].sval += 2;
+ }
+ }
+ }
+ /*
+ * This one triggers abort from the mid-level driver.
+ */
+ else if (np->debug_error_recovery == 2) {
+ printf("%s: testing error recovery from mid-level driver abort()...\n", ncr_name(np));
+ np->stalling = 2;
+ }
+ /*
+ * This one triggers reset from the mid-level driver.
+ */
+ else if (np->debug_error_recovery == 3) {
+ printf("%s: testing error recovery from mid-level driver reset()...\n", ncr_name(np));
+ np->stalling = 3;
+ }
+ /*
+ * This one set ATN on phase mismatch in DATA IN phase and so
+ * will behave as on scsi parity error detected.
+ */
+ else if (np->debug_error_recovery == 4) {
+ printf("%s: testing data in parity error...\n", ncr_name(np));
+ np->assert_atn = 1;
+ }
+ } while (0);
+}
+#endif
/*==========================================================
**
@@ -5977,6 +6017,10 @@ static void ncr_timeout (ncb_p np)
add_timer(&np->timer);
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ ncr_trigger_errors (np);
+#endif
+
/*
** If we are resetting the ncr, wait for settle_time before
** clearing it. Then command processing will be resumed.
@@ -6084,6 +6128,9 @@ static void ncr_timeout (ncb_p np)
*/
ncr_complete (np, cp);
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ if (!np->stalling)
+#endif
OUTB (nc_istat, SIGP);
}
restore_flags(flags);
@@ -6138,6 +6185,7 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
{
u_int32 dsp;
int script_ofs;
+ int script_size;
char *script_name;
u_char *script_base;
int i;
@@ -6146,11 +6194,13 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) {
script_ofs = dsp - np->p_script;
+ script_size = sizeof(struct script);
script_base = (u_char *) np->script;
script_name = "script";
}
else {
script_ofs = dsp - np->p_scripth;
+ script_size = sizeof(struct scripth);
script_base = (u_char *) np->scripth;
script_name = "scripth";
}
@@ -6162,7 +6212,7 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
(unsigned)INL (nc_dbc));
if (((script_ofs & 3) == 0) &&
- (unsigned)script_ofs < sizeof(struct script)) {
+ (unsigned)script_ofs < script_size) {
printf ("%s: script cmd = %08x\n", ncr_name(np),
(int) *(ncrcmd *)(script_base + script_ofs));
}
@@ -6173,13 +6223,36 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
printf (".\n");
}
-/*==========================================================
-**
+/*============================================================
**
** ncr chip exception handler.
**
+**============================================================
**
-**==========================================================
+** In normal cases, interrupt conditions occur one at a
+** time. The ncr is able to stack in some extra registers
+** other interrupts that will occurs after the first one.
+** But severall interrupts may occur at the same time.
+**
+** We probably should only try to deal with the normal
+** case, but it seems that multiple interrupts occur in
+** some cases that are not abnormal at all.
+**
+** The most frequent interrupt condition is Phase Mismatch.
+** We should want to service this interrupt quickly.
+** A SCSI parity error may be delivered at the same time.
+** The SIR interrupt is not very frequent in this driver,
+** since the INTFLY is likely used for command completion
+** signaling.
+** The Selection Timeout interrupt may be triggered with
+** IID and/or UDC.
+** The SBMC interrupt (SCSI Bus Mode Change) may probably
+** occur at any time.
+**
+** This handler try to deal as cleverly as possible with all
+** the above.
+**
+**============================================================
*/
void ncr_exception (ncb_p np)
@@ -6193,14 +6266,23 @@ void ncr_exception (ncb_p np)
*/
while ((istat = INB (nc_istat)) & INTF) {
if (DEBUG_FLAGS & DEBUG_TINY) printf ("F ");
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ if (np->stalling)
+ OUTB (nc_istat, INTF);
+ else
+#endif
OUTB (nc_istat, (istat & SIGP) | INTF);
np->profile.num_fly++;
ncr_wakeup (np, 0);
};
- if (!(istat & (SIP|DIP))) {
+ if (!(istat & (SIP|DIP)))
return;
- }
+
+ np->profile.num_int++;
+
+ if (istat & CABRT)
+ OUTB (nc_istat, CABRT);
/*
** Steinbach's Guideline for Systems Programming:
@@ -6209,7 +6291,6 @@ void ncr_exception (ncb_p np)
sist = (istat & SIP) ? INW (nc_sist) : 0;
dstat = (istat & DIP) ? INB (nc_dstat) : 0;
- np->profile.num_int++;
if (DEBUG_FLAGS & DEBUG_TINY)
printf ("<%d|%x:%x|%x:%x>",
@@ -6217,234 +6298,121 @@ void ncr_exception (ncb_p np)
dstat,sist,
(unsigned)INL(nc_dsp),
(unsigned)INL(nc_dbc));
- if ((dstat==DFE) && (sist==PAR)) return;
-/*==========================================================
-**
-** First the normal cases.
-**
-**==========================================================
-*/
- /*-------------------------------------------
- ** SCSI reset
- **-------------------------------------------
- */
-
- if (sist & RST) {
- ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET);
- return;
- };
-
- /*-------------------------------------------
- ** selection timeout
+ /*========================================================
+ ** First, interrupts we want to service cleanly.
**
- ** IID excluded from dstat mask!
- ** (chip bug)
- **-------------------------------------------
- */
-
- if ((sist & STO) &&
- !(sist & (GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
- !(dstat & (MDPE|BF|ABRT|SIR))) {
- ncr_int_sto (np);
- return;
- };
-
- /*-------------------------------------------
- ** Phase mismatch.
- **-------------------------------------------
- */
-
- if ((sist & MA) &&
- !(sist & (STO|GEN|HTH|SGE|UDC|RST|PAR)) &&
- !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
- ncr_int_ma (np);
+ ** Phase mismatch is the most frequent interrupt, and
+ ** so we have to service it as quickly and as cleanly
+ ** as possible.
+ ** Programmed interrupts are rarely used in this driver,
+ ** but we must handle them cleanly anyway.
+ ** We try to deal with PAR and SBMC combined with
+ ** some other interrupt(s).
+ **=========================================================
+ */
+
+ if (!(sist & (STO|GEN|HTH|SGE|UDC|RST)) &&
+ !(dstat & (MDPE|BF|ABRT|IID))) {
+ if ((sist & SBMC) && ncr_int_sbmc (np))
+ return;
+ if ((sist & PAR) && ncr_int_par (np))
+ return;
+ if (sist & MA) {
+ ncr_int_ma (np);
+ return;
+ }
+ if (dstat & SIR) {
+ ncr_int_sir (np);
+ return;
+ }
+ if (!(sist & (SBMC|PAR)) && !(dstat & SSI))
+ printf("%s: unknown interrupt(s) ignored sist=%x dstat=%x\n",
+ ncr_name(np), sist, dstat);
+ OUTONB (nc_dcntl, (STD|NOCOM));
return;
};
- /*----------------------------------------
- ** move command with length 0
- **----------------------------------------
+ /*========================================================
+ ** Now, interrupts that need some fixing up.
+ ** Order and multiple interrupts is so less important.
+ **
+ ** If SRST has been asserted, we just reset the chip.
+ **
+ ** Selection is intirely handled by the chip. If the
+ ** chip says STO, we trust it. Seems some other
+ ** interrupts may occur at the same time (UDC, IID), so
+ ** we ignore them. In any case we do enough fix-up
+ ** in the service routine.
+ ** We just exclude some fatal dma errors.
+ **=========================================================
*/
- if ((dstat & IID) &&
- !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
- !(dstat & (MDPE|BF|ABRT|SIR)) &&
- ((INL(nc_dbc) & 0xf8000000) == SCR_MOVE_TBL)) {
- /*
- ** Target wants more data than available.
- ** The "no_data" script will do it.
- */
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, no_data));
+ if (sist & RST) {
+ ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET);
return;
};
- /*-------------------------------------------
- ** Programmed interrupt
- **-------------------------------------------
- */
-
- if ((dstat & SIR) &&
- !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
- !(dstat & (MDPE|BF|ABRT|IID)) &&
- (INB(nc_dsps) <= SIR_MAX)) {
- ncr_int_sir (np);
+ if ((sist & STO) &&
+ !(dstat & (MDPE|BF|ABRT))) {
+ ncr_int_sto (np);
return;
};
- /*========================================
- ** do the register dump
- **========================================
+ /*=========================================================
+ ** Now, interrupts we are not able to recover cleanly.
+ ** (At least for the moment).
+ **
+ ** Do the register dump.
+ ** Log message for real hard errors.
+ ** Clear all fifos.
+ ** For MDPE, BF, ABORT, IID, SGE and HTH we reset the
+ ** BUS and the chip.
+ ** We are more soft for UDC.
+ **=========================================================
*/
if (jiffies - np->regtime > 10*HZ) {
- int i;
np->regtime = jiffies;
- for (i=0; i<sizeof(np->regdump); i++)
+ for (i = 0; i<sizeof(np->regdump); i++)
((char*)&np->regdump)[i] = INB_OFF(i);
np->regdump.nc_dstat = dstat;
np->regdump.nc_sist = sist;
};
- /*=========================================
- ** log message for real hard errors
- **=========================================
- */
ncr_log_hard_error(np, sist, dstat);
- /*----------------------------------------
- ** clean up the dma fifo
- **----------------------------------------
- */
-
- if ( (INB(nc_sstat0) & (ILF|ORF|OLF) ) ||
- (INB(nc_sstat1) & (FF3210) ) ||
- (INB(nc_sstat2) & (ILF1|ORF1|OLF1)) || /* wide .. */
- !(dstat & DFE)) {
- printf ("%s: have to clear fifos.\n", ncr_name (np));
- OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */
- OUTONB (nc_ctest3, CLF); /* clear dma fifo */
- }
-
- /*----------------------------------------
- ** handshake timeout
- **----------------------------------------
- */
-
- if (sist & HTH) {
- printf ("%s: handshake timeout\n", ncr_name(np));
- OUTB (nc_scntl1, CRST);
- DELAY (1000);
- OUTB (nc_scntl1, 0x00);
- OUTB (nc_scr0, HS_FAIL);
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
- return;
- }
-
- /*----------------------------------------
- ** unexpected disconnect
- **----------------------------------------
- */
+ printf ("%s: have to clear fifos.\n", ncr_name (np));
+ OUTB (nc_stest3, TE|CSF);
+ OUTONB (nc_ctest3, CLF);
- if ((sist & UDC) &&
- !(sist & (STO|GEN|HTH|MA|SGE|RST|PAR)) &&
- !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
- OUTB (nc_scr0, HS_UNEXPECTED);
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
+ if ((sist & (SGE)) ||
+ (dstat & (MDPE|BF|ABORT|IID))) {
+ ncr_start_reset(np, 2);
return;
};
- /*----------------------------------------
- ** cannot disconnect
- **----------------------------------------
- */
-
- if ((dstat & IID) &&
- !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
- !(dstat & (MDPE|BF|ABRT|SIR)) &&
- ((INL(nc_dbc) & 0xf8000000) == SCR_WAIT_DISC)) {
- /*
- ** Unexpected data cycle while waiting for disconnect.
- ** LDSC and CON bits may help in order to understand
- ** what really happened. Print some info message and let
- ** the reset function reset the BUS and the NCR.
- */
- printf("%s:%d: data cycle while waiting for disconnect, LDSC=%d CON=%d\n",
- ncr_name (np), (int)(INB(nc_ctest0)&0x0f),
- (0!=(INB(nc_sstat2)&LDSC)), (0!=(INB(nc_scntl1)&ISCON)));
- };
-
- /*----------------------------------------
- ** single step
- **----------------------------------------
- */
-
- if ((dstat & SSI) &&
- !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
- !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
- OUTONB (nc_dcntl, (STD|NOCOM));
+ if (sist & HTH) {
+ printf ("%s: handshake timeout\n", ncr_name(np));
+ ncr_start_reset(np, 2);
return;
};
-/*
-** @RECOVER@ HTH, SGE, ABRT.
-**
-** We should try to recover from these interrupts.
-** They may occur if there are problems with synch transfers, or
-** if targets are switched on or off while the driver is running.
-*/
-
- if (sist & SGE) {
- OUTONB (nc_ctest3, CLF); /* clear scsi offsets */
- }
-
- /*
- ** Freeze controller to be able to read the messages.
- */
-
- if (DEBUG_FLAGS & DEBUG_FREEZE) {
- unsigned char val;
- for (i=0; i<0x60; i++) {
- switch (i%16) {
-
- case 0:
- printf ("%s: reg[%d0]: ",
- ncr_name(np),i/16);
- break;
- case 4:
- case 8:
- case 12:
- printf (" ");
- break;
- };
- val = INB_OFF(i);
- printf (" %x%x", val/16, val%16);
- if (i%16==15) printf (".\n");
- }
-
- del_timer(&np->timer);
-
- printf ("%s: halted!\n", ncr_name(np));
- /*
- ** don't restart controller ...
- */
- OUTB (nc_istat, SRST);
+ if (sist & UDC) {
+ printf ("%s: unexpected disconnect\n", ncr_name(np));
+ if (INB (nc_scr1) != 0xff) {
+ OUTB (nc_scr1, HS_UNEXPECTED);
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
+ };
+ ncr_start_reset(np, 2);
return;
};
-#ifdef NCR_FREEZE
- /*
- ** Freeze system to be able to read the messages.
- */
- printf ("ncr: fatal error: system halted - press reset to reboot ...");
- cli();
- for (;;);
-#endif
-
- /*
- ** sorry, have to kill ALL jobs ...
+ /*=========================================================
+ ** We just miss the cause of the interrupt. :(
+ ** Print a message. The timeout will do the real work.
+ **=========================================================
*/
-
- ncr_start_reset(np, 2);
+ printf ("%s: unknown interrupt\n", ncr_name(np));
}
/*==========================================================
@@ -6503,6 +6471,70 @@ void ncr_int_sto (ncb_p np)
/*==========================================================
**
+** ncr chip exception handler for SCSI bus mode change
+**
+**==========================================================
+**
+** I'm not quite sure of what is to be done in such a
+** situation.
+** For now,
+** Reset the bus if some devices use too fast sync transfers.
+** Otherwise, just try to renegotiate sync with targets.
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_int_sbmc (ncb_p np)
+{
+ u_char scsi_mode = INB (nc_stest4) & SMODE;
+ int i;
+ int oversync;
+
+ printf("%s: SCSI bus mode change from %x to %x\n", ncr_name(np),
+ np->scsi_mode, scsi_mode);
+
+ if (scsi_mode == np->scsi_mode)
+ return 0;
+
+ np->scsi_mode = scsi_mode;
+ oversync = 0;
+ for (i = 0; i < MAX_TARGET; i++) {
+ tcb_p tp = &np->target[i];
+
+ if (np->ns_sync < 12 && tp->maxoffs && tp->usrsync < 12) {
+ if (scsi_mode != SMODE_SE)
+ ncr_negotiate(np, tp);
+ else
+ ++oversync;
+ }
+ }
+
+ if (oversync)
+ ncr_start_reset(np, 2);
+
+ return oversync;
+}
+
+/*==========================================================
+**
+** ncr chip exception handler for SCSI parity error.
+**
+**==========================================================
+**
+** SCSI parity errors are handled by the SCSI script.
+** So, we just print some message.
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_int_par (ncb_p np)
+{
+ printf("%s: SCSI parity error detected\n", ncr_name(np));
+ return 0;
+}
+
+/*==========================================================
+**
**
** ncr chip exception handler for phase errors.
**
@@ -6538,22 +6570,18 @@ static void ncr_int_ma (ncb_p np)
/*
** Take into account dma fifo and various buffers and latches,
- ** only if the interrupted phase in an OUTPUT phase.
+ ** only if the interrupted phase was DATA OUT.
*/
- if ((cmd & 1) == 0) {
+ if ((cmd & 7) == 0) {
u_char ctest5, ss0, ss2;
u_short delta;
- if (!(INB(nc_dstat) & DFE)) {
- ctest5 = (np->rv_ctest5 & DFS) ? INB (nc_ctest5) : 0;
- if (ctest5 & DFS)
- delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff;
- else
- delta=(INB (nc_dfifo) - rest) & 0x7f;
- } else {
- delta = 0;
- }
+ ctest5 = (np->rv_ctest5 & DFS) ? INB (nc_ctest5) : 0;
+ if (ctest5 & DFS)
+ delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff;
+ else
+ delta=(INB (nc_dfifo) - rest) & 0x7f;
/*
** The data in the dma fifo has not been transfered to
@@ -6582,9 +6610,10 @@ static void ncr_int_ma (ncb_p np)
} else {
if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
printf ("P%x%x RL=%d ", cmd&7, sbcl&7, rest);
- if (!(INB(nc_dstat) & DFE))
- printf("INPUT phase mismatch with DMA fifo not empty, P%x%x RL=%d\n",
- cmd&7, sbcl&7, rest);
+ if ((cmd & 7) != 1) {
+ OUTONB (nc_ctest3, CLF );
+ OUTB (nc_stest3, TE|CSF);
+ }
}
/*
@@ -6660,7 +6689,7 @@ static void ncr_int_ma (ncb_p np)
};
/*
- ** if old phase not dataphase, leave here.
+ ** check cmd against assumed interrupted script command.
*/
if (cmd != (vdsp[0] >> 24)) {
@@ -6670,6 +6699,18 @@ static void ncr_int_ma (ncb_p np)
return;
}
+
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+ if ((cmd & 7) == 1 && np->assert_atn) {
+ np->assert_atn = 0;
+ OUTONB(nc_socl, CATN);
+ }
+#endif
+
+ /*
+ ** if old phase not dataphase, leave here.
+ */
+
if (cmd & 0x06) {
PRINT_ADDR(cp->cmd);
printf ("phase change %x-%x %d@%08x resid=%d.\n",
@@ -6712,7 +6753,10 @@ static void ncr_int_ma (ncb_p np)
*/
np->profile.num_break++;
OUTL (nc_temp, vtophys (newcmd));
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+ if ((cmd & 7) == 0)
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+ else
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, checkatn));
}
/*==========================================================
@@ -6778,15 +6822,24 @@ void ncr_int_sir (ncb_p np)
}
switch (num) {
+ u_long endp;
case SIR_DATA_IO_IS_OUT:
+ case SIR_DATA_IO_IS_IN:
/*
-** We did not guess the direction of transfer. We assumed DATA IN,
-** but the the target drove DATA OUT.
-** We have to patch the script context with DATA OUT context and
-** restart processing at data out script address.
-*/
- cp->phys.header.savep = NCB_SCRIPTH_PHYS (np, data_out);
- cp->phys.header.goalp = cp->phys.header.savep +20 +cp->segments*16;
+** We did not guess the direction of transfer. We have to wait for
+** actual data direction driven by the target before setting
+** pointers. We must patch the global header too.
+*/
+ if (num == SIR_DATA_IO_IS_OUT) {
+ endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
+ cp->phys.header.goalp = endp + 8;
+ cp->phys.header.savep = endp - cp->segments*16;
+ } else {
+ endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16;
+ cp->phys.header.goalp = endp + 8;
+ cp->phys.header.savep = endp - cp->segments*16;
+ }
+
cp->phys.header.lastp = cp->phys.header.savep;
np->header.savep = cp->phys.header.savep;
np->header.goalp = cp->phys.header.goalp;
@@ -7276,6 +7329,7 @@ void ncr_int_sir (ncb_p np)
(unsigned) np->header.goalp);
break;
+#if 0 /* This stuff does not work */
/*--------------------------------------------------------------------
**
** Processing of a "S_QUEUE_FULL" status.
@@ -7353,6 +7407,7 @@ void ncr_int_sir (ncb_p np)
printf ("%s: queue empty.\n", ncr_name (np));
np->script->start1[0] = SCR_INT ^ IFFALSE (0);
break;
+#endif /* This stuff does not work */
};
out:
@@ -7362,7 +7417,7 @@ out:
/*==========================================================
**
**
-** Acquire a control block
+** Aquire a control block
**
**
**==========================================================
@@ -7496,10 +7551,10 @@ static void ncr_alloc_ccb (ncb_p np, u_long target, u_long lun)
tp->jump_tcb.l_cmd = (SCR_JUMP^IFFALSE (DATA (0x80 + target)));
tp->jump_tcb.l_paddr = np->jump_tcb.l_paddr;
- tp->getscr[0] = SCR_COPY (1);
+ tp->getscr[0] = (np->features & _F_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
tp->getscr[1] = vtophys (&tp->sval);
tp->getscr[2] = np->paddr + offsetof (struct ncr_reg, nc_sxfer);
- tp->getscr[3] = SCR_COPY (1);
+ tp->getscr[3] = (np->features & _F_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
tp->getscr[4] = vtophys (&tp->wval);
tp->getscr[5] = np->paddr + offsetof (struct ncr_reg, nc_scntl3);
@@ -7712,12 +7767,15 @@ static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
int segment = 0;
int use_sg = (int) cmd->use_sg;
+#if 0
bzero (cp->phys.data, sizeof (cp->phys.data));
+#endif
data = cp->phys.data;
cp->data_len = 0;
if (!use_sg) {
if (cmd->request_bufflen) {
+ data = &data[MAX_SCATTER - 1];
data[0].addr = vtophys(cmd->request_buffer);
data[0].size = cmd->request_bufflen;
cp->data_len = data[0].size;
@@ -7727,6 +7785,7 @@ static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
else if (use_sg <= MAX_SCATTER) {
struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
+ data = &data[MAX_SCATTER - use_sg];
while (segment < use_sg) {
data[segment].addr = vtophys(scatter[segment].address);
data[segment].size = scatter[segment].length;
@@ -7753,7 +7812,9 @@ static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
*/
#ifndef NCR_IOMAPPED
+__initfunc(
static int ncr_regtest (struct ncb* np)
+)
{
register volatile u_long data;
/*
@@ -7777,7 +7838,9 @@ static int ncr_regtest (struct ncb* np)
}
#endif
+__initfunc(
static int ncr_snooptest (struct ncb* np)
+)
{
u_long ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc, err=0;
int i;
@@ -7801,6 +7864,7 @@ static int ncr_snooptest (struct ncb* np)
/*
** Start script (exchange values)
*/
+flush_cache_all();
OUTL (nc_dsp, pc);
/*
** Wait 'til done (with timeout)
@@ -7871,7 +7935,7 @@ static int ncr_snooptest (struct ncb* np)
**==========================================================
*/
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
/*
** Compute the difference in jiffies ticks.
@@ -7883,7 +7947,7 @@ static int ncr_snooptest (struct ncb* np)
#define PROFILE cp->phys.header.stamp
static void ncb_profile (ncb_p np, ccb_p cp)
{
- int co, da, st, en, di, se, post,work,disc;
+ int co, st, en, di, se, post,work,disc;
u_long diff;
PROFILE.end = jiffies;
@@ -7891,9 +7955,6 @@ static void ncb_profile (ncb_p np, ccb_p cp)
st = ncr_delta (PROFILE.start,PROFILE.status);
if (st<0) return; /* status not reached */
- da = ncr_delta (PROFILE.start,PROFILE.data);
- if (da<0) return; /* No data transfer phase */
-
co = ncr_delta (PROFILE.start,PROFILE.command);
if (co<0) return; /* command not executed */
@@ -7930,7 +7991,7 @@ static void ncb_profile (ncb_p np, ccb_p cp)
}
#undef PROFILE
-#endif /* SCSI_NCR_PROFILE */
+#endif /* SCSI_NCR_PROFILE_SUPPORT */
/*==========================================================
**
@@ -7991,7 +8052,7 @@ static u_long ncr_lookup(char * id)
/*==========================================================
**
** Determine the ncr's clock frequency.
-** This is important for the negotiation
+** This is essential for the negotiation
** of the synchronous transfer rate.
**
**==========================================================
@@ -7999,20 +8060,53 @@ static u_long ncr_lookup(char * id)
** Note: we have to return the correct value.
** THERE IS NO SAVE DEFAULT VALUE.
**
-** We assume that all NCR based boards are delivered
-** with a 40Mhz clock. Because we have to divide
-** by an integer value greater than 3, only clock
-** frequencies of 40Mhz (/4) or 50MHz (/5) permit
-** the FAST-SCSI rate of 10MHz.
+** Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock.
+** 53C860 and 53C875 rev. 1 support fast20 transfers but
+** do not have a clock doubler and so are provided with a
+** 80 MHz clock. All other fast20 boards incorporate a doubler
+** and so should be delivered with a 40 MHz clock.
+** The future fast40 chips (895/895) use a 40 Mhz base clock
+** and provide a clock quadrupler (160 Mhz). The code below
+** tries to deal as cleverly as possible with all this stuff.
**
**----------------------------------------------------------
*/
/*
+ * Select NCR SCSI clock frequency
+ */
+static void ncr_selectclock(ncb_p np, u_char scntl3)
+{
+ if (np->multiplier < 2) {
+ OUTB(nc_scntl3, scntl3);
+ return;
+ }
+
+ if (bootverbose >= 2)
+ printf ("%s: enabling clock multiplier\n", ncr_name(np));
+
+ OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */
+ if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */
+ int i = 20;
+ while (!(INB(nc_stest4) & LCKFRQ) && --i > 0)
+ DELAY(20);
+ if (!i)
+ printf("%s: the chip cannot lock the frequency\n", ncr_name(np));
+ } else /* Wait 20 micro-seconds for doubler */
+ DELAY(20);
+ OUTB(nc_stest3, HSC); /* Halt the scsi clock */
+ OUTB(nc_scntl3, scntl3);
+ OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */
+ OUTB(nc_stest3, 0x00); /* Restart scsi clock */
+}
+
+
+/*
* calculate NCR SCSI clock frequency (in KHz)
*/
-static unsigned
-ncrgetfreq (ncb_p np, int gen)
+__initfunc(
+static unsigned ncrgetfreq (ncb_p np, int gen)
+)
{
unsigned ms = 0;
@@ -8058,38 +8152,11 @@ ncrgetfreq (ncb_p np, int gen)
}
/*
- * Select NCR SCSI clock frequency
- */
-static void ncr_selectclock(ncb_p np, u_char scntl3)
-{
- if (np->multiplier < 2) {
- OUTB(nc_scntl3, scntl3);
- return;
- }
-
- if (bootverbose >= 2)
- printf ("%s: enabling clock multiplier\n", ncr_name(np));
-
- OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */
- if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */
- int i = 20;
- while (!(INB(nc_stest4) & 0x20) && --i > 0)
- DELAY(20);
- if (!i)
- printf("%s: the chip cannot lock the frequency\n", ncr_name(np));
- } else /* Wait 20 micro-seconds for doubler */
- DELAY(20);
- OUTB(nc_stest3, 0x20); /* Halt the scsi clock */
- OUTB(nc_scntl3, scntl3);
- OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */
- OUTB(nc_stest3, 0x00); /* Restart scsi clock */
-}
-
-
-/*
* Get/probe NCR SCSI clock frequency
*/
+__initfunc(
static void ncr_getclock (ncb_p np, int mult)
+)
{
unsigned char scntl3 = INB(nc_scntl3);
unsigned char stest1 = INB(nc_stest1);
@@ -8151,58 +8218,14 @@ static void ncr_getclock (ncb_p np, int mult)
np->ns_sync = 25;
if (f1 >= 160000) {
- if (driver_setup.ultra_scsi) np->ns_sync = 10;
- np->rv_scntl3 = 7;
+ if (np->features & _F_ULTRA2) np->ns_sync = 10;
+ else if (np->features & _F_ULTRA) np->ns_sync = 12;
}
else if (f1 >= 80000) {
- if (driver_setup.ultra_scsi) np->ns_sync = 12;
- np->rv_scntl3 = 5;
- }
- else {
- np->rv_scntl3 = 3;
- }
-
- if (bootverbose > 1) {
- printf ("%s: initial value of SCNTL3 = %02x, final = %02x\n",
- ncr_name(np), scntl3, np->rv_scntl3);
+ if (np->features & _F_ULTRA) np->ns_sync = 12;
}
}
-/*
-** Save some features set by bios
-**
-** DMODE 0xce
-** 0x02 burst op-code fetch
-** 0x04 enable read multiple
-** 0x08 enable read line
-** 0xc0 burst length 16/8/2
-** DCNTL 0xa8
-** 0x08 totem pole irq
-** 0x20 enable pre-fetch
-** 0x80 enable cache line size
-** CTEST3 0x01
-** 0x01 set write and invalidate
-** CTEST4 0x80
-** 0x80 burst disabled
-** CTEST5 0x24
-** 0x20 large dma fifo (875 and 895 only)
-** 0x04 burst len 32/64/128 (875 and 895 only)
-** GPCNTL general purpose control register
-** STEST2 0x20 differential mode
-*/
-
-static void ncr_save_bios_setting(ncb_p np)
-{
- np->sv_scntl3 = INB(nc_scntl3) & 0x07;
- np->sv_dmode = INB(nc_dmode) & 0xce;
- np->sv_dcntl = INB(nc_dcntl) & 0xa8;
- np->sv_ctest3 = INB(nc_ctest3) & 0x01;
- np->sv_ctest4 = INB(nc_ctest4) & 0x80;
- np->sv_ctest5 = INB(nc_ctest5) & 0x24;
- np->sv_gpcntl = INB(nc_gpcntl);
- np->sv_stest2 = INB(nc_stest2) & 0x20;
-}
-
/*===================== LINUX ENTRY POINTS SECTION ==========================*/
#ifndef uchar
@@ -8224,8 +8247,11 @@ static void ncr_save_bios_setting(ncb_p np)
** ---------------------------------------------------------------------
*/
+__initfunc(
void ncr53c8xx_setup(char *str, int *ints)
+)
{
+#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
char *cur = str;
char *pv;
int val;
@@ -8295,6 +8321,8 @@ void ncr53c8xx_setup(char *str, int *ints)
driver_setup.diff_support= val;
else if (!strncmp(cur, "irqm:", 5))
driver_setup.irqm = val;
+ else if (!strncmp(cur, "pcifix:", 7))
+ driver_setup.pci_fix_up = val;
else if (!strncmp(cur, "safe:", 5) && val)
memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup));
@@ -8302,34 +8330,11 @@ void ncr53c8xx_setup(char *str, int *ints)
if ((cur = strchr(cur, ',')) != NULL)
++cur;
}
+#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
}
-static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, int board, int chip,
- uchar bus, uchar device_fn, int options);
-
-/*
-** NCR53C8XX devices description table
-*/
-
-static struct {
- ushort pci_device_id;
- int chip;
- int max_revision;
- int min_revision;
-} pci_chip_ids[] = {
- {PCI_DEVICE_ID_NCR_53C810, 810, -1, -1},
-/* {PCI_DEVICE_ID_NCR_53C810AP, 810, -1, -1}, */
- {PCI_DEVICE_ID_NCR_53C815, 815, -1, -1},
- {PCI_DEVICE_ID_NCR_53C820, 820, -1, -1},
- {PCI_DEVICE_ID_NCR_53C825, 825, -1, -1},
- {PCI_DEVICE_ID_NCR_53C860, 860, -1, -1},
- {PCI_DEVICE_ID_NCR_53C875, 875, -1, -1},
- {PCI_DEVICE_ID_NCR_53C885, 885, -1, -1},
- {PCI_DEVICE_ID_NCR_53C895, 895, -1, -1},
- {PCI_DEVICE_ID_NCR_53C896, 896, -1, -1}
-};
-
-#define NPCI_CHIP_IDS (sizeof (pci_chip_ids) / sizeof(pci_chip_ids[0]))
+static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit,
+ uchar bus, uchar device_fn);
/*
** Linux entry point for NCR53C8XX devices detection routine.
@@ -8343,16 +8348,12 @@ static struct {
** Returns the number of boards successfully attached.
*/
-int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
+__initfunc(
+static void ncr_print_driver_setup(void)
+)
{
- int i, j;
- int count = 0; /* Number of boards detected */
- uchar pci_bus, pci_device_fn;
- short pci_index; /* Device index to PCI BIOS calls */
-
#define YesNo(y) y ? 'y' : 'n'
- if (bootverbose >= 2) {
- printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
+ printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
YesNo(driver_setup.disconnection),
YesNo(driver_setup.special_features),
YesNo(driver_setup.ultra_scsi),
@@ -8361,7 +8362,7 @@ int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
driver_setup.burst_max,
YesNo(driver_setup.max_wide),
driver_setup.diff_support);
- printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n",
+ printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n",
YesNo(driver_setup.master_parity),
YesNo(driver_setup.scsi_parity),
YesNo(driver_setup.force_sync_nego),
@@ -8370,10 +8371,30 @@ int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
YesNo(driver_setup.led_pin),
driver_setup.settle_delay,
driver_setup.irqm);
- }
#undef YesNo
+}
-#ifdef SCSI_NCR_DEBUG
+/*
+** NCR53C8XX devices description table and chip ids list.
+*/
+
+static ncr_chip ncr_chip_table[] __initdata = SCSI_NCR_CHIP_TABLE;
+static ushort ncr_chip_ids[] __initdata = SCSI_NCR_CHIP_IDS;
+
+__initfunc(
+int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
+)
+{
+ int i, j;
+ int chips;
+ int count = 0;
+ uchar bus, device_fn;
+ short index;
+
+ if (bootverbose >= 2)
+ ncr_print_driver_setup();
+
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
ncr_debug = driver_setup.debug;
#endif
@@ -8384,21 +8405,21 @@ int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
# endif
#endif
- if (pcibios_present()) {
- for (j = 0; j < NPCI_CHIP_IDS; ++j) {
- i = driver_setup.reverse_probe ? NPCI_CHIP_IDS-1 - j : j;
- for (pci_index = 0;
- !pcibios_find_device(PCI_VENDOR_ID_NCR,
- pci_chip_ids[i].pci_device_id, pci_index, &pci_bus,
- &pci_device_fn);
- ++pci_index)
- if (!ncr53c8xx_pci_init(tpnt, count, 0, pci_chip_ids[i].chip,
- pci_bus, pci_device_fn, /* no options */ 0))
- ++count;
- }
- }
+ if (!pcibios_present())
+ return 0;
- return count;
+ chips = sizeof(ncr_chip_ids) / sizeof(ncr_chip_ids[0]);
+ for (j = 0; j < chips ; ++j) {
+ i = driver_setup.reverse_probe ? chips-1 - j : j;
+ for (index = 0; ; index++) {
+ if (pcibios_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i],
+ index, &bus, &device_fn))
+ break;
+ if (!ncr53c8xx_pci_init(tpnt, count, bus, device_fn))
+ ++count;
+ }
+ }
+ return count;
}
@@ -8440,6 +8461,17 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, int board, int
pcibios_strerror(error));
return -1;
}
+#ifdef CONFIG_SNI_RM200_PCI
+ /*
+ * The onboard NCR bypasses the normal PCI interrupt system.
+ */
+ if (mips_machgroup == MACH_GROUP_SNI_RM
+ && mips_machtype == MACH_SNI_RM200_PCI
+ && bus == 0 && device_fn == PCI_DEVFN(0, 1))
+ irq = PCIMT_IRQ_SCSI;
+printk("ncr53c8xx_pci_init() #1: bus == %d, device_fn == %d\n", bus, device_fn);
+#endif
+
if (vendor_id != PCI_VENDOR_ID_NCR) {
printk("ncr53c8xx: not initializing, 0x%04x is not NCR vendor ID\n", (int) vendor_id);
@@ -8527,7 +8559,7 @@ static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_de
device->queue_depth = 1;
#endif
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx_select_queue_depth: id=%d, lun=%d, queue_depth=%d\n",
device->id, device->lun, device->queue_depth);
#endif
@@ -8543,19 +8575,19 @@ printk("ncr53c8xx_select_queue_depth: id=%d, lun=%d, queue_depth=%d\n",
int ncr53c8xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
{
int sts;
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx_queue_command\n");
#endif
if ((sts = ncr_queue_command(cmd, done)) != DID_OK) {
cmd->result = ScsiResult(sts, 0);
done(cmd);
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx : command not queued - result=%d\n", sts);
#endif
return sts;
}
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx : command successfully queued\n");
#endif
return sts;
@@ -8573,8 +8605,14 @@ static void ncr53c8xx_intr(int irq, struct pt_regs * regs)
{
struct Scsi_Host *host;
struct host_data *host_data;
+#if 0
+ u_long flags;
-#ifdef DEBUG
+ save_flags(flags); cli();
+#endif
+
+printk("Yow, an NCR interrupt!\n");
+#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx : interrupt received\n");
#endif
@@ -8583,12 +8621,20 @@ printk("ncr53c8xx : interrupt received\n");
host_data = (struct host_data *) host->hostdata;
#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
# ifdef SCSI_NCR_SHARE_IRQ
- if (dev_id == host_data->ncb)
+ if (dev_id == host_data->ncb) {
+#else
+ if (1) {
# endif
#endif
- ncr_intr(host_data->ncb);
+ if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
+ ncr_exception(host_data->ncb);
+ if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
+ }
}
}
+#if 0
+ restore_flags(flags);
+#endif
}
/*
@@ -8696,7 +8742,7 @@ int ncr53c8xx_abort(Scsi_Cmnd *cmd)
int ncr53c8xx_release(struct Scsi_Host *host)
{
struct host_data *host_data;
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx : release\n");
#endif
@@ -8847,6 +8893,8 @@ static int guess_xfer_direction(int opcode)
**=========================================================================
*/
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
+
#define is_digit(c) ((c) >= '0' && (c) <= '9')
#define digit_to_bin(c) ((c) - '0')
#define is_space(c) ((c) == ' ' || (c) == '\t')
@@ -8928,6 +8976,10 @@ static int ncr_user_command(ncb_p np, char *buffer, int length)
uc->cmd = UC_SETFLAG;
else if ((arg_len = is_keyword(ptr, len, "clearprof")) != 0)
uc->cmd = UC_CLEARPROF;
+#ifdef UC_DEBUG_ERROR_RECOVERY
+ else if ((arg_len = is_keyword(ptr, len, "debug_error_recovery")) != 0)
+ uc->cmd = UC_DEBUG_ERROR_RECOVERY;
+#endif
else
arg_len = 0;
@@ -9028,13 +9080,30 @@ printf("ncr_user_command: data=%ld\n", uc->data);
ptr += arg_len; len -= arg_len;
}
break;
+#ifdef UC_DEBUG_ERROR_RECOVERY
+ case UC_DEBUG_ERROR_RECOVERY:
+ SKIP_SPACES(1);
+ if ((arg_len = is_keyword(ptr, len, "sge")))
+ uc->data = 1;
+ else if ((arg_len = is_keyword(ptr, len, "abort")))
+ uc->data = 2;
+ else if ((arg_len = is_keyword(ptr, len, "reset")))
+ uc->data = 3;
+ else if ((arg_len = is_keyword(ptr, len, "parity")))
+ uc->data = 4;
+ else if ((arg_len = is_keyword(ptr, len, "none")))
+ uc->data = 0;
+ else
+ return -EINVAL;
+ ptr += arg_len; len -= arg_len;
+ break;
+#endif
default:
break;
}
if (len)
return -EINVAL;
-#ifdef SCSI_NCR_USER_COMMAND
else {
long flags;
@@ -9042,10 +9111,13 @@ printf("ncr_user_command: data=%ld\n", uc->data);
ncr_usercmd (np);
restore_flags(flags);
}
-#endif
return length;
}
+#endif /* SCSI_NCR_USER_COMMAND_SUPPORT */
+
+#ifdef SCSI_NCR_USER_INFO_SUPPORT
+
struct info_str
{
char *buffer;
@@ -9104,7 +9176,7 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
info.pos = 0;
copy_info(&info, "General information:\n");
- copy_info(&info, " Chip NCR53C%03d, ", np->chip);
+ copy_info(&info, " Chip NCR53C%s, ", np->chip_name);
copy_info(&info, "device id 0x%x, ", np->device_id);
copy_info(&info, "revision id 0x%x\n", np->revision_id);
@@ -9124,7 +9196,7 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
copy_info(&info, "verbosity level %d\n", driver_setup.verbose);
}
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
copy_info(&info, "Profiling information:\n");
copy_info(&info, " %-12s = %lu\n", "num_trans",np->profile.num_trans);
copy_info(&info, " %-12s = %lu\n", "num_kbytes",np->profile.num_kbytes);
@@ -9141,6 +9213,8 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
return info.pos > info.offset? info.pos - info.offset : 0;
}
+#endif /* SCSI_NCR_USER_INFO_SUPPORT */
+
/*
** Entry point of the scsi proc fs of the driver.
** - func = 0 means read (returns profile data)
@@ -9171,20 +9245,26 @@ printf("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func);
return -EINVAL;
if (func) {
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
retv = ncr_user_command(ncb, buffer, length);
-#ifdef DEBUG_PROC_INFO
-printf("ncr_user_command: retv=%d\n", retv);
+#else
+ retv = -EINVAL;
#endif
}
else {
if (start)
*start = buffer;
+#ifdef SCSI_NCR_USER_INFO_SUPPORT
retv = ncr_host_info(ncb, buffer, offset, length);
+#else
+ retv = -EINVAL;
+#endif
}
return retv;
}
+
/*=========================================================================
** End of proc file system stuff
**=========================================================================
diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
index 3c0c7fb03..412c66a37 100644
--- a/drivers/scsi/ncr53c8xx.h
+++ b/drivers/scsi/ncr53c8xx.h
@@ -45,36 +45,7 @@
/*
** Name and revision of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 1.18f"
-
-/*
-** If SCSI_NCR_SETUP_SPECIAL_FEATURES is defined,
-** the driver enables or not the following features according to chip id
-** revision id:
-** DMODE 0xce
-** 0x02 burst op-code fetch
-** 0x04 enable read multiple
-** 0x08 enable read line
-** 0xc0 burst length 16/8/2
-** DCNTL 0xa0
-** 0x20 enable pre-fetch
-** 0x80 enable cache line size
-** CTEST3 0x01
-** 0x01 set write and invalidate
-** CTEST4 0x80
-** 0x80 burst disabled
-** CTEST5 0x24 (825a and 875 only)
-** 0x04 burst 128
-** 0x80 large dma fifo
-**
-** If SCSI_NCR_TRUST_BIOS_SETTING is defined, the driver will use the
-** initial value of corresponding bit fields, assuming they have been
-** set by the SDMS BIOS.
-** When Linux is booted from another O/S, these assertion is false and
-** the driver will not be able to guess it.
-*/
-
-/*********** LINUX SPECIFIC SECTION ******************/
+#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 2.1b"
/*
** Check supported Linux versions
@@ -97,28 +68,6 @@
#define LINUX_VERSION_CODE LinuxVersionCode(1,2,13)
#endif
-#if !defined(VERSION)
-#define VERSION ((LINUX_VERSION_CODE >> 16) & 0xff)
-#define PATCHLEVEL ((LINUX_VERSION_CODE >> 8) & 0xff)
-#define SUBLEVEL ((LINUX_VERSION_CODE >> 0) & 0xff)
-#endif
-
-#if VERSION == 0 || VERSION > 3
-# error Only Linux version 1 and probable 2 or 3 supported.
-#endif
-
-#if VERSION == 1 && PATCHLEVEL == 2
-# if SUBLEVEL != 13
-# error Only sublevel 13 of Linux 1.2 is supported.
-# endif
-#endif
-
-#if VERSION == 1 && PATCHLEVEL == 3
-# if SUBLEVEL < 45
-# error Only sublevels >=45 of Linux 1.3 are supported.
-# endif
-#endif
-
/*
** Normal IO or memory mapped IO.
**
@@ -139,6 +88,20 @@
# define SCSI_NCR_SHARE_IRQ
#endif
+/*
+** If you want a driver as small as possible, donnot define the
+** following options.
+*/
+
+#define SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+#define SCSI_NCR_DEBUG_INFO_SUPPORT
+#ifdef SCSI_NCR_PROC_INFO_SUPPORT
+# define SCSI_NCR_PROFILE_SUPPORT
+# define SCSI_NCR_USER_COMMAND_SUPPORT
+# define SCSI_NCR_USER_INFO_SUPPORT
+/* # define SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT */
+#endif
+
/* ---------------------------------------------------------------------
** Take into account kernel configured parameters.
** Most of these options can be overridden at startup by a command line.
@@ -208,14 +171,6 @@
#endif
/*
- * Default sync to 0 will force asynchronous at startup
- */
-#ifdef CONFIG_SCSI_FORCE_ASYNCHRONOUS
-#undef SCSI_NCR_SETUP_DEFAULT_SYNC
-#define SCSI_NCR_SETUP_DEFAULT_SYNC (255)
-#endif
-
-/*
* Disallow disconnections at boot-up
*/
#ifdef CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
@@ -291,57 +246,6 @@
#endif
/*
-** Initial setup.
-** Can be overriden at startup by a command line.
-*/
-#define SCSI_NCR_DRIVER_SETUP \
-{ \
- SCSI_NCR_SETUP_MASTER_PARITY, \
- SCSI_NCR_SETUP_SCSI_PARITY, \
- SCSI_NCR_SETUP_DISCONNECTION, \
- SCSI_NCR_SETUP_SPECIAL_FEATURES, \
- SCSI_NCR_SETUP_ULTRA_SCSI, \
- SCSI_NCR_SETUP_FORCE_SYNC_NEGO, \
- 0, \
- 1, \
- SCSI_NCR_SETUP_DEFAULT_TAGS, \
- SCSI_NCR_SETUP_DEFAULT_SYNC, \
- 0x00, \
- 7, \
- SCSI_NCR_SETUP_LED_PIN, \
- 1, \
- SCSI_NCR_SETUP_SETTLE_TIME, \
- SCSI_NCR_SETUP_DIFF_SUPPORT, \
- 0 \
-}
-
-/*
-** Boot fail safe setup.
-** Override initial setup from boot command line:
-** ncr53c8xx=safe:y
-*/
-#define SCSI_NCR_DRIVER_SAFE_SETUP \
-{ \
- 0, \
- 1, \
- 0, \
- 0, \
- 0, \
- 0, \
- 0, \
- 2, \
- 0, \
- 255, \
- 0x00, \
- 255, \
- 0, \
- 0, \
- 10, \
- 1, \
- 1 \
-}
-
-/*
** Define Scsi_Host_Template parameters
**
** Used by hosts.c and ncr53c8xx.c with module configuration.
@@ -399,6 +303,198 @@ int ncr53c8xx_release(struct Scsi_Host *);
#ifndef HOSTS_C
/*
+** NCR53C8XX Device Ids
+*/
+
+#ifndef PCI_DEVICE_ID_NCR_53C810
+#define PCI_DEVICE_ID_NCR_53C810 1
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C810AP
+#define PCI_DEVICE_ID_NCR_53C810AP 5
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C815
+#define PCI_DEVICE_ID_NCR_53C815 4
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C820
+#define PCI_DEVICE_ID_NCR_53C820 2
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C825
+#define PCI_DEVICE_ID_NCR_53C825 3
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C860
+#define PCI_DEVICE_ID_NCR_53C860 6
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C875
+#define PCI_DEVICE_ID_NCR_53C875 0xf
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C875J
+#define PCI_DEVICE_ID_NCR_53C875J 0x8f
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C885
+#define PCI_DEVICE_ID_NCR_53C885 0xd
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C895
+#define PCI_DEVICE_ID_NCR_53C895 0xc
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C896
+#define PCI_DEVICE_ID_NCR_53C896 0xb
+#endif
+
+/*
+** NCR53C8XX devices features table.
+*/
+typedef struct {
+ unsigned short device_id;
+ unsigned short revision_id;
+ char *name;
+ unsigned char burst_max;
+ unsigned char offset_max;
+ unsigned char nr_divisor;
+ unsigned int features;
+#define _F_LED0 (1<<0)
+#define _F_WIDE (1<<1)
+#define _F_ULTRA (1<<2)
+#define _F_ULTRA2 (1<<3)
+#define _F_DBLR (1<<4)
+#define _F_QUAD (1<<5)
+#define _F_ERL (1<<6)
+#define _F_CLSE (1<<7)
+#define _F_WRIE (1<<8)
+#define _F_ERMP (1<<9)
+#define _F_BOF (1<<10)
+#define _F_DFS (1<<11)
+#define _F_PFEN (1<<12)
+#define _F_LDSTR (1<<13)
+#define _F_RAM (1<<14)
+#define _F_CLK80 (1<<15)
+#define _F_CACHE_SET (_F_ERL|_F_CLSE|_F_WRIE|_F_ERMP)
+#define _F_SCSI_SET (_F_WIDE|_F_ULTRA|_F_ULTRA2|_F_DBLR|_F_QUAD|F_CLK80)
+#define _F_SPECIAL_SET (_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM)
+} ncr_chip;
+
+#define SCSI_NCR_CHIP_TABLE \
+{ \
+ {PCI_DEVICE_ID_NCR_53C810, 0x0f, "810", 4, 8, 4, \
+ _F_ERL} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C810, 0xff, "810a", 4, 8, 4, \
+ _F_CACHE_SET|_F_LDSTR|_F_PFEN|_F_BOF} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C815, 0xff, "815", 4, 8, 4, \
+ _F_ERL|_F_BOF} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C820, 0xff, "820", 4, 8, 4, \
+ _F_WIDE|_F_ERL} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C825, 0x0f, "825", 4, 8, 4, \
+ _F_WIDE|_F_ERL|_F_BOF} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 7, 8, 4, \
+ _F_WIDE|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C860, 0xff, "860", 4, 8, 5, \
+ _F_WIDE|_F_ULTRA|_F_CLK80|_F_CACHE_SET|_F_BOF|_F_LDSTR|_F_PFEN|_F_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C875, 0x01, "875", 7, 16, 5, \
+ _F_WIDE|_F_ULTRA|_F_CLK80|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C875, 0xff, "875", 7, 16, 5, \
+ _F_WIDE|_F_ULTRA|_F_DBLR|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C875J, 0xff, "875J", 7, 16, 5, \
+ _F_WIDE|_F_ULTRA|_F_DBLR|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C885, 0xff, "885", 7, 16, 5, \
+ _F_WIDE|_F_ULTRA|_F_DBLR|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C895, 0xff, "895", 7, 31, 7, \
+ _F_WIDE|_F_ULTRA|_F_ULTRA2|_F_QUAD|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 7, 31, 7, \
+ _F_WIDE|_F_ULTRA|_F_ULTRA2|_F_QUAD|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+}
+
+/*
+ * List of supported NCR chip ids
+ */
+#define SCSI_NCR_CHIP_IDS \
+{ \
+ PCI_DEVICE_ID_NCR_53C810, \
+ PCI_DEVICE_ID_NCR_53C815, \
+ PCI_DEVICE_ID_NCR_53C820, \
+ PCI_DEVICE_ID_NCR_53C825, \
+ PCI_DEVICE_ID_NCR_53C860, \
+ PCI_DEVICE_ID_NCR_53C875, \
+ PCI_DEVICE_ID_NCR_53C875J, \
+ PCI_DEVICE_ID_NCR_53C885, \
+ PCI_DEVICE_ID_NCR_53C895, \
+ PCI_DEVICE_ID_NCR_53C896 \
+}
+
+/*
+** Initial setup.
+** Can be overriden at startup by a command line.
+*/
+#define SCSI_NCR_DRIVER_SETUP \
+{ \
+ SCSI_NCR_SETUP_MASTER_PARITY, \
+ SCSI_NCR_SETUP_SCSI_PARITY, \
+ SCSI_NCR_SETUP_DISCONNECTION, \
+ SCSI_NCR_SETUP_SPECIAL_FEATURES, \
+ SCSI_NCR_SETUP_ULTRA_SCSI, \
+ SCSI_NCR_SETUP_FORCE_SYNC_NEGO, \
+ 0, \
+ 0, \
+ 1, \
+ SCSI_NCR_SETUP_DEFAULT_TAGS, \
+ SCSI_NCR_SETUP_DEFAULT_SYNC, \
+ 0x00, \
+ 7, \
+ SCSI_NCR_SETUP_LED_PIN, \
+ 1, \
+ SCSI_NCR_SETUP_SETTLE_TIME, \
+ SCSI_NCR_SETUP_DIFF_SUPPORT, \
+ 0 \
+}
+
+/*
+** Boot fail safe setup.
+** Override initial setup from boot command line:
+** ncr53c8xx=safe:y
+*/
+#define SCSI_NCR_DRIVER_SAFE_SETUP \
+{ \
+ 0, \
+ 1, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 2, \
+ 0, \
+ 255, \
+ 0x00, \
+ 255, \
+ 0, \
+ 0, \
+ 10, \
+ 1, \
+ 1 \
+}
+
+/*
** Define the table of target capabilities by host and target
**
** If you have problems with a scsi device, note the host unit and the
@@ -486,50 +582,6 @@ int ncr53c8xx_release(struct Scsi_Host *);
#endif
#endif
-/*
-** NCR53C8XX Device Ids
-*/
-
-#ifndef PCI_DEVICE_ID_NCR_53C810
-#define PCI_DEVICE_ID_NCR_53C810 1
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C810AP
-#define PCI_DEVICE_ID_NCR_53C810AP 5
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C815
-#define PCI_DEVICE_ID_NCR_53C815 4
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C820
-#define PCI_DEVICE_ID_NCR_53C820 2
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C825
-#define PCI_DEVICE_ID_NCR_53C825 3
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C860
-#define PCI_DEVICE_ID_NCR_53C860 6
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C875
-#define PCI_DEVICE_ID_NCR_53C875 0xf
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C885
-#define PCI_DEVICE_ID_NCR_53C885 0xd
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C895
-#define PCI_DEVICE_ID_NCR_53C895 0xc
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C896
-#define PCI_DEVICE_ID_NCR_53C896 0xb
-#endif
-
/**************** ORIGINAL CONTENT of ncrreg.h from FreeBSD ******************/
/*-----------------------------------------------------------------
@@ -608,6 +660,7 @@ struct ncr_reg {
#define ILF1 0x80 /* sta: data in SIDL register msb[W]*/
#define ORF1 0x40 /* sta: data in SODR register msb[W]*/
#define OLF1 0x20 /* sta: data in SODL register msb[W]*/
+ #define DM 0x04 /* sta: DIFFSENS mismatch (895/6 only) */
#define LDSC 0x02 /* sta: disconnect & reconnect */
/*10*/ u_int32 nc_dsa; /* --> Base page */
@@ -680,6 +733,7 @@ struct ncr_reg {
/*40*/ u_short nc_sien; /* -->: interrupt enable */
/*42*/ u_short nc_sist; /* <--: interrupt status */
+ #define SBMC 0x1000/* sta: SCSI Bus Mode Change (895/6 only) */
#define STO 0x0400/* sta: timeout (select) */
#define GEN 0x0200/* sta: timeout (general) */
#define HTH 0x0100/* sta: timeout (handshake) */
@@ -713,10 +767,17 @@ struct ncr_reg {
/*4f*/ u_char nc_stest3;
#define TE 0x80 /* c: tolerAnt enable */
+ #define HSC 0x20 /* c: Halt SCSI Clock */
#define CSF 0x02 /* c: clear scsi fifo */
/*50*/ u_short nc_sidl; /* Lowlevel: latched from scsi data */
/*52*/ u_char nc_stest4;
+ #define SMODE 0xc0 /* SCSI bus mode (895/6 only) */
+ #define SMODE_HVD 0x40 /* High Voltage Differential */
+ #define SMODE_SE 0x80 /* Single Ended */
+ #define SMODE_LVD 0xc0 /* Low Voltage Differential */
+ #define LCKFRQ 0x20 /* Frequency Lock (895/6 only) */
+
/*53*/ u_char nc_53_;
/*54*/ u_short nc_sodl; /* Lowlevel: data out to scsi data */
/*56*/ u_short nc_56_;
@@ -870,10 +931,18 @@ struct scr_tblsel {
** << source_address >>
** << destination_address >>
**
+** SCR_COPY sets the NO FLUSH option by default.
+** SCR_COPY_F does not set this option.
+**
+** For chips which do not support this option,
+** ncr_copy_and_bind() will remove this bit.
**-----------------------------------------------------------
*/
-#define SCR_COPY(n) (0xc0000000 | (n))
+#define SCR_NO_FLUSH 0x01000000
+
+#define SCR_COPY(n) (0xc0000000 | SCR_NO_FLUSH | (n))
+#define SCR_COPY_F(n) (0xc0000000 | (n))
/*-----------------------------------------------------------
**
@@ -979,6 +1048,7 @@ struct scr_tblsel {
**-----------------------------------------------------------
*/
+#define SCR_NO_OP 0x80000000
#define SCR_JUMP 0x80080000
#define SCR_JUMPR 0x80880000
#define SCR_CALL 0x88080000
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 54658955f..e9d80501f 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -8,6 +8,8 @@
* An even bigger kudos to John Grana at Performance Technologies
* for providing me with the hardware to write this driver, you rule
* John you really do.
+ *
+ * May, 2, 1997: Added support for QLGC,isp --jj
*/
#include <linux/kernel.h>
@@ -573,6 +575,7 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
unsigned char bsizes, bsizes_more;
int nqptis = 0, nqptis_in_use = 0;
int qpti_node;
+ int is_pti;
tpnt->proc_dir = &proc_scsi_qlogicpti;
qptichain = 0;
@@ -584,7 +587,8 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
/* Is this a red snapper? */
if(strcmp(qpti_dev->prom_name, "ptisp") &&
- strcmp(qpti_dev->prom_name, "PTI,ptisp"))
+ strcmp(qpti_dev->prom_name, "PTI,ptisp") &&
+ strcmp(qpti_dev->prom_name, "QLGC,isp"))
continue;
/* Yep, register and allocate software state. */
@@ -618,6 +622,8 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
prom_getstring(qpti_node, "name", qpti->prom_name,
sizeof(qpti->prom_name));
qpti->prom_node = qpti_node;
+
+ is_pti = strcmp (qpti->prom_name, "QLGC,isp");
/* Setup the reg property for this device. */
prom_apply_sbus_ranges(qpti->qdev->my_bus,
@@ -632,17 +638,19 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
qpti->qdev->reg_addrs[0].which_io, 0x0);
if(!qregs)
panic("PTI Qlogic/ISP registers unmappable");
-
- /* Map this one read only. */
- qpti->sreg = sreg = (volatile unsigned char *)
- sparc_alloc_io((qpti->qdev->reg_addrs[0].phys_addr +
- (16 * PAGE_SIZE)), 0,
- sizeof(unsigned char),
- "PTI Qlogic/ISP Status Reg",
- qpti->qdev->reg_addrs[0].which_io, 1);
- if(!sreg)
- panic("PTI Qlogic/ISP status reg unmappable");
- qpti->swsreg = 0;
+
+ if(is_pti) {
+ /* Map this one read only. */
+ qpti->sreg = sreg = (volatile unsigned char *)
+ sparc_alloc_io((qpti->qdev->reg_addrs[0].phys_addr +
+ (16 * PAGE_SIZE)), 0,
+ sizeof(unsigned char),
+ "PTI Qlogic/ISP Status Reg",
+ qpti->qdev->reg_addrs[0].which_io, 1);
+ if(!sreg)
+ panic("PTI Qlogic/ISP status reg unmappable");
+ qpti->swsreg = 0;
+ }
qpti_host->base = (unsigned char *)qregs;
qpti_host->io_port = (unsigned int) qregs;
@@ -713,21 +721,32 @@ qpti_irq_acquired:
/* Set adapter and per-device default values. */
qlogicpti_set_hostdev_defaults(qpti);
-
- /* Load the firmware. */
- if(qlogicpti_load_firmware(qpti))
- panic("PTI Qlogic/ISP firmware load failed");
-
- /* Check the PTI status reg. */
- if(qlogicpti_verify_tmon(qpti))
- panic("PTI Qlogic/ISP tmon verification failed");
+
+ if (is_pti) {
+ /* Load the firmware. */
+ if(qlogicpti_load_firmware(qpti))
+ panic("PTI Qlogic/ISP firmware load failed");
+
+ /* Check the PTI status reg. */
+ if(qlogicpti_verify_tmon(qpti))
+ panic("PTI Qlogic/ISP tmon verification failed");
+ }
/* Reset the ISP and init res/req queues. */
if(qlogicpti_reset_hardware(qpti_host))
panic("PTI Qlogic/ISP cannot be reset");
- printk("(Firmware v%d.%d) [%s Wide, using %s interface]\n",
- qpti->fware_majrev, qpti->fware_minrev,
+ if (is_pti) {
+ printk("(Firmware v%d.%d)",
+ qpti->fware_majrev, qpti->fware_minrev);
+ } else {
+ char buffer[60];
+
+ prom_getstring (qpti_node, "isp-fcode", buffer, 60);
+ printk("(Firmware %s)", buffer);
+ }
+
+ printk (" [%s Wide, using %s interface]\n",
(qpti->ultra ? "Ultra" : "Fast"),
(qpti->differential ? "differential" : "single ended"));
@@ -751,7 +770,9 @@ int qlogicpti_release(struct Scsi_Host *host)
/* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
free_irq(host->irq, NULL);
unmapioaddr((unsigned long)qregs);
- unmapioaddr((unsigned long)qpti->sreg);
+ /* QLGC,isp doesn't have status reg */
+ if (strcmp (qpti->prom_name, "QLGC,isp"))
+ unmapioaddr((unsigned long)qpti->sreg);
return 0;
}
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
index 4f9fdad07..c447f8658 100644
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -218,7 +218,13 @@ extern int scsi_dev_init (void);
#include <asm/scatterlist.h>
+#ifdef __mc68000__
+#include <asm/pgtable.h>
+#define CONTIGUOUS_BUFFERS(X,Y) \
+ (VTOP((X)->b_data+(X)->b_size-1)+1 == VTOP((Y)->b_data))
+#else
#define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data)
+#endif
/*
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index aca31e7c7..83c21c20b 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -11,6 +11,9 @@
*
* generic command parser provided by:
* Andreas Heilwagen <crashcar@informatik.uni-koblenz.de>
+ *
+ * generic_proc_info() support of xxxx_info() by:
+ * Michael A. Griffith <grif@acm.org>
*/
/*
@@ -48,7 +51,9 @@ struct scsi_dir {
* Used if the driver currently has no own support for /proc/scsi
*/
int generic_proc_info(char *buffer, char **start, off_t offset,
- int length, int inode, int inout)
+ int length, int inode, int inout,
+ const char *(*info)(struct Scsi_Host *),
+ struct Scsi_Host *sh)
{
int len, pos, begin;
@@ -56,8 +61,13 @@ int generic_proc_info(char *buffer, char **start, off_t offset,
return(-ENOSYS); /* This is a no-op */
begin = 0;
- pos = len = sprintf(buffer,
- "The driver does not yet support the proc-fs\n");
+ if (info && sh) {
+ pos = len = sprintf(buffer, "%s\n", info(sh));
+ }
+ else {
+ pos = len = sprintf(buffer,
+ "The driver does not yet support the proc-fs\n");
+ }
if(pos < offset) {
len = 0;
begin = pos;
@@ -91,7 +101,9 @@ extern int dispatch_scsi_info(int ino, char *buffer, char **start,
if (ino == (hpnt->host_no + PROC_SCSI_FILE)) {
if(hpnt->hostt->proc_info == NULL)
return generic_proc_info(buffer, start, offset, length,
- hpnt->host_no, func);
+ hpnt->host_no, func,
+ hpnt->hostt->info,
+ hpnt);
else
return(hpnt->hostt->proc_info(buffer, start, offset,
length, hpnt->host_no, func));
diff --git a/drivers/scsi/scsiiom.c b/drivers/scsi/scsiiom.c
new file mode 100644
index 000000000..97801d755
--- /dev/null
+++ b/drivers/scsi/scsiiom.c
@@ -0,0 +1,1540 @@
+/***********************************************************************
+ * FILE NAME : SCSIIOM.C *
+ * BY : C.L. Huang, ching@tekram.com.tw *
+ * Description: Device Driver for Tekram DC-390 (T) PCI SCSI *
+ * Bus Master Host Adapter *
+ ***********************************************************************/
+
+
+static USHORT
+DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
+{
+ USHORT ioport, rc;
+ UCHAR bval, bval1, i, cnt;
+ PUCHAR ptr;
+ ULONG wlval;
+
+ pSRB->TagNumber = 31;
+ ioport = pACB->IOPortBase;
+ bval = pDCB->UnitSCSIID;
+ outb(bval,ioport+Scsi_Dest_ID);
+ bval = pDCB->SyncPeriod;
+ outb(bval,ioport+Sync_Period);
+ bval = pDCB->SyncOffset;
+ outb(bval,ioport+Sync_Offset);
+ bval = pDCB->CtrlR1;
+ outb(bval,ioport+CtrlReg1);
+ bval = pDCB->CtrlR3;
+ outb(bval,ioport+CtrlReg3);
+ bval = pDCB->CtrlR4;
+ outb(bval,ioport+CtrlReg4);
+ bval = CLEAR_FIFO_CMD; /* Flush FIFO */
+ outb(bval,ioport+ScsiCmd);
+
+ pSRB->ScsiPhase = SCSI_NOP0;
+ bval = pDCB->IdentifyMsg;
+ if( !(pDCB->SyncMode & EN_ATN_STOP) )
+ {
+ if( (pSRB->CmdBlock[0] == INQUIRY) ||
+ (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+ (pSRB->SRBFlag & AUTO_REQSENSE) )
+ {
+ bval &= 0xBF; /* NO disconnection */
+ outb(bval,ioport+ScsiFifo);
+ bval1 = SELECT_W_ATN;
+ pSRB->SRBState = SRB_START_;
+ if( pDCB->SyncMode & SYNC_ENABLE )
+ {
+ if( !(pDCB->IdentifyMsg & 7) ||
+ (pSRB->CmdBlock[0] != INQUIRY) )
+ {
+ bval1 = SEL_W_ATN_STOP;
+ pSRB->SRBState = SRB_MSGOUT;
+ }
+ }
+ }
+ else
+ {
+ if(pDCB->SyncMode & EN_TAG_QUEUING)
+ {
+ outb(bval,ioport+ScsiFifo);
+ bval = MSG_SIMPLE_QTAG;
+ outb(bval,ioport+ScsiFifo);
+ wlval = 1;
+ bval = 0;
+ while( wlval & pDCB->TagMask )
+ {
+ wlval = wlval << 1;
+ bval++;
+ }
+ outb(bval,ioport+ScsiFifo);
+ pDCB->TagMask |= wlval;
+ pSRB->TagNumber = bval;
+ bval1 = SEL_W_ATN2;
+ pSRB->SRBState = SRB_START_;
+ }
+ else
+ {
+ outb(bval,ioport+ScsiFifo);
+ bval1 = SELECT_W_ATN;
+ pSRB->SRBState = SRB_START_;
+ }
+ }
+
+ if( pSRB->SRBFlag & AUTO_REQSENSE )
+ {
+ bval = REQUEST_SENSE;
+ outb(bval,ioport+ScsiFifo);
+ bval = pDCB->IdentifyMsg << 5;
+ outb(bval,ioport+ScsiFifo);
+ bval = 0;
+ outb(bval,ioport+ScsiFifo);
+ outb(bval,ioport+ScsiFifo);
+ bval = sizeof(pSRB->pcmd->sense_buffer);
+ outb(bval,ioport+ScsiFifo);
+ bval = 0;
+ outb(bval,ioport+ScsiFifo);
+ }
+ else
+ {
+ cnt = pSRB->ScsiCmdLen;
+ ptr = (PUCHAR) pSRB->CmdBlock;
+ for(i=0; i<cnt; i++)
+ {
+ bval = *ptr++;
+ outb(bval,ioport+ScsiFifo);
+ }
+ }
+ }
+ else /* ATN_STOP */
+ {
+ if( (pSRB->CmdBlock[0] == INQUIRY) ||
+ (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+ (pSRB->SRBFlag & AUTO_REQSENSE) )
+ {
+ bval &= 0xBF;
+ outb(bval,ioport+ScsiFifo);
+ bval1 = SELECT_W_ATN;
+ pSRB->SRBState = SRB_START_;
+ if( pDCB->SyncMode & SYNC_ENABLE )
+ {
+ if( !(pDCB->IdentifyMsg & 7) ||
+ (pSRB->CmdBlock[0] != INQUIRY) )
+ {
+ bval1 = SEL_W_ATN_STOP;
+ pSRB->SRBState = SRB_MSGOUT;
+ }
+ }
+ }
+ else
+ {
+ if(pDCB->SyncMode & EN_TAG_QUEUING)
+ {
+ outb(bval,ioport+ScsiFifo);
+ pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG;
+ wlval = 1;
+ bval = 0;
+ while( wlval & pDCB->TagMask )
+ {
+ wlval = wlval << 1;
+ bval++;
+ }
+ pDCB->TagMask |= wlval;
+ pSRB->TagNumber = bval;
+ pSRB->MsgOutBuf[1] = bval;
+ pSRB->MsgCnt = 2;
+ bval1 = SEL_W_ATN_STOP;
+ pSRB->SRBState = SRB_START_;
+ }
+ else
+ {
+ outb(bval,ioport+ScsiFifo);
+ pSRB->MsgOutBuf[0] = MSG_NOP;
+ pSRB->MsgCnt = 1;
+ pSRB->SRBState = SRB_START_;
+ bval1 = SEL_W_ATN_STOP;
+ }
+ }
+ }
+ bval = inb( ioport+Scsi_Status );
+ if( bval & INTERRUPT )
+ {
+ pSRB->SRBState = SRB_READY;
+ pDCB->TagMask &= ~( 1 << pSRB->TagNumber );
+ rc = 1;
+ }
+ else
+ {
+ pSRB->ScsiPhase = SCSI_NOP1;
+ pACB->pActiveDCB = pDCB;
+ pDCB->pActiveSRB = pSRB;
+ rc = 0;
+ outb(bval1,ioport+ScsiCmd);
+ }
+ return( rc );
+}
+
+
+#ifndef VERSION_ELF_1_2_13
+static void
+DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
+#else
+static void
+DC390_Interrupt( int irq, struct pt_regs *regs)
+#endif
+{
+ PACB pACB;
+ PDCB pDCB;
+ PSRB pSRB;
+ USHORT ioport = 0;
+ USHORT phase, i;
+ void (*stateV)( PACB, PSRB, PUCHAR );
+ UCHAR istate = 0;
+ UCHAR sstatus=0, istatus;
+
+ pACB = pACB_start;
+ if( pACB == NULL )
+ return;
+ for( i=0; i < adapterCnt; i++ )
+ {
+ if( pACB->IRQLevel == (UCHAR) irq )
+ {
+ ioport = pACB->IOPortBase;
+ sstatus = inb( ioport+Scsi_Status );
+ if( sstatus & INTERRUPT )
+ break;
+ else
+ pACB = pACB->pNextACB;
+ }
+ else
+ {
+ pACB = pACB->pNextACB;
+ }
+ }
+
+#ifdef DC390_DEBUG1
+ printk("sstatus=%2x,",sstatus);
+#endif
+
+ if( pACB == (PACB )-1 )
+ {
+ printk("DC390: Spurious interrupt detected!\n");
+ return;
+ }
+
+ istate = inb( ioport+Intern_State );
+ istatus = inb( ioport+INT_Status );
+
+#ifdef DC390_DEBUG1
+ printk("Istatus=%2x,",istatus);
+#endif
+
+ if(istatus & DISCONNECTED)
+ {
+ DC390_Disconnect( pACB );
+ return;
+ }
+
+ if(istatus & RESELECTED)
+ {
+ DC390_Reselect( pACB );
+ return;
+ }
+
+ if(istatus & INVALID_CMD)
+ {
+ DC390_InvalidCmd( pACB );
+ return;
+ }
+
+ if(istatus & SCSI_RESET)
+ {
+ DC390_ScsiRstDetect( pACB );
+ return;
+ }
+
+ if( istatus & (SUCCESSFUL_OP+SERVICE_REQUEST) )
+ {
+ pDCB = pACB->pActiveDCB;
+ pSRB = pDCB->pActiveSRB;
+ if( pDCB )
+ {
+ if( pDCB->DCBFlag & ABORT_DEV_ )
+ EnableMsgOut( pACB, pSRB );
+ }
+
+ phase = (USHORT) pSRB->ScsiPhase;
+ stateV = (void *) DC390_phase0[phase];
+ stateV( pACB, pSRB, &sstatus );
+
+ pSRB->ScsiPhase = sstatus & 7;
+ phase = (USHORT) sstatus & 7;
+ stateV = (void *) DC390_phase1[phase];
+ stateV( pACB, pSRB, &sstatus );
+ }
+}
+
+
+static void
+DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR sstatus, bval;
+ USHORT ioport;
+ PSGL psgl;
+ ULONG ResidCnt, xferCnt;
+
+ ioport = pACB->IOPortBase;
+ sstatus = *psstatus;
+
+ if( !(pSRB->SRBState & SRB_XFERPAD) )
+ {
+ if( sstatus & PARITY_ERR )
+ pSRB->SRBStatus |= PARITY_ERROR;
+
+ if( sstatus & COUNT_2_ZERO )
+ {
+ bval = inb(ioport+DMA_Status);
+ while( !(bval & DMA_XFER_DONE) )
+ bval = inb(ioport+DMA_Status);
+ pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
+ pSRB->SGIndex++;
+ if( pSRB->SGIndex < pSRB->SGcount )
+ {
+ pSRB->pSegmentList++;
+ psgl = pSRB->pSegmentList;
+
+#ifndef VERSION_ELF_1_2_13
+ pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+#else
+ pSRB->SGPhysAddr = (ULONG) psgl->address;
+#endif
+ pSRB->SGToBeXferLen = (ULONG) psgl->length;
+ }
+ else
+ pSRB->SGToBeXferLen = 0;
+ }
+ else
+ {
+ bval = inb( ioport+Current_Fifo );
+ bval &= 0x1f;
+ ResidCnt = (ULONG) inb(ioport+CtcReg_High);
+ ResidCnt = ResidCnt << 8;
+ ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
+ ResidCnt = ResidCnt << 8;
+ ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
+ ResidCnt += (ULONG) bval;
+
+ xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+ pSRB->SGPhysAddr += xferCnt;
+ pSRB->TotalXferredLen += xferCnt;
+ pSRB->SGToBeXferLen = ResidCnt;
+ }
+ }
+ bval = WRITE_DIRECTION+DMA_IDLE_CMD;
+ outb( bval, ioport+DMA_Cmd);
+}
+
+static void
+DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR sstatus, bval;
+ USHORT i, ioport, residual;
+ PSGL psgl;
+ ULONG ResidCnt, xferCnt;
+ PUCHAR ptr;
+
+
+ ioport = pACB->IOPortBase;
+ sstatus = *psstatus;
+
+ if( !(pSRB->SRBState & SRB_XFERPAD) )
+ {
+ if( sstatus & PARITY_ERR )
+ pSRB->SRBStatus |= PARITY_ERROR;
+
+ if( sstatus & COUNT_2_ZERO )
+ {
+ bval = inb(ioport+DMA_Status);
+ while( !(bval & DMA_XFER_DONE) )
+ bval = inb(ioport+DMA_Status);
+
+ bval = READ_DIRECTION+DMA_IDLE_CMD;
+ outb( bval, ioport+DMA_Cmd);
+
+ pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
+ pSRB->SGIndex++;
+ if( pSRB->SGIndex < pSRB->SGcount )
+ {
+ pSRB->pSegmentList++;
+ psgl = pSRB->pSegmentList;
+
+#ifndef VERSION_ELF_1_2_13
+ pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+#else
+ pSRB->SGPhysAddr = (ULONG) psgl->address;
+#endif
+ pSRB->SGToBeXferLen = (ULONG) psgl->length;
+ }
+ else
+ pSRB->SGToBeXferLen = 0;
+ }
+ else /* phase changed */
+ {
+ residual = 0;
+ bval = inb(ioport+Current_Fifo);
+ while( bval & 0x1f )
+ {
+ if( (bval & 0x1f) == 1 )
+ {
+ for(i=0; i< 0x100; i++)
+ {
+ bval = inb(ioport+Current_Fifo);
+ if( !(bval & 0x1f) )
+ goto din_1;
+ else if( i == 0x0ff )
+ {
+ residual = 1; /* ;1 residual byte */
+ goto din_1;
+ }
+ }
+ }
+ else
+ bval = inb(ioport+Current_Fifo);
+ }
+din_1:
+ bval = READ_DIRECTION+DMA_BLAST_CMD;
+ outb(bval, ioport+DMA_Cmd);
+ for(i=0; i<0x8000; i++)
+ {
+ bval = inb(ioport+DMA_Status);
+ if(bval & BLAST_COMPLETE)
+ break;
+ }
+ bval = READ_DIRECTION+DMA_IDLE_CMD;
+ outb(bval, ioport+DMA_Cmd);
+
+ ResidCnt = (ULONG) inb(ioport+CtcReg_High);
+ ResidCnt = ResidCnt << 8;
+ ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
+ ResidCnt = ResidCnt << 8;
+ ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
+
+ xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+ pSRB->SGPhysAddr += xferCnt;
+ pSRB->TotalXferredLen += xferCnt;
+ pSRB->SGToBeXferLen = ResidCnt;
+
+ if( residual )
+ {
+ bval = inb(ioport+ScsiFifo); /* get residual byte */
+#ifndef VERSION_ELF_1_2_13
+ ptr = (PUCHAR) phys_to_virt( pSRB->SGPhysAddr );
+#else
+ ptr = (PUCHAR) pSRB->SGPhysAddr;
+#endif
+ *ptr = bval;
+ pSRB->SGPhysAddr++;
+ pSRB->TotalXferredLen++;
+ pSRB->SGToBeXferLen--;
+ }
+ }
+ }
+}
+
+static void
+DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+}
+
+static void
+DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR bval;
+ USHORT ioport;
+
+ ioport = pACB->IOPortBase;
+ bval = inb(ioport+ScsiFifo);
+ pSRB->TargetStatus = bval;
+ bval++;
+ bval = inb(ioport+ScsiFifo); /* get message */
+ pSRB->EndMessage = bval;
+
+ *psstatus = SCSI_NOP0;
+ pSRB->SRBState = SRB_COMPLETED;
+ bval = MSG_ACCEPTED_CMD;
+ outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) )
+ *psstatus = SCSI_NOP0;
+}
+
+static void
+DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR bval;
+ USHORT ioport, wval, wval1;
+ PDCB pDCB;
+ PSRB psrb;
+
+ ioport = pACB->IOPortBase;
+ pDCB = pACB->pActiveDCB;
+
+ bval = inb( ioport+ScsiFifo );
+ if( !(pSRB->SRBState & SRB_MSGIN_MULTI) )
+ {
+ if(bval == MSG_DISCONNECT)
+ {
+ pSRB->SRBState = SRB_DISCONNECT;
+ }
+ else if( bval == MSG_SAVE_PTR )
+ goto min6;
+ else if( (bval == MSG_EXTENDED) || ((bval >= MSG_SIMPLE_QTAG) &&
+ (bval <= MSG_ORDER_QTAG)) )
+ {
+ pSRB->SRBState |= SRB_MSGIN_MULTI;
+ pSRB->MsgInBuf[0] = bval;
+ pSRB->MsgCnt = 1;
+ pSRB->pMsgPtr = &pSRB->MsgInBuf[1];
+ }
+ else if(bval == MSG_REJECT_)
+ {
+ bval = RESET_ATN_CMD;
+ outb(bval, ioport+ScsiCmd);
+ if( pSRB->SRBState & DO_SYNC_NEGO)
+ goto set_async;
+ }
+ else if( bval == MSG_RESTORE_PTR)
+ goto min6;
+ else
+ goto min6;
+ }
+ else
+ { /* minx: */
+
+ *pSRB->pMsgPtr = bval;
+ pSRB->MsgCnt++;
+ pSRB->pMsgPtr++;
+ if( (pSRB->MsgInBuf[0] >= MSG_SIMPLE_QTAG) &&
+ (pSRB->MsgInBuf[0] <= MSG_ORDER_QTAG) )
+ {
+ if( pSRB->MsgCnt == 2)
+ {
+ pSRB->SRBState = 0;
+ bval = pSRB->MsgInBuf[1];
+ pSRB = pDCB->pGoingSRB;
+ psrb = pDCB->pGoingLast;
+ if( pSRB )
+ {
+ for( ;; )
+ {
+ if(pSRB->TagNumber != bval)
+ {
+ if( pSRB == psrb )
+ goto mingx0;
+ pSRB = pSRB->pNextSRB;
+ }
+ else
+ break;
+ }
+ if( pDCB->DCBFlag & ABORT_DEV_ )
+ {
+ pSRB->SRBState = SRB_ABORT_SENT;
+ EnableMsgOut( pACB, pSRB );
+ }
+ if( !(pSRB->SRBState & SRB_DISCONNECT) )
+ goto mingx0;
+ pDCB->pActiveSRB = pSRB;
+ pSRB->SRBState = SRB_DATA_XFER;
+ }
+ else
+ {
+mingx0:
+ pSRB = pACB->pTmpSRB;
+ pSRB->SRBState = SRB_UNEXPECT_RESEL;
+ pDCB->pActiveSRB = pSRB;
+ pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
+ EnableMsgOut2( pACB, pSRB );
+ }
+ }
+ }
+ else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgCnt == 5) )
+ {
+ pSRB->SRBState &= ~(SRB_MSGIN_MULTI+DO_SYNC_NEGO);
+ if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != 1) )
+ { /* reject_msg: */
+ pSRB->MsgCnt = 1;
+ pSRB->MsgInBuf[0] = MSG_REJECT_;
+ bval = SET_ATN_CMD;
+ outb(bval, ioport+ScsiCmd);
+ }
+ else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) )
+ {
+set_async:
+ pDCB = pSRB->pSRBDCB;
+ pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
+ pDCB->SyncPeriod = 0;
+ pDCB->SyncOffset = 0;
+ pDCB->CtrlR3 = FAST_CLK; /* ;non_fast */
+ pDCB->CtrlR4 &= 0x3f;
+ pDCB->CtrlR4 |= EATER_25NS; /* ; 25ns glitch eater */
+ goto re_prog;
+ }
+ else
+ { /* set_sync: */
+
+ pDCB = pSRB->pSRBDCB;
+ pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
+ pDCB->SyncOffset &= 0x0f0;
+ pDCB->SyncOffset |= pSRB->MsgInBuf[4];
+ pDCB->NegoPeriod = pSRB->MsgInBuf[3];
+ wval = (USHORT) pSRB->MsgInBuf[3];
+ wval = wval << 2;
+ wval--;
+ wval1 = wval / 25;
+ if( (wval1 * 25) != wval)
+ wval1++;
+ bval = FAST_CLK+FAST_SCSI;
+ pDCB->CtrlR4 &= 0x3f;
+ if(wval1 >= 8)
+ {
+ wval1--;
+ bval = FAST_CLK; /* ;fast clock/normal scsi */
+ pDCB->CtrlR4 |= EATER_25NS; /* ;25 ns glitch eater */
+ }
+ pDCB->CtrlR3 = bval;
+ pDCB->SyncPeriod = (UCHAR)wval1;
+re_prog:
+ bval = pDCB->SyncPeriod;
+ outb(bval, ioport+Sync_Period);
+ bval = pDCB->SyncOffset;
+ outb(bval, ioport+Sync_Offset);
+ bval = pDCB->CtrlR3;
+ outb(bval, ioport+CtrlReg3);
+ bval = pDCB->CtrlR4;
+ outb(bval, ioport+CtrlReg4);
+ SetXferRate( pACB, pDCB);
+ }
+ }
+ }
+min6:
+ *psstatus = SCSI_NOP0;
+ bval = MSG_ACCEPTED_CMD;
+ outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
+{
+ PSGL psgl;
+ UCHAR bval;
+ USHORT ioport;
+ ULONG lval;
+
+
+ ioport = pACB->IOPortBase;
+ if( pSRB->SGIndex < pSRB->SGcount )
+ {
+ bval = DMA_IDLE_CMD | ioDir; /* ;+EN_DMA_INT */
+ outb( bval, ioport+DMA_Cmd);
+ if( !pSRB->SGToBeXferLen )
+ {
+ psgl = pSRB->pSegmentList;
+#ifndef VERSION_ELF_1_2_13
+ pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+#else
+ pSRB->SGPhysAddr = (ULONG) psgl->address;
+#endif
+ pSRB->SGToBeXferLen = (ULONG) psgl->length;
+ }
+ lval = pSRB->SGToBeXferLen;
+ bval = (UCHAR) lval;
+ outb(bval,ioport+CtcReg_Low);
+ lval = lval >> 8;
+ bval = (UCHAR) lval;
+ outb(bval,ioport+CtcReg_Mid);
+ lval = lval >> 8;
+ bval = (UCHAR) lval;
+ outb(bval,ioport+CtcReg_High);
+
+ lval = pSRB->SGToBeXferLen;
+ outl(lval, ioport+DMA_XferCnt);
+
+ lval = pSRB->SGPhysAddr;
+ outl( lval, ioport+DMA_XferAddr);
+
+ bval = DMA_COMMAND+INFO_XFER_CMD;
+ outb(bval, ioport+ScsiCmd);
+
+ pSRB->SRBState = SRB_DATA_XFER;
+
+ bval = DMA_IDLE_CMD | ioDir; /* ;+EN_DMA_INT */
+ outb(bval, ioport+DMA_Cmd);
+
+ bval = DMA_START_CMD | ioDir; /* ;+EN_DMA_INT */
+ outb(bval, ioport+DMA_Cmd);
+ }
+ else /* xfer pad */
+ {
+ if( pSRB->SGcount )
+ {
+ pSRB->AdaptStatus = H_OVER_UNDER_RUN;
+ pSRB->SRBStatus |= OVER_RUN;
+ }
+ bval = 0;
+ outb(bval,ioport+CtcReg_Low);
+ outb(bval,ioport+CtcReg_Mid);
+ outb(bval,ioport+CtcReg_High);
+
+ pSRB->SRBState |= SRB_XFERPAD;
+ bval = DMA_COMMAND+XFER_PAD_BYTE;
+ outb(bval, ioport+ScsiCmd);
+/*
+ bval = DMA_IDLE_CMD | ioDir; ;+EN_DMA_INT
+ outb(bval, ioport+DMA_Cmd);
+ bval = DMA_START_CMD | ioDir; ;+EN_DMA_INT
+ outb(bval, ioport+DMA_Cmd);
+*/
+ }
+}
+
+
+static void
+DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR ioDir;
+
+ ioDir = WRITE_DIRECTION;
+ DataIO_Comm( pACB, pSRB, ioDir);
+}
+
+static void
+DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR ioDir;
+
+ ioDir = READ_DIRECTION;
+ DataIO_Comm( pACB, pSRB, ioDir);
+}
+
+static void
+DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ PDCB pDCB;
+ UCHAR bval;
+ PUCHAR ptr;
+ USHORT ioport, i, cnt;
+
+
+ ioport = pACB->IOPortBase;
+ bval = RESET_ATN_CMD;
+ outb(bval, ioport+ScsiCmd);
+ bval = CLEAR_FIFO_CMD;
+ outb(bval, ioport+ScsiCmd);
+ if( !(pSRB->SRBFlag & AUTO_REQSENSE) )
+ {
+ cnt = (USHORT) pSRB->ScsiCmdLen;
+ ptr = (PUCHAR) pSRB->CmdBlock;
+ for(i=0; i < cnt; i++)
+ {
+ outb(*ptr, ioport+ScsiFifo);
+ ptr++;
+ }
+ }
+ else
+ {
+ bval = REQUEST_SENSE;
+ outb(bval, ioport+ScsiFifo);
+ pDCB = pACB->pActiveDCB;
+ bval = pDCB->IdentifyMsg << 5;
+ outb(bval, ioport+ScsiFifo);
+ bval = 0;
+ outb(bval, ioport+ScsiFifo);
+ outb(bval, ioport+ScsiFifo);
+ bval = sizeof(pSRB->pcmd->sense_buffer);
+ outb(bval, ioport+ScsiFifo);
+ bval = 0;
+ outb(bval, ioport+ScsiFifo);
+ }
+ pSRB->SRBState = SRB_COMMAND;
+ bval = INFO_XFER_CMD;
+ outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR bval;
+ USHORT ioport;
+
+ ioport = pACB->IOPortBase;
+ bval = CLEAR_FIFO_CMD;
+ outb(bval, ioport+ScsiCmd);
+ pSRB->SRBState = SRB_STATUS;
+ bval = INITIATOR_CMD_CMPLTE;
+ outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR bval;
+ USHORT ioport, i, cnt;
+ PUCHAR ptr;
+ PDCB pDCB;
+
+ ioport = pACB->IOPortBase;
+ bval = CLEAR_FIFO_CMD;
+ outb(bval, ioport+ScsiCmd);
+ pDCB = pACB->pActiveDCB;
+ if( !(pSRB->SRBState & SRB_MSGOUT) )
+ {
+ cnt = pSRB->MsgCnt;
+ if( cnt )
+ {
+ ptr = (PUCHAR) pSRB->MsgOutBuf;
+ for(i=0; i < cnt; i++)
+ {
+ outb(*ptr, ioport+ScsiFifo);
+ ptr++;
+ }
+ pSRB->MsgCnt = 0;
+ if( (pDCB->DCBFlag & ABORT_DEV_) &&
+ (pSRB->MsgOutBuf[0] == MSG_ABORT) )
+ pSRB->SRBState = SRB_ABORT_SENT;
+ }
+ else
+ {
+ bval = MSG_ABORT; /* ??? MSG_NOP */
+ if( (pSRB->CmdBlock[0] == INQUIRY ) ||
+ (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+ (pSRB->SRBFlag & AUTO_REQSENSE) )
+ {
+ if( pDCB->SyncMode & SYNC_ENABLE )
+ goto mop1;
+ }
+ outb(bval, ioport+ScsiFifo);
+ }
+ bval = INFO_XFER_CMD;
+ outb( bval, ioport+ScsiCmd);
+ }
+ else
+ {
+mop1:
+ bval = MSG_EXTENDED;
+ outb(bval, ioport+ScsiFifo);
+ bval = 3; /* ;length of extended msg */
+ outb(bval, ioport+ScsiFifo);
+ bval = 1; /* ; sync nego */
+ outb(bval, ioport+ScsiFifo);
+ bval = pDCB->NegoPeriod;
+ outb(bval, ioport+ScsiFifo);
+ bval = SYNC_NEGO_OFFSET;
+ outb(bval, ioport+ScsiFifo);
+ pSRB->SRBState |= DO_SYNC_NEGO;
+ bval = INFO_XFER_CMD;
+ outb(bval, ioport+ScsiCmd);
+ }
+}
+
+static void
+DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+ UCHAR bval;
+ USHORT ioport;
+
+ ioport = pACB->IOPortBase;
+ bval = CLEAR_FIFO_CMD;
+ outb(bval, ioport+ScsiCmd);
+ if( !(pSRB->SRBState & SRB_MSGIN) )
+ {
+ pSRB->SRBState &= SRB_DISCONNECT;
+ pSRB->SRBState |= SRB_MSGIN;
+ }
+ bval = INFO_XFER_CMD;
+ outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+}
+
+static void
+DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+}
+
+
+static void
+SetXferRate( PACB pACB, PDCB pDCB )
+{
+ UCHAR bval;
+ USHORT cnt, i;
+ PDCB ptr;
+
+ if( !(pDCB->IdentifyMsg & 0x07) )
+ {
+ if( pACB->scan_devices )
+ {
+ CurrSyncOffset = pDCB->SyncOffset;
+ }
+ else
+ {
+ ptr = pACB->pLinkDCB;
+ cnt = pACB->DeviceCnt;
+ bval = pDCB->UnitSCSIID;
+ for(i=0; i<cnt; i++)
+ {
+ if( ptr->UnitSCSIID == bval )
+ {
+ ptr->SyncPeriod = pDCB->SyncPeriod;
+ ptr->SyncOffset = pDCB->SyncOffset;
+ ptr->CtrlR3 = pDCB->CtrlR3;
+ ptr->CtrlR4 = pDCB->CtrlR4;
+ ptr->SyncMode = pDCB->SyncMode;
+ }
+ ptr = ptr->pNextDCB;
+ }
+ }
+ }
+ return;
+}
+
+
+static void
+DC390_Disconnect( PACB pACB )
+{
+ PDCB pDCB;
+ PSRB pSRB, psrb;
+ ULONG flags;
+ USHORT ioport, i, cnt;
+ UCHAR bval;
+
+#ifdef DC390_DEBUG0
+ printk("DISC,");
+#endif
+
+ save_flags(flags);
+ cli();
+ ioport = pACB->IOPortBase;
+ pDCB = pACB->pActiveDCB;
+ if (!pDCB)
+ {
+#ifdef DC390_DEBUG0
+ printk("ACB:%08lx->ActiveDCB:%08lx !,",(ULONG)pACB,(ULONG)pDCB);
+#endif
+ restore_flags(flags); return;
+ }
+ pSRB = pDCB->pActiveSRB;
+ pACB->pActiveDCB = 0;
+ pSRB->ScsiPhase = SCSI_NOP0;
+ bval = EN_SEL_RESEL;
+ outb(bval, ioport+ScsiCmd);
+ if( pSRB->SRBState & SRB_UNEXPECT_RESEL )
+ {
+ pSRB->SRBState = 0;
+ DoWaitingSRB( pACB );
+ }
+ else if( pSRB->SRBState & SRB_ABORT_SENT )
+ {
+ pDCB->TagMask = 0;
+ pDCB->DCBFlag = 0;
+ cnt = pDCB->GoingSRBCnt;
+ pDCB->GoingSRBCnt = 0;
+ pSRB = pDCB->pGoingSRB;
+ for( i=0; i < cnt; i++)
+ {
+ psrb = pSRB->pNextSRB;
+ pSRB->pNextSRB = pACB->pFreeSRB;
+ pACB->pFreeSRB = pSRB;
+ pSRB = psrb;
+ }
+ pDCB->pGoingSRB = 0;
+ DoWaitingSRB( pACB );
+ }
+ else
+ {
+ if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) ||
+ !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) )
+ { /* Selection time out */
+ if( !(pACB->scan_devices) )
+ {
+ pSRB->SRBState = SRB_READY;
+ RewaitSRB( pDCB, pSRB);
+ }
+ else
+ {
+ pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT;
+ goto disc1;
+ }
+ }
+ else if( pSRB->SRBState & SRB_DISCONNECT )
+ {
+ DoWaitingSRB( pACB );
+ }
+ else if( pSRB->SRBState & SRB_COMPLETED )
+ {
+disc1:
+ if(pDCB->MaxCommand > 1)
+ {
+ bval = pSRB->TagNumber;
+ pDCB->TagMask &= (~(1 << bval)); /* free tag mask */
+ }
+ pDCB->pActiveSRB = 0;
+ pSRB->SRBState = SRB_FREE;
+ SRBdone( pACB, pDCB, pSRB);
+ }
+ }
+ restore_flags(flags);
+ return;
+}
+
+
+static void
+DC390_Reselect( PACB pACB )
+{
+ PDCB pDCB, pdcb;
+ PSRB pSRB;
+ USHORT ioport, wval;
+ UCHAR bval, bval1;
+
+
+#ifdef DC390_DEBUG0
+ printk("RSEL,");
+#endif
+ ioport = pACB->IOPortBase;
+ pDCB = pACB->pActiveDCB;
+ if( pDCB )
+ { /* Arbitration lost but Reselection win */
+ pSRB = pDCB->pActiveSRB;
+ if( !( pACB->scan_devices ) )
+ {
+ pSRB->SRBState = SRB_READY;
+ RewaitSRB( pDCB, pSRB);
+ }
+ }
+ bval = inb(ioport+ScsiFifo); /* get ID */
+ bval = bval ^ pACB->HostID_Bit;
+ wval = 0;
+ bval1 = 1;
+ for(;;)
+ {
+ if( !(bval & bval1) )
+ {
+ bval1 = bval1 << 1;
+ wval++;
+ }
+ else
+ break;
+ }
+ wval |= ( (USHORT) inb(ioport+ScsiFifo) & 7) << 8; /* get LUN */
+ pDCB = pACB->pLinkDCB;
+ pdcb = pDCB;
+ while( wval != *((PUSHORT) &pDCB->UnitSCSIID) )
+ {
+ pDCB = pDCB->pNextDCB;
+ if( pDCB == pdcb )
+ return;
+ }
+ pACB->pActiveDCB = pDCB;
+ if( pDCB->SyncMode & EN_TAG_QUEUING )
+ {
+ pSRB = pACB->pTmpSRB;
+ pDCB->pActiveSRB = pSRB;
+ }
+ else
+ {
+ pSRB = pDCB->pActiveSRB;
+ if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) )
+ {
+ pSRB= pACB->pTmpSRB;
+ pSRB->SRBState = SRB_UNEXPECT_RESEL;
+ pDCB->pActiveSRB = pSRB;
+ EnableMsgOut( pACB, pSRB );
+ }
+ else
+ {
+ if( pDCB->DCBFlag & ABORT_DEV_ )
+ {
+ pSRB->SRBState = SRB_ABORT_SENT;
+ EnableMsgOut( pACB, pSRB );
+ }
+ else
+ pSRB->SRBState = SRB_DATA_XFER;
+ }
+ }
+ pSRB->ScsiPhase = SCSI_NOP0;
+ bval = pDCB->UnitSCSIID;
+ outb( bval, ioport+Scsi_Dest_ID);
+ bval = pDCB->SyncPeriod;
+ outb(bval, ioport+Sync_Period);
+ bval = pDCB->SyncOffset;
+ outb( bval, ioport+Sync_Offset);
+ bval = pDCB->CtrlR1;
+ outb(bval, ioport+CtrlReg1);
+ bval = pDCB->CtrlR3;
+ outb(bval, ioport+CtrlReg3);
+ bval = pDCB->CtrlR4; /* ; Glitch eater */
+ outb(bval, ioport+CtrlReg4);
+ bval = MSG_ACCEPTED_CMD; /* ;to rls the /ACK signal */
+ outb(bval, ioport+ScsiCmd);
+}
+
+
+static void
+SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
+{
+ PSRB psrb;
+ UCHAR bval, bval1, i, j, status;
+ PSCSICMD pcmd;
+ PSCSI_INQDATA ptr;
+ USHORT disable_tag;
+ ULONG flags;
+ PSGL ptr2;
+ ULONG swlval;
+
+ pcmd = pSRB->pcmd;
+ status = pSRB->TargetStatus;
+ if(pSRB->SRBFlag & AUTO_REQSENSE)
+ {
+ pSRB->SRBFlag &= ~AUTO_REQSENSE;
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = SCSI_STAT_CHECKCOND;
+ if(status == SCSI_STAT_CHECKCOND)
+ {
+ pcmd->result = DID_BAD_TARGET << 16;
+ goto ckc_e;
+ }
+ if(pSRB->RetryCnt == 0)
+ {
+ *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
+ pSRB->TotalXferredLen = pSRB->Segment1[1];
+ if( (pSRB->TotalXferredLen) &&
+ (pSRB->TotalXferredLen >= pcmd->underflow) )
+ pcmd->result |= (DID_OK << 16);
+ else
+ pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
+ SCSI_STAT_CHECKCOND;
+#ifdef DC390_DEBUG0
+ printk("Cmd=%2x,Result=%8x,XferL=%8x,",pSRB->CmdBlock[0],
+ (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);
+#endif
+ goto ckc_e;
+ }
+ else
+ {
+ pSRB->RetryCnt--;
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+ *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
+ *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1];
+ if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
+ {
+ pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
+ SCSI_STAT_CHECKCOND;
+ goto ckc_e;
+ }
+ pcmd->result |= (DRIVER_SENSE << 24);
+ pSRB->SGcount = (UCHAR) pSRB->Segment1[0];
+ pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8);
+ pSRB->SGIndex = 0;
+ pSRB->TotalXferredLen = 0;
+ pSRB->SGToBeXferLen = 0;
+ if( pcmd->use_sg )
+ pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+ else if( pcmd->request_buffer )
+ {
+ pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+ pSRB->Segmentx.length = pcmd->request_bufflen;
+ }
+ if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
+ RewaitSRB( pDCB, pSRB );
+ return;
+ }
+ }
+ if( status )
+ {
+ if( status == SCSI_STAT_CHECKCOND)
+ {
+ if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) )
+ {
+ bval = pSRB->SGcount;
+ swlval = 0;
+ ptr2 = pSRB->pSegmentList;
+ for( i=pSRB->SGIndex; i < bval; i++)
+ {
+ swlval += ptr2->length;
+ ptr2++;
+ }
+#ifdef DC390_DEBUG0
+ printk("XferredLen=%8x,NotXferLen=%8x,",
+ (UINT) pSRB->TotalXferredLen, (UINT) swlval);
+#endif
+ }
+ RequestSense( pACB, pDCB, pSRB );
+ return;
+ }
+ else if( status == SCSI_STAT_QUEUEFULL )
+ {
+ bval = (UCHAR) pDCB->GoingSRBCnt;
+ bval--;
+ pDCB->MaxCommand = bval;
+ RewaitSRB( pDCB, pSRB );
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+ return;
+ }
+ else if(status == SCSI_STAT_SEL_TIMEOUT)
+ {
+ pSRB->AdaptStatus = H_SEL_TIMEOUT;
+ pSRB->TargetStatus = 0;
+ pcmd->result = DID_BAD_TARGET << 16;
+ }
+ else
+ {
+ pSRB->AdaptStatus = 0;
+ if( pSRB->RetryCnt )
+ {
+ pSRB->RetryCnt--;
+ pSRB->TargetStatus = 0;
+ pSRB->SGIndex = 0;
+ pSRB->TotalXferredLen = 0;
+ pSRB->SGToBeXferLen = 0;
+ if( pcmd->use_sg )
+ pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+ else if( pcmd->request_buffer )
+ {
+ pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+ pSRB->Segmentx.length = pcmd->request_bufflen;
+ }
+ if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
+ RewaitSRB( pDCB, pSRB );
+ return;
+ }
+ else
+ {
+ pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) |
+ (ULONG) status;
+ }
+ }
+ }
+ else
+ {
+ status = pSRB->AdaptStatus;
+ if(status & H_OVER_UNDER_RUN)
+ {
+ pSRB->TargetStatus = 0;
+ pcmd->result |= (DID_OK << 16) | (pSRB->EndMessage << 8);
+ }
+ else if( pSRB->SRBStatus & PARITY_ERROR)
+ {
+ pcmd->result |= (DID_PARITY << 16) | (pSRB->EndMessage << 8);
+ }
+ else /* No error */
+ {
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+ pcmd->result |= (DID_OK << 16);
+ }
+ }
+
+ckc_e:
+ if( pACB->scan_devices )
+ {
+ if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
+ {
+ if(pcmd->result != (DID_OK << 16))
+ {
+ if( pcmd->result & SCSI_STAT_CHECKCOND )
+ {
+ goto RTN_OK;
+ }
+ else
+ {
+ pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
+ pPrevDCB->pNextDCB = pACB->pLinkDCB;
+ if( (pcmd->target == pACB->max_id) &&
+ ((pcmd->lun == 0) || (pcmd->lun == pACB->max_lun)) )
+ {
+ pACB->scan_devices = 0;
+ }
+ }
+ }
+ else
+ {
+RTN_OK:
+ pPrevDCB->pNextDCB = pDCB;
+ pDCB->pNextDCB = pACB->pLinkDCB;
+ if( (pcmd->target == pACB->max_id) && (pcmd->lun == pACB->max_lun) )
+ pACB->scan_devices = END_SCAN;
+ }
+ }
+ else if( pSRB->CmdBlock[0] == INQUIRY )
+ {
+ if( (pcmd->target == pACB->max_id) &&
+ (pcmd->lun == pACB->max_lun) )
+ {
+ pACB->scan_devices = 0;
+ }
+ ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
+ if( pcmd->use_sg )
+ ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
+ bval1 = ptr->DevType & SCSI_DEVTYPE;
+ if(bval1 == SCSI_NODEV)
+ {
+ pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
+ pPrevDCB->pNextDCB = pACB->pLinkDCB;
+ }
+ else
+ {
+ pACB->DeviceCnt++;
+ pPrevDCB = pDCB;
+ pACB->pDCB_free = (PDCB) ((ULONG) (pACB->pDCB_free) + sizeof( DC390_DCB ));
+ pDCB->DevType = bval1;
+ if(bval1 == TYPE_DISK || bval1 == TYPE_MOD)
+ {
+ if( (((ptr->Vers & 0x07) >= 2) || ((ptr->RDF & 0x0F) == 2)) &&
+ (ptr->Flags & SCSI_INQ_CMDQUEUE) &&
+ (pDCB->DevMode & TAG_QUEUING_) &&
+ (pDCB->DevMode & EN_DISCONNECT_) )
+ {
+ disable_tag = 0;
+ for(i=0; i<BADDEVCNT; i++)
+ {
+ for(j=0; j<28; j++)
+ {
+ if( ((PUCHAR)ptr)[8+j] != baddevname1[i][j])
+ break;
+ }
+ if(j == 28)
+ {
+ disable_tag = 1;
+ break;
+ }
+ }
+
+ if( !disable_tag )
+ {
+ pDCB->MaxCommand = pACB->TagMaxNum;
+ pDCB->SyncMode |= EN_TAG_QUEUING;
+ pDCB->TagMask = 0;
+ }
+ else
+ {
+ pDCB->SyncMode |= EN_ATN_STOP;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ save_flags( flags );
+ cli();
+/* ReleaseSRB( pDCB, pSRB ); */
+
+ if(pSRB == pDCB->pGoingSRB )
+ {
+ pDCB->pGoingSRB = pSRB->pNextSRB;
+ }
+ else
+ {
+ psrb = pDCB->pGoingSRB;
+ while( psrb->pNextSRB != pSRB )
+ psrb = psrb->pNextSRB;
+ psrb->pNextSRB = pSRB->pNextSRB;
+ if( pSRB == pDCB->pGoingLast )
+ pDCB->pGoingLast = psrb;
+ }
+ pSRB->pNextSRB = pACB->pFreeSRB;
+ pACB->pFreeSRB = pSRB;
+ pDCB->GoingSRBCnt--;
+
+ DoWaitingSRB( pACB );
+ restore_flags(flags);
+
+/* Notify cmd done */
+ pcmd->scsi_done( pcmd );
+
+ if( pDCB->QIORBCnt )
+ DoNextCmd( pACB, pDCB );
+ return;
+}
+
+
+static void
+DoingSRB_Done( PACB pACB )
+{
+ PDCB pDCB, pdcb;
+ PSRB psrb, psrb2;
+ USHORT cnt, i;
+ PSCSICMD pcmd;
+
+ pDCB = pACB->pLinkDCB;
+ pdcb = pDCB;
+ do
+ {
+ cnt = pdcb->GoingSRBCnt;
+ psrb = pdcb->pGoingSRB;
+ for( i=0; i<cnt; i++)
+ {
+ psrb2 = psrb->pNextSRB;
+ pcmd = psrb->pcmd;
+ pcmd->result = DID_RESET << 16;
+
+/* ReleaseSRB( pDCB, pSRB ); */
+
+ psrb->pNextSRB = pACB->pFreeSRB;
+ pACB->pFreeSRB = psrb;
+
+ pcmd->scsi_done( pcmd );
+ psrb = psrb2;
+ }
+ pdcb->GoingSRBCnt = 0;;
+ pdcb->pGoingSRB = NULL;
+ pdcb->TagMask = 0;
+ pdcb = pdcb->pNextDCB;
+ }
+ while( pdcb != pDCB );
+}
+
+
+static void
+DC390_ResetSCSIBus( PACB pACB )
+{
+ USHORT ioport;
+ UCHAR bval;
+ ULONG flags;
+
+ save_flags(flags);
+ cli();
+ pACB->ACBFlag |= RESET_DEV;
+ ioport = pACB->IOPortBase;
+
+ bval = DMA_IDLE_CMD;
+ outb(bval,ioport+DMA_Cmd);
+
+ bval = RST_SCSI_BUS_CMD;
+ outb(bval,ioport+ScsiCmd);
+
+ restore_flags(flags);
+ return;
+}
+
+
+static void
+DC390_ScsiRstDetect( PACB pACB )
+{
+ ULONG wlval, flags;
+ USHORT ioport;
+ UCHAR bval;
+
+#ifdef DC390_DEBUG0
+ printk("RST_DETEC");
+#endif
+ save_flags(flags);
+ sti();
+ wlval = jiffies + HZ;
+ while( jiffies < wlval ); /* delay 1 sec */
+
+ cli();
+ ioport = pACB->IOPortBase;
+ bval = DMA_IDLE_CMD;
+ outb(bval,ioport+DMA_Cmd);
+ bval = CLEAR_FIFO_CMD;
+ outb(bval,ioport+ScsiCmd);
+
+ if( pACB->ACBFlag & RESET_DEV )
+ pACB->ACBFlag |= RESET_DONE;
+ else
+ {
+ pACB->ACBFlag |= RESET_DETECT;
+
+ ResetDevParam( pACB );
+/* DoingSRB_Done( pACB ); ???? */
+ RecoverSRB( pACB );
+ pACB->pActiveDCB = NULL;
+ pACB->ACBFlag = 0;
+ DoWaitingSRB( pACB );
+ }
+ restore_flags(flags);
+ return;
+}
+
+
+static void
+RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
+{
+ PSCSICMD pcmd;
+
+ pSRB->SRBFlag |= AUTO_REQSENSE;
+ pSRB->Segment0[0] = *((PULONG) &(pSRB->CmdBlock[0]));
+ pSRB->Segment0[1] = *((PULONG) &(pSRB->CmdBlock[4]));
+ pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount);
+ pSRB->Segment1[1] = pSRB->TotalXferredLen;
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+
+ pcmd = pSRB->pcmd;
+
+ pSRB->Segmentx.address = (PUCHAR) &(pcmd->sense_buffer);
+ pSRB->Segmentx.length = sizeof(pcmd->sense_buffer);
+ pSRB->pSegmentList = &pSRB->Segmentx;
+ pSRB->SGcount = 1;
+ pSRB->SGIndex = 0;
+
+ *((PULONG) &(pSRB->CmdBlock[0])) = 0x00000003;
+ pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5;
+ *((PUSHORT) &(pSRB->CmdBlock[4])) = sizeof(pcmd->sense_buffer);
+ pSRB->ScsiCmdLen = 6;
+
+ pSRB->TotalXferredLen = 0;
+ pSRB->SGToBeXferLen = 0;
+ if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
+ RewaitSRB( pDCB, pSRB );
+}
+
+
+static void
+EnableMsgOut2( PACB pACB, PSRB pSRB )
+{
+ USHORT ioport;
+ UCHAR bval;
+
+ ioport = pACB->IOPortBase;
+ pSRB->MsgCnt = 1;
+ bval = SET_ATN_CMD;
+ outb(bval, ioport+ScsiCmd);
+}
+
+
+static void
+EnableMsgOut( PACB pACB, PSRB pSRB )
+{
+ pSRB->MsgOutBuf[0] = MSG_ABORT;
+ EnableMsgOut2( pACB, pSRB );
+}
+
+
+static void
+DC390_InvalidCmd( PACB pACB )
+{
+ UCHAR bval;
+ USHORT ioport;
+ PSRB pSRB;
+
+ pSRB = pACB->pActiveDCB->pActiveSRB;
+ if( pSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
+ {
+ ioport = pACB->IOPortBase;
+ bval = CLEAR_FIFO_CMD;
+ outb(bval,(ioport+ScsiCmd));
+ }
+}
+
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 919fb7f0f..eb68d383b 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1047,7 +1047,7 @@ static int sd_init_onedisk(int i)
spintime = 0;
/* Spin up drives, as required. Only do this at boot time */
- if (!MODULE_FLAG){
+ /* Spinup needs to be done for module loads too. */
do{
retries = 0;
while(retries < 3)
@@ -1120,7 +1120,6 @@ static int sd_init_onedisk(int i)
else
printk( "ready\n" );
}
- } /* !MODULE_FLAG */
retries = 3;
do {
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index 73bff45af..e9c411e48 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -564,36 +564,6 @@ const char *seagate_st0x_info (struct Scsi_Host *shpnt)
return buffer;
}
-int seagate_st0x_proc_info (char *buffer, char **start, off_t offset,
- int length, int hostno, int inout)
-{
- const char *info = seagate_st0x_info (NULL);
- int len;
- int pos;
- int begin;
-
- if (inout)
- return (-ENOSYS);
-
- begin = 0;
- strcpy (buffer, info);
- strcat (buffer, "\n");
-
- pos = len = strlen (buffer);
-
- if (pos < offset)
- {
- len = 0;
- begin = pos;
- }
-
- *start = buffer + (offset - begin);
- len -= (offset - begin);
- if (len > length)
- len = length;
- return (len);
-}
-
/*
* These are our saved pointers for the outstanding command that is
* waiting for a reconnect
diff --git a/drivers/scsi/seagate.h b/drivers/scsi/seagate.h
index 7d677e5ea..f339ea612 100644
--- a/drivers/scsi/seagate.h
+++ b/drivers/scsi/seagate.h
@@ -19,7 +19,6 @@ int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int seagate_st0x_abort(Scsi_Cmnd *);
const char *seagate_st0x_info(struct Scsi_Host *);
int seagate_st0x_reset(Scsi_Cmnd *, unsigned int);
-int seagate_st0x_proc_info(char *,char **,off_t,int,int,int);
#ifndef NULL
#define NULL 0
@@ -28,7 +27,7 @@ int seagate_st0x_proc_info(char *,char **,off_t,int,int,int);
#include <linux/kdev_t.h>
int seagate_st0x_biosparam(Disk *, kdev_t, int*);
-#define SEAGATE_ST0X { NULL, NULL, NULL, seagate_st0x_proc_info, \
+#define SEAGATE_ST0X { NULL, NULL, NULL, NULL, \
NULL, seagate_st0x_detect, \
NULL, \
seagate_st0x_info, seagate_st0x_command, \
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
new file mode 100644
index 000000000..f5ceb1371
--- /dev/null
+++ b/drivers/scsi/tmscsim.c
@@ -0,0 +1,1928 @@
+/***********************************************************************
+ * FILE NAME : TMSCSIM.C *
+ * BY : C.L. Huang, ching@tekram.com.tw *
+ * Description: Device Driver for Tekram DC-390(T) PCI SCSI *
+ * Bus Master Host Adapter *
+ * (C)Copyright 1995-1996 Tekram Technology Co., Ltd. *
+ ***********************************************************************/
+/* Minor enhancements and bugfixes by *
+ * Kurt Garloff <K.Garloff@ping.de> *
+ ***********************************************************************/
+/* HISTORY: *
+ * *
+ * REV# DATE NAME DESCRIPTION *
+ * 1.00 04/24/96 CLH First release *
+ * 1.01 06/12/96 CLH Fixed bug of Media Change for Removable *
+ * Device, scan all LUN. Support Pre2.0.10 *
+ * 1.02 06/18/96 CLH Fixed bug of Command timeout ... *
+ * 1.03 09/25/96 KG Added tmscsim_proc_info() *
+ * 1.04 10/11/96 CLH Updating for support KV 2.0.x *
+ * 1.05 10/18/96 KG Fixed bug in DC390_abort(null ptr deref)*
+ * 1.06 10/25/96 KG Fixed module support *
+ * 1.07 11/09/96 KG Fixed tmscsim_proc_info() *
+ * 1.08 11/18/96 KG Fixed null ptr in DC390_Disconnect() *
+ * 1.09 11/30/96 KG Added register the allocated IO space *
+ * 1.10 12/05/96 CLH Modified tmscsim_proc_info(), and reset *
+ * pending interrupt in DC390_detect() *
+ ***********************************************************************/
+
+
+#define DC390_DEBUG
+
+#define SCSI_MALLOC
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/delay.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/config.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < 66354 /* 1.3.50 */
+#include "../block/blk.h"
+#else
+#include <linux/blk.h>
+#endif
+
+#include "scsi.h"
+#include "hosts.h"
+#include "tmscsim.h"
+#include "constants.h"
+#include "sd.h"
+#include <linux/stat.h>
+
+#include "dc390.h"
+
+#define PCI_DEVICE_ID_AMD53C974 PCI_DEVICE_ID_AMD_SCSI
+
+
+#ifndef VERSION_ELF_1_2_13
+struct proc_dir_entry proc_scsi_tmscsim ={
+ PROC_SCSI_DC390T, 7 ,"tmscsim",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+ };
+#endif
+
+static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+
+static void SetXferRate( PACB pACB, PDCB pDCB );
+static void DC390_Disconnect( PACB pACB );
+static void DC390_Reselect( PACB pACB );
+static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void DoingSRB_Done( PACB pACB );
+static void DC390_ScsiRstDetect( PACB pACB );
+static void DC390_ResetSCSIBus( PACB pACB );
+static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void EnableMsgOut2( PACB pACB, PSRB pSRB );
+static void EnableMsgOut( PACB pACB, PSRB pSRB );
+static void DC390_InvalidCmd( PACB pACB );
+
+int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index );
+void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd );
+
+#ifdef MODULE
+static int DC390_release(struct Scsi_Host *host);
+static int DC390_shutdown (struct Scsi_Host *host);
+#endif
+
+
+static PSHT pSHT_start = NULL;
+static PSH pSH_start = NULL;
+static PSH pSH_current = NULL;
+static PACB pACB_start= NULL;
+static PACB pACB_current = NULL;
+static PDCB pPrevDCB = NULL;
+static USHORT adapterCnt = 0;
+static USHORT InitialTime = 0;
+static USHORT CurrSyncOffset = 0;
+static ULONG mech1addr;
+static UCHAR mech2bus, mech2Agent, mech2CfgSPenR;
+
+static PVOID DC390_phase0[]={
+ DC390_DataOut_0,
+ DC390_DataIn_0,
+ DC390_Command_0,
+ DC390_Status_0,
+ DC390_Nop_0,
+ DC390_Nop_0,
+ DC390_MsgOut_0,
+ DC390_MsgIn_0,
+ DC390_Nop_1
+ };
+
+static PVOID DC390_phase1[]={
+ DC390_DataOutPhase,
+ DC390_DataInPhase,
+ DC390_CommandPhase,
+ DC390_StatusPhase,
+ DC390_Nop_0,
+ DC390_Nop_0,
+ DC390_MsgOutPhase,
+ DC390_MsgInPhase,
+ DC390_Nop_1,
+ };
+
+UCHAR eepromBuf[MAX_ADAPTER_NUM][128];
+
+
+UCHAR clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+
+UCHAR baddevname1[2][28] ={
+ "SEAGATE ST3390N 9546",
+ "HP C3323-300 4269"};
+
+#define BADDEVCNT 2
+
+
+/***********************************************************************
+ *
+ *
+ *
+ **********************************************************************/
+static void
+QLinkcmd( PSCSICMD cmd, PDCB pDCB )
+{
+ ULONG flags;
+ PSCSICMD pcmd;
+
+ save_flags(flags);
+ cli();
+
+ if( !pDCB->QIORBCnt )
+ {
+ pDCB->pQIORBhead = cmd;
+ pDCB->pQIORBtail = cmd;
+ pDCB->QIORBCnt++;
+ cmd->next = NULL;
+ }
+ else
+ {
+ pcmd = pDCB->pQIORBtail;
+ pcmd->next = cmd;
+ pDCB->pQIORBtail = cmd;
+ pDCB->QIORBCnt++;
+ cmd->next = NULL;
+ }
+
+ restore_flags(flags);
+}
+
+
+static PSCSICMD
+Getcmd( PDCB pDCB )
+{
+ ULONG flags;
+ PSCSICMD pcmd;
+
+ save_flags(flags);
+ cli();
+
+ pcmd = pDCB->pQIORBhead;
+ pDCB->pQIORBhead = pcmd->next;
+ pcmd->next = NULL;
+ pDCB->QIORBCnt--;
+
+ restore_flags(flags);
+ return( pcmd );
+}
+
+
+static PSRB
+GetSRB( PACB pACB )
+{
+ ULONG flags;
+ PSRB pSRB;
+
+ save_flags(flags);
+ cli();
+
+ pSRB = pACB->pFreeSRB;
+ if( pSRB )
+ {
+ pACB->pFreeSRB = pSRB->pNextSRB;
+ pSRB->pNextSRB = NULL;
+ }
+ restore_flags(flags);
+ return( pSRB );
+}
+
+
+static void
+RewaitSRB0( PDCB pDCB, PSRB pSRB )
+{
+ PSRB psrb1;
+ ULONG flags;
+
+ save_flags(flags);
+ cli();
+
+ if( (psrb1 = pDCB->pWaitingSRB) )
+ {
+ pSRB->pNextSRB = psrb1;
+ pDCB->pWaitingSRB = pSRB;
+ }
+ else
+ {
+ pSRB->pNextSRB = NULL;
+ pDCB->pWaitingSRB = pSRB;
+ pDCB->pWaitLast = pSRB;
+ }
+ restore_flags(flags);
+}
+
+
+static void
+RewaitSRB( PDCB pDCB, PSRB pSRB )
+{
+ PSRB psrb1;
+ ULONG flags;
+ UCHAR bval;
+
+ save_flags(flags);
+ cli();
+ pDCB->GoingSRBCnt--;
+ psrb1 = pDCB->pGoingSRB;
+ if( pSRB == psrb1 )
+ {
+ pDCB->pGoingSRB = psrb1->pNextSRB;
+ }
+ else
+ {
+ while( pSRB != psrb1->pNextSRB )
+ psrb1 = psrb1->pNextSRB;
+ psrb1->pNextSRB = pSRB->pNextSRB;
+ if( pSRB == pDCB->pGoingLast )
+ pDCB->pGoingLast = psrb1;
+ }
+ if( (psrb1 = pDCB->pWaitingSRB) )
+ {
+ pSRB->pNextSRB = psrb1;
+ pDCB->pWaitingSRB = pSRB;
+ }
+ else
+ {
+ pSRB->pNextSRB = NULL;
+ pDCB->pWaitingSRB = pSRB;
+ pDCB->pWaitLast = pSRB;
+ }
+
+ bval = pSRB->TagNumber;
+ pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */
+ restore_flags(flags);
+}
+
+
+static void
+DoWaitingSRB( PACB pACB )
+{
+ ULONG flags;
+ PDCB ptr, ptr1;
+ PSRB pSRB;
+
+ save_flags(flags);
+ cli();
+
+ if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) )
+ {
+ ptr = pACB->pDCBRunRobin;
+ if( !ptr )
+ {
+ ptr = pACB->pLinkDCB;
+ pACB->pDCBRunRobin = ptr;
+ }
+ ptr1 = ptr;
+ for( ;ptr1; )
+ {
+ pACB->pDCBRunRobin = ptr1->pNextDCB;
+ if( !( ptr1->MaxCommand > ptr1->GoingSRBCnt ) ||
+ !( pSRB = ptr1->pWaitingSRB ) )
+ {
+ if(pACB->pDCBRunRobin == ptr)
+ break;
+ ptr1 = ptr1->pNextDCB;
+ }
+ else
+ {
+ if( !DC390_StartSCSI(pACB, ptr1, pSRB) )
+ {
+ ptr1->GoingSRBCnt++;
+ if( ptr1->pWaitLast == pSRB )
+ {
+ ptr1->pWaitingSRB = NULL;
+ ptr1->pWaitLast = NULL;
+ }
+ else
+ {
+ ptr1->pWaitingSRB = pSRB->pNextSRB;
+ }
+ pSRB->pNextSRB = NULL;
+
+ if( ptr1->pGoingSRB )
+ ptr1->pGoingLast->pNextSRB = pSRB;
+ else
+ ptr1->pGoingSRB = pSRB;
+ ptr1->pGoingLast = pSRB;
+ }
+ break;
+ }
+ }
+ }
+ restore_flags(flags);
+ return;
+}
+
+
+static void
+SRBwaiting( PDCB pDCB, PSRB pSRB)
+{
+ if( pDCB->pWaitingSRB )
+ {
+ pDCB->pWaitLast->pNextSRB = pSRB;
+ pDCB->pWaitLast = pSRB;
+ pSRB->pNextSRB = NULL;
+ }
+ else
+ {
+ pDCB->pWaitingSRB = pSRB;
+ pDCB->pWaitLast = pSRB;
+ }
+}
+
+
+static void
+SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB )
+{
+ ULONG flags;
+ PDCB pDCB;
+
+ save_flags(flags);
+ cli();
+
+ pDCB = pSRB->pSRBDCB;
+ if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) ||
+ (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) )
+ {
+ SRBwaiting(pDCB, pSRB);
+ goto SND_EXIT;
+ }
+
+ if( pDCB->pWaitingSRB )
+ {
+ SRBwaiting(pDCB, pSRB);
+/* pSRB = GetWaitingSRB(pDCB); */
+ pSRB = pDCB->pWaitingSRB;
+ pDCB->pWaitingSRB = pSRB->pNextSRB;
+ pSRB->pNextSRB = NULL;
+ }
+
+ if( !DC390_StartSCSI(pACB, pDCB, pSRB) )
+ {
+ pDCB->GoingSRBCnt++;
+ if( pDCB->pGoingSRB )
+ {
+ pDCB->pGoingLast->pNextSRB = pSRB;
+ pDCB->pGoingLast = pSRB;
+ }
+ else
+ {
+ pDCB->pGoingSRB = pSRB;
+ pDCB->pGoingLast = pSRB;
+ }
+ }
+ else
+ RewaitSRB0( pDCB, pSRB );
+
+SND_EXIT:
+ restore_flags(flags);
+ return;
+}
+
+
+/***********************************************************************
+ * Function : static int DC390_queue_command (Scsi_Cmnd *cmd,
+ * void (*done)(Scsi_Cmnd *))
+ *
+ * Purpose : enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ * a pointer to the command descriptor.
+ *
+ * Returns : 0
+ *
+ ***********************************************************************/
+
+int
+DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+{
+ USHORT ioport, i;
+ Scsi_Cmnd *pcmd;
+ struct Scsi_Host *psh;
+ PACB pACB;
+ PDCB pDCB;
+ PSRB pSRB;
+ ULONG flags;
+ PUCHAR ptr,ptr1;
+
+ psh = cmd->host;
+ pACB = (PACB ) psh->hostdata;
+ ioport = pACB->IOPortBase;
+
+#ifdef DC390_DEBUG0
+/* if(pACB->scan_devices) */
+ printk("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmnd[0],cmd->target,cmd->lun);
+#endif
+
+ if( (pACB->scan_devices == END_SCAN) && (cmd->cmnd[0] != INQUIRY) )
+ {
+ pACB->scan_devices = 0;
+ pPrevDCB->pNextDCB = pACB->pLinkDCB;
+ }
+ else if( (pACB->scan_devices) && (cmd->cmnd[0] == 8) )
+ {
+ pACB->scan_devices = 0;
+ pPrevDCB->pNextDCB = pACB->pLinkDCB;
+ }
+
+ if ( ( cmd->target > pACB->max_id ) || (cmd->lun > pACB->max_lun) )
+ {
+/* printk("DC390: Ignore target %d lun %d\n",
+ cmd->target, cmd->lun); */
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ return( 0 );
+ }
+
+ if( (pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
+ {
+ if( pACB->DeviceCnt < MAX_DEVICES )
+ {
+ pACB->DCBmap[cmd->target] |= (1 << cmd->lun);
+ pDCB = pACB->pDCB_free;
+#ifdef DC390_DEBUG0
+ printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
+#endif
+ DC390_initDCB( pACB, pDCB, cmd );
+ }
+ else /* ???? */
+ {
+/* printk("DC390: Ignore target %d lun %d\n",
+ cmd->target, cmd->lun); */
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ return(0);
+ }
+ }
+ else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
+ {
+/* printk("DC390: Ignore target %d lun %d\n",
+ cmd->target, cmd->lun); */
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ return(0);
+ }
+ else
+ {
+ pDCB = pACB->pLinkDCB;
+ while( (pDCB->UnitSCSIID != cmd->target) ||
+ (pDCB->UnitSCSILUN != cmd->lun) )
+ {
+ pDCB = pDCB->pNextDCB;
+ }
+#ifdef DC390_DEBUG0
+ printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
+#endif
+ }
+
+ cmd->scsi_done = done;
+ cmd->result = 0;
+
+ save_flags(flags);
+ cli();
+
+ if( pDCB->QIORBCnt )
+ {
+ QLinkcmd( cmd, pDCB );
+ pcmd = Getcmd( pDCB );
+ }
+ else
+ pcmd = cmd;
+
+ pSRB = GetSRB( pACB );
+
+ if( !pSRB )
+ {
+ QLinkcmd( pcmd, pDCB );
+ restore_flags(flags);
+ return(0);
+ }
+
+/* BuildSRB(pSRB); */
+
+ pSRB->pSRBDCB = pDCB;
+ pSRB->pcmd = pcmd;
+ ptr = (PUCHAR) pSRB->CmdBlock;
+ ptr1 = (PUCHAR) pcmd->cmnd;
+ pSRB->ScsiCmdLen = pcmd->cmd_len;
+ for(i=0; i< pcmd->cmd_len; i++)
+ {
+ *ptr = *ptr1;
+ ptr++;
+ ptr1++;
+ }
+ if( pcmd->use_sg )
+ {
+ pSRB->SGcount = (UCHAR) pcmd->use_sg;
+ pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+ }
+ else if( pcmd->request_buffer )
+ {
+ pSRB->SGcount = 1;
+ pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+ pSRB->Segmentx.length = pcmd->request_bufflen;
+ }
+ else
+ pSRB->SGcount = 0;
+
+ pSRB->SGIndex = 0;
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+ pSRB->MsgCnt = 0;
+ if( pDCB->DevType != TYPE_TAPE )
+ pSRB->RetryCnt = 1;
+ else
+ pSRB->RetryCnt = 0;
+ pSRB->SRBStatus = 0;
+ pSRB->SRBFlag = 0;
+ pSRB->SRBState = 0;
+ pSRB->TotalXferredLen = 0;
+ pSRB->SGPhysAddr = 0;
+ pSRB->SGToBeXferLen = 0;
+ pSRB->ScsiPhase = 0;
+ pSRB->EndMessage = 0;
+ SendSRB( pcmd, pACB, pSRB );
+
+ restore_flags(flags);
+ return(0);
+}
+
+
+static void
+DoNextCmd( PACB pACB, PDCB pDCB )
+{
+ Scsi_Cmnd *pcmd;
+ PSRB pSRB;
+ ULONG flags;
+ PUCHAR ptr,ptr1;
+ USHORT i;
+
+
+ if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) )
+ return;
+ save_flags(flags);
+ cli();
+
+ pcmd = Getcmd( pDCB );
+ pSRB = GetSRB( pACB );
+ if( !pSRB )
+ {
+ QLinkcmd( pcmd, pDCB );
+ restore_flags(flags);
+ return;
+ }
+
+ pSRB->pSRBDCB = pDCB;
+ pSRB->pcmd = pcmd;
+ ptr = (PUCHAR) pSRB->CmdBlock;
+ ptr1 = (PUCHAR) pcmd->cmnd;
+ pSRB->ScsiCmdLen = pcmd->cmd_len;
+ for(i=0; i< pcmd->cmd_len; i++)
+ {
+ *ptr = *ptr1;
+ ptr++;
+ ptr1++;
+ }
+ if( pcmd->use_sg )
+ {
+ pSRB->SGcount = (UCHAR) pcmd->use_sg;
+ pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+ }
+ else if( pcmd->request_buffer )
+ {
+ pSRB->SGcount = 1;
+ pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+ pSRB->Segmentx.length = pcmd->request_bufflen;
+ }
+ else
+ pSRB->SGcount = 0;
+
+ pSRB->SGIndex = 0;
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+ pSRB->MsgCnt = 0;
+ if( pDCB->DevType != TYPE_TAPE )
+ pSRB->RetryCnt = 1;
+ else
+ pSRB->RetryCnt = 0;
+ pSRB->SRBStatus = 0;
+ pSRB->SRBFlag = 0;
+ pSRB->SRBState = 0;
+ pSRB->TotalXferredLen = 0;
+ pSRB->SGPhysAddr = 0;
+ pSRB->SGToBeXferLen = 0;
+ pSRB->ScsiPhase = 0;
+ pSRB->EndMessage = 0;
+ SendSRB( pcmd, pACB, pSRB );
+
+ restore_flags(flags);
+ return;
+}
+
+
+/***********************************************************************
+ * Function:
+ * DC390_bios_param
+ *
+ * Description:
+ * Return the disk geometry for the given SCSI device.
+ ***********************************************************************/
+#ifdef VERSION_ELF_1_2_13
+int DC390_bios_param(Disk *disk, int devno, int geom[])
+#else
+int DC390_bios_param(Disk *disk, kdev_t devno, int geom[])
+#endif
+{
+ int heads, sectors, cylinders;
+ PACB pACB;
+
+ pACB = (PACB) disk->device->host->hostdata;
+ heads = 64;
+ sectors = 32;
+ cylinders = disk->capacity / (heads * sectors);
+
+ if ( cylinders > 1024)
+ {
+ heads = 255;
+ sectors = 63;
+ cylinders = disk->capacity / (255 * 63);
+ }
+
+ geom[0] = heads;
+ geom[1] = sectors;
+ geom[2] = cylinders;
+
+ return (0);
+}
+
+
+/***********************************************************************
+ * Function : int DC390_abort (Scsi_Cmnd *cmd)
+ *
+ * Purpose : Abort an errant SCSI command
+ *
+ * Inputs : cmd - command to abort
+ *
+ * Returns : 0 on success, -1 on failure.
+ ***********************************************************************/
+
+int
+DC390_abort (Scsi_Cmnd *cmd)
+{
+ ULONG flags;
+ PACB pACB;
+ PDCB pDCB, pdcb;
+ PSRB pSRB, psrb;
+ USHORT count, i;
+ PSCSICMD pcmd, pcmd1;
+ int status;
+
+
+#ifdef DC390_DEBUG0
+ printk("DC390 : Abort Cmd.");
+#endif
+
+ save_flags(flags);
+ cli();
+
+ pACB = (PACB) cmd->host->hostdata;
+ pDCB = pACB->pLinkDCB;
+ pdcb = pDCB;
+ while( (pDCB->UnitSCSIID != cmd->target) ||
+ (pDCB->UnitSCSILUN != cmd->lun) )
+ {
+ pDCB = pDCB->pNextDCB;
+ if( pDCB == pdcb )
+ goto NOT_RUN;
+ }
+
+ if( pDCB->QIORBCnt )
+ {
+ pcmd = pDCB->pQIORBhead;
+ if( pcmd == cmd )
+ {
+ pDCB->pQIORBhead = pcmd->next;
+ pcmd->next = NULL;
+ pDCB->QIORBCnt--;
+ status = SCSI_ABORT_SUCCESS;
+ goto ABO_X;
+ }
+ for( count = pDCB->QIORBCnt, i=0; i<count-1; i++)
+ {
+ if( pcmd->next == cmd )
+ {
+ pcmd1 = pcmd->next;
+ pcmd->next = pcmd1->next;
+ pcmd1->next = NULL;
+ pDCB->QIORBCnt--;
+ status = SCSI_ABORT_SUCCESS;
+ goto ABO_X;
+ }
+ else
+ {
+ pcmd = pcmd->next;
+ }
+ }
+ }
+
+ pSRB = pDCB->pWaitingSRB;
+ if( !pSRB )
+ goto ON_GOING;
+ if( pSRB->pcmd == cmd )
+ {
+ pDCB->pWaitingSRB = pSRB->pNextSRB;
+ goto IN_WAIT;
+ }
+ else
+ {
+ psrb = pSRB;
+ if( !(psrb->pNextSRB) )
+ goto ON_GOING;
+ while( psrb->pNextSRB->pcmd != cmd )
+ {
+ psrb = psrb->pNextSRB;
+ if( !(psrb->pNextSRB) )
+ goto ON_GOING;
+ }
+ pSRB = psrb->pNextSRB;
+ psrb->pNextSRB = pSRB->pNextSRB;
+ if( pSRB == pDCB->pWaitLast )
+ pDCB->pWaitLast = psrb; /* No check for psrb == NULL ? */
+IN_WAIT:
+ pSRB->pNextSRB = pACB->pFreeSRB;
+ pACB->pFreeSRB = pSRB;
+ cmd->next = NULL;
+ status = SCSI_ABORT_SUCCESS;
+ goto ABO_X;
+ }
+
+ON_GOING:
+ pSRB = pDCB->pGoingSRB;
+ for( count = pDCB->GoingSRBCnt, i=0; i<count; i++)
+ {
+ if( pSRB->pcmd != cmd )
+ pSRB = pSRB->pNextSRB;
+ else
+ {
+ if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) )
+ {
+ status = SCSI_ABORT_BUSY;
+ goto ABO_X;
+ }
+ else
+ {
+ status = SCSI_ABORT_SNOOZE;
+ goto ABO_X;
+ }
+ }
+ }
+
+NOT_RUN:
+ status = SCSI_ABORT_NOT_RUNNING;
+
+ABO_X:
+ cmd->result = DID_ABORT << 16;
+ cmd->scsi_done(cmd);
+ restore_flags(flags);
+ return( status );
+}
+
+
+static void
+ResetDevParam( PACB pACB )
+{
+ PDCB pDCB, pdcb;
+
+ pDCB = pACB->pLinkDCB;
+ if( pDCB == NULL )
+ return;
+ pdcb = pDCB;
+ do
+ {
+ pDCB->SyncMode &= ~SYNC_NEGO_DONE;
+ pDCB->SyncPeriod = 0;
+ pDCB->SyncOffset = 0;
+ pDCB->CtrlR3 = FAST_CLK;
+ pDCB->CtrlR4 &= NEGATE_REQACKDATA;
+ pDCB->CtrlR4 |= EATER_25NS;
+ pDCB = pDCB->pNextDCB;
+ }
+ while( pdcb != pDCB );
+}
+
+
+static void
+RecoverSRB( PACB pACB )
+{
+ PDCB pDCB, pdcb;
+ PSRB psrb, psrb2;
+ USHORT cnt, i;
+
+ pDCB = pACB->pLinkDCB;
+ if( pDCB == NULL )
+ return;
+ pdcb = pDCB;
+ do
+ {
+ cnt = pdcb->GoingSRBCnt;
+ psrb = pdcb->pGoingSRB;
+ for (i=0; i<cnt; i++)
+ {
+ psrb2 = psrb;
+ psrb = psrb->pNextSRB;
+/* RewaitSRB( pDCB, psrb ); */
+ if( pdcb->pWaitingSRB )
+ {
+ psrb2->pNextSRB = pdcb->pWaitingSRB;
+ pdcb->pWaitingSRB = psrb2;
+ }
+ else
+ {
+ pdcb->pWaitingSRB = psrb2;
+ pdcb->pWaitLast = psrb2;
+ psrb2->pNextSRB = NULL;
+ }
+ }
+ pdcb->GoingSRBCnt = 0;
+ pdcb->pGoingSRB = NULL;
+ pdcb->TagMask = 0;
+ pdcb = pdcb->pNextDCB;
+ }
+ while( pdcb != pDCB );
+}
+
+
+/***********************************************************************
+ * Function : int DC390_reset (Scsi_Cmnd *cmd, ...)
+ *
+ * Purpose : perform a hard reset on the SCSI bus
+ *
+ * Inputs : cmd - command which caused the SCSI RESET
+ *
+ * Returns : 0 on success.
+ ***********************************************************************/
+
+#ifdef VERSION_2_0_0
+int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags)
+#else
+int DC390_reset (Scsi_Cmnd *cmd)
+#endif
+{
+ USHORT ioport;
+ unsigned long flags;
+ PACB pACB;
+ UCHAR bval;
+ USHORT i;
+
+
+#ifdef DC390_DEBUG1
+ printk("DC390: RESET,");
+#endif
+
+ pACB = (PACB ) cmd->host->hostdata;
+ ioport = pACB->IOPortBase;
+ save_flags(flags);
+ cli();
+ bval = inb(ioport+CtrlReg1);
+ bval |= DIS_INT_ON_SCSI_RST;
+ outb(bval,ioport+CtrlReg1); /* disable interrupt */
+ DC390_ResetSCSIBus( pACB );
+ for( i=0; i<500; i++ )
+ udelay(1000);
+ bval = inb(ioport+CtrlReg1);
+ bval &= ~DIS_INT_ON_SCSI_RST;
+ outb(bval,ioport+CtrlReg1); /* re-enable interrupt */
+
+ bval = DMA_IDLE_CMD;
+ outb(bval,ioport+DMA_Cmd);
+ bval = CLEAR_FIFO_CMD;
+ outb(bval,ioport+ScsiCmd);
+
+ ResetDevParam( pACB );
+ DoingSRB_Done( pACB );
+ pACB->pActiveDCB = NULL;
+
+ pACB->ACBFlag = 0;
+ DoWaitingSRB( pACB );
+
+ restore_flags(flags);
+#ifdef DC390_DEBUG1
+ printk("DC390: RESET1,");
+#endif
+ return( SCSI_RESET_SUCCESS );
+}
+
+
+#include "scsiiom.c"
+
+
+/***********************************************************************
+ * Function : static void DC390_initDCB
+ *
+ * Purpose : initialize the internal structures for a given DCB
+ *
+ * Inputs : cmd - pointer to this scsi cmd request block structure
+ *
+ ***********************************************************************/
+void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd )
+{
+ PEEprom prom;
+ UCHAR bval;
+ USHORT index;
+
+ if( pACB->DeviceCnt == 0 )
+ {
+ pACB->pLinkDCB = pDCB;
+ pACB->pDCBRunRobin = pDCB;
+ pDCB->pNextDCB = pDCB;
+ pPrevDCB = pDCB;
+ }
+ else
+ pPrevDCB->pNextDCB = pDCB;
+
+ pDCB->pDCBACB = pACB;
+ pDCB->QIORBCnt = 0;
+ pDCB->UnitSCSIID = cmd->target;
+ pDCB->UnitSCSILUN = cmd->lun;
+ pDCB->pWaitingSRB = NULL;
+ pDCB->pGoingSRB = NULL;
+ pDCB->GoingSRBCnt = 0;
+ pDCB->pActiveSRB = NULL;
+ pDCB->TagMask = 0;
+ pDCB->MaxCommand = 1;
+ pDCB->AdaptIndex = pACB->AdapterIndex;
+ index = pACB->AdapterIndex;
+ pDCB->DCBFlag = 0;
+
+ prom = (PEEprom) &eepromBuf[index][cmd->target << 2];
+ pDCB->DevMode = prom->EE_MODE1;
+ pDCB->AdpMode = eepromBuf[index][EE_MODE2];
+
+ if( pDCB->DevMode & EN_DISCONNECT_ )
+ bval = 0xC0;
+ else
+ bval = 0x80;
+ bval |= cmd->lun;
+ pDCB->IdentifyMsg = bval;
+
+ pDCB->SyncMode = 0;
+ if( pDCB->DevMode & SYNC_NEGO_ )
+ {
+ if( !(cmd->lun) || CurrSyncOffset )
+ pDCB->SyncMode = SYNC_ENABLE;
+ }
+
+ pDCB->SyncPeriod = 0;
+ pDCB->SyncOffset = 0;
+ pDCB->NegoPeriod = (clock_period1[prom->EE_SPEED] * 25) >> 2;
+
+ pDCB->CtrlR1 = pACB->AdaptSCSIID;
+ if( pDCB->DevMode & PARITY_CHK_ )
+ pDCB->CtrlR1 |= PARITY_ERR_REPO;
+
+ pDCB->CtrlR3 = FAST_CLK;
+
+ pDCB->CtrlR4 = EATER_25NS;
+ if( pDCB->AdpMode & ACTIVE_NEGATION)
+ pDCB->CtrlR4 |= NEGATE_REQACKDATA;
+}
+
+
+/***********************************************************************
+ * Function : static void DC390_initSRB
+ *
+ * Purpose : initialize the internal structures for a given SRB
+ *
+ * Inputs : psrb - pointer to this scsi request block structure
+ *
+ ***********************************************************************/
+void DC390_initSRB( PSRB psrb )
+{
+#ifndef VERSION_ELF_1_2_13
+#ifdef DC390_DEBUG0
+ printk("DC390 init: %08lx %08lx,",(ULONG)psrb,(ULONG)virt_to_bus(psrb));
+#endif
+ psrb->PhysSRB = virt_to_bus( psrb );
+#else
+ psrb->PhysSRB = (ULONG) psrb;
+#endif
+}
+
+
+void DC390_linkSRB( PACB pACB )
+{
+ USHORT count, i;
+ PSRB psrb;
+
+ count = pACB->SRBCount;
+
+ for( i=0; i< count; i++)
+ {
+ if( i != count - 1)
+ pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1];
+ else
+ pACB->SRB_array[i].pNextSRB = NULL;
+ psrb = (PSRB) &pACB->SRB_array[i];
+ DC390_initSRB( psrb );
+ }
+}
+
+
+/***********************************************************************
+ * Function : static void DC390_initACB
+ *
+ * Purpose : initialize the internal structures for a given SCSI host
+ *
+ * Inputs : psh - pointer to this host adapter's structure
+ *
+ ***********************************************************************/
+void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
+{
+ PACB pACB;
+ USHORT i;
+
+ psh->can_queue = MAX_CMD_QUEUE;
+ psh->cmd_per_lun = MAX_CMD_PER_LUN;
+ psh->this_id = (int) eepromBuf[index][EE_ADAPT_SCSI_ID];
+ psh->io_port = io_port;
+ psh->n_io_port = 0x80;
+ psh->irq = Irq;
+
+ pACB = (PACB) psh->hostdata;
+
+#ifndef VERSION_ELF_1_2_13
+ psh->max_id = 8;
+#ifdef CONFIG_SCSI_MULTI_LUN
+ if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
+ psh->max_lun = 8;
+ else
+#endif
+ psh->max_lun = 1;
+#endif
+
+ pACB->max_id = 7;
+ if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] )
+ pACB->max_id--;
+#ifdef CONFIG_SCSI_MULTI_LUN
+ if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
+ pACB->max_lun = 7;
+ else
+#endif
+ pACB->max_lun = 0;
+
+ pACB->pScsiHost = psh;
+ pACB->IOPortBase = (USHORT) io_port;
+ pACB->pLinkDCB = NULL;
+ pACB->pDCBRunRobin = NULL;
+ pACB->pActiveDCB = NULL;
+ pACB->pFreeSRB = pACB->SRB_array;
+ pACB->SRBCount = MAX_SRB_CNT;
+ pACB->AdapterIndex = index;
+ pACB->status = 0;
+ pACB->AdaptSCSIID = eepromBuf[index][EE_ADAPT_SCSI_ID];
+ pACB->HostID_Bit = (1 << pACB->AdaptSCSIID);
+ pACB->AdaptSCSILUN = 0;
+ pACB->DeviceCnt = 0;
+ pACB->IRQLevel = Irq;
+ pACB->TagMaxNum = eepromBuf[index][EE_TAG_CMD_NUM] << 2;
+ pACB->ACBFlag = 0;
+ pACB->scan_devices = 1;
+ pACB->Gmode2 = eepromBuf[index][EE_MODE2];
+ if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
+ pACB->LUNchk = 1;
+ pACB->pDCB_free = &pACB->DCB_array[0];
+ DC390_linkSRB( pACB );
+ pACB->pTmpSRB = &pACB->TmpSRB;
+ DC390_initSRB( pACB->pTmpSRB );
+ for(i=0; i<MAX_SCSI_ID; i++)
+ pACB->DCBmap[i] = 0;
+}
+
+
+/***********************************************************************
+ * Function : static int DC390_initAdapter
+ *
+ * Purpose : initialize the SCSI chip ctrl registers
+ *
+ * Inputs : psh - pointer to this host adapter's structure
+ *
+ ***********************************************************************/
+int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
+{
+ USHORT ioport;
+ UCHAR bval;
+ PACB pACB, pacb;
+ USHORT used_irq = 0;
+
+ pacb = pACB_start;
+ if( pacb != NULL )
+ {
+ for ( ; (pacb != (PACB) -1) ; )
+ {
+ if( pacb->IRQLevel == Irq )
+ {
+ used_irq = 1;
+ break;
+ }
+ else
+ pacb = pacb->pNextACB;
+ }
+ }
+
+ if( !used_irq )
+ {
+#ifdef VERSION_ELF_1_2_13
+ if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim"))
+#else
+ if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim", NULL))
+#endif
+ {
+ printk("DC390: register IRQ error!\n");
+ return( -1 );
+ }
+ }
+
+ request_region(io_port,psh->n_io_port,"tmscsim");
+
+ ioport = (USHORT) io_port;
+
+ pACB = (PACB) psh->hostdata;
+ bval = SEL_TIMEOUT; /* 250ms selection timeout */
+ outb(bval,ioport+Scsi_TimeOut);
+
+ bval = CLK_FREQ_40MHZ; /* Conversion factor = 0 , 40MHz clock */
+ outb(bval,ioport+Clk_Factor);
+
+ bval = NOP_CMD; /* NOP cmd - clear command register */
+ outb(bval,ioport+ScsiCmd);
+
+ bval = EN_FEATURE+EN_SCSI2_CMD; /* Enable Feature and SCSI-2 */
+ outb(bval,ioport+CtrlReg2);
+
+ bval = FAST_CLK; /* fast clock */
+ outb(bval,ioport+CtrlReg3);
+
+ bval = EATER_25NS;
+ if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION )
+ bval |= NEGATE_REQACKDATA;
+ outb(bval,ioport+CtrlReg4);
+
+ bval = DIS_INT_ON_SCSI_RST; /* Disable SCSI bus reset interrupt */
+ outb(bval,ioport+CtrlReg1);
+
+ return(0);
+}
+
+
+void
+DC390_EnableCfg( USHORT mechnum, UCHAR regval )
+{
+ ULONG wlval;
+
+ if(mechnum == 2)
+ {
+ outb(mech2bus, PCI_CFG2_FORWARD_REG);
+ outb(mech2CfgSPenR, PCI_CFG2_ENABLE_REG);
+ }
+ else
+ {
+ regval &= 0xFC;
+ wlval = mech1addr;
+ wlval |= (((ULONG)regval) & 0xff);
+ outl(wlval, PCI_CFG1_ADDRESS_REG);
+ }
+}
+
+
+void
+DC390_DisableCfg( USHORT mechnum )
+{
+
+ if(mechnum == 2)
+ outb(0, PCI_CFG2_ENABLE_REG);
+ else
+ outl(0, PCI_CFG1_ADDRESS_REG);
+}
+
+
+UCHAR
+DC390_inByte( USHORT mechnum, UCHAR regval )
+{
+ UCHAR bval;
+ ULONG wval;
+ ULONG flags;
+
+ save_flags(flags);
+ cli();
+ DC390_EnableCfg( mechnum, regval );
+ if(mechnum == 2)
+ {
+ wval = mech2Agent;
+ wval <<= 8;
+ wval |= ((USHORT) regval) & 0xff;
+ bval = inb(wval);
+ }
+ else
+ {
+ regval &= 3;
+ bval = inb(PCI_CFG1_DATA_REG | regval);
+ }
+ DC390_DisableCfg(mechnum);
+ restore_flags(flags);
+ return(bval);
+}
+
+
+USHORT
+DC390_inWord( USHORT mechnum, UCHAR regval )
+{
+ USHORT wval;
+ ULONG flags;
+
+ save_flags(flags);
+ cli();
+ DC390_EnableCfg(mechnum,regval);
+ if(mechnum == 2)
+ {
+ wval = mech2Agent;
+ wval <<= 8;
+ wval |= regval;
+ wval = inw(wval);
+ }
+ else
+ {
+ regval &= 3;
+ wval = inw(PCI_CFG1_DATA_REG | regval);
+ }
+ DC390_DisableCfg(mechnum);
+ restore_flags(flags);
+ return(wval);
+}
+
+
+ULONG
+DC390_inDword(USHORT mechnum, UCHAR regval )
+{
+ ULONG wlval;
+ ULONG flags;
+ USHORT wval;
+
+ save_flags(flags);
+ cli();
+ DC390_EnableCfg(mechnum,regval);
+ if(mechnum == 2)
+ {
+ wval = mech2Agent;
+ wval <<= 8;
+ wval |= regval;
+ wlval = inl(wval);
+ }
+ else
+ {
+ wlval = inl(PCI_CFG1_DATA_REG);
+ }
+ DC390_DisableCfg(mechnum);
+ restore_flags(flags);
+ return(wlval);
+}
+
+
+void
+DC390_OutB(USHORT mechnum, UCHAR regval, UCHAR bval )
+{
+
+ USHORT wval;
+ ULONG flags;
+
+ save_flags(flags);
+ cli();
+ DC390_EnableCfg(mechnum,regval);
+ if(mechnum == 2)
+ {
+ wval = mech2Agent;
+ wval <<= 8;
+ wval |= regval;
+ outb(bval, wval);
+ }
+ else
+ {
+ regval &= 3;
+ outb(bval, PCI_CFG1_DATA_REG | regval);
+ }
+ DC390_DisableCfg(mechnum);
+ restore_flags(flags);
+}
+
+
+void
+DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval )
+{
+
+ UCHAR bval;
+
+ bval = 0;
+ if(mode == ENABLE_CE)
+ *regval = 0xc0;
+ else
+ *regval = 0x80;
+ DC390_OutB(mechnum,*regval,bval);
+ if(mode == DISABLE_CE)
+ DC390_OutB(mechnum,*regval,bval);
+ udelay(160);
+}
+
+
+void
+DC390_EEpromOutDI( USHORT mechnum, PUCHAR regval, USHORT Carry )
+{
+ UCHAR bval;
+
+ bval = 0;
+ if(Carry)
+ {
+ bval = 0x40;
+ *regval = 0x80;
+ DC390_OutB(mechnum,*regval,bval);
+ }
+ udelay(160);
+ bval |= 0x80;
+ DC390_OutB(mechnum,*regval,bval);
+ udelay(160);
+ bval = 0;
+ DC390_OutB(mechnum,*regval,bval);
+ udelay(160);
+}
+
+
+UCHAR
+DC390_EEpromInDO( USHORT mechnum )
+{
+ UCHAR bval,regval;
+
+ regval = 0x80;
+ bval = 0x80;
+ DC390_OutB(mechnum,regval,bval);
+ udelay(160);
+ bval = 0x40;
+ DC390_OutB(mechnum,regval,bval);
+ udelay(160);
+ regval = 0x0;
+ bval = DC390_inByte(mechnum,regval);
+ if(bval == 0x22)
+ return(1);
+ else
+ return(0);
+}
+
+
+USHORT
+EEpromGetData1( USHORT mechnum )
+{
+ UCHAR i;
+ UCHAR carryFlag;
+ USHORT wval;
+
+ wval = 0;
+ for(i=0; i<16; i++)
+ {
+ wval <<= 1;
+ carryFlag = DC390_EEpromInDO(mechnum);
+ wval |= carryFlag;
+ }
+ return(wval);
+}
+
+
+void
+DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd )
+{
+ UCHAR i,j;
+ USHORT carryFlag;
+
+ carryFlag = 1;
+ j = 0x80;
+ for(i=0; i<9; i++)
+ {
+ DC390_EEpromOutDI(mechnum,regval,carryFlag);
+ carryFlag = (EEpromCmd & j) ? 1 : 0;
+ j >>= 1;
+ }
+}
+
+
+void
+DC390_ReadEEprom( USHORT mechnum, USHORT index )
+{
+ UCHAR regval,cmd;
+ PUSHORT ptr;
+ USHORT i;
+
+ ptr = (PUSHORT) &eepromBuf[index][0];
+ cmd = EEPROM_READ;
+ for(i=0; i<0x40; i++)
+ {
+ DC390_EnDisableCE(ENABLE_CE, mechnum, &regval);
+ DC390_Prepare(mechnum, &regval, cmd);
+ *ptr = EEpromGetData1(mechnum);
+ ptr++;
+ cmd++;
+ DC390_EnDisableCE(DISABLE_CE,mechnum,&regval);
+ }
+}
+
+
+USHORT
+DC390_CheckEEpromCheckSum( USHORT MechNum, USHORT index )
+{
+ USHORT wval, rc, *ptr;
+ UCHAR i;
+
+ DC390_ReadEEprom( MechNum, index );
+ wval = 0;
+ ptr = (PUSHORT) &eepromBuf[index][0];
+ for(i=0; i<128 ;i+=2, ptr++)
+ wval += *ptr;
+ if( wval == 0x1234 )
+ rc = 0;
+ else
+ rc = -1;
+ return( rc );
+}
+
+
+USHORT
+DC390_ToMech( USHORT Mechnum, USHORT BusDevFunNum )
+{
+ USHORT devnum;
+
+ devnum = BusDevFunNum;
+
+ if(Mechnum == 2)
+ {
+ if(devnum & 0x80)
+ return(-1);
+ mech2bus = (UCHAR)((devnum & 0xff00) >> 8); /* Bus num */
+ mech2Agent = ((UCHAR)(devnum & 0xff)) >> 3; /* Dev num */
+ mech2Agent |= 0xc0;
+ mech2CfgSPenR = ((UCHAR)(devnum & 0xff)) & 0x07; /* Fun num */
+ mech2CfgSPenR = (mech2CfgSPenR << 1) | 0x20;
+ }
+ else /* use mech #1 method */
+ {
+ mech1addr = 0x80000000 | ((ULONG)devnum << 8);
+ }
+ return(0);
+}
+
+/***********************************************************************
+ * Function : static int DC390_init (struct Scsi_Host *host)
+ *
+ * Purpose : initialize the internal structures for a given SCSI host
+ *
+ * Inputs : host - pointer to this host adapter's structure/
+ *
+ * Preconditions : when this function is called, the chip_type
+ * field of the pACB structure MUST have been set.
+ ***********************************************************************/
+
+static int
+DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum)
+{
+ PSH psh;
+ PACB pACB;
+
+ if( !DC390_CheckEEpromCheckSum( MechNum, index) )
+ {
+ psh = scsi_register( psht, sizeof(DC390_ACB) );
+ if( !psh )
+ return( -1 );
+ if( !pSH_start )
+ {
+ pSH_start = psh;
+ pSH_current = psh;
+ }
+ else
+ {
+ pSH_current->next = psh;
+ pSH_current = psh;
+ }
+
+#ifdef DC390_DEBUG0
+ printk("DC390: pSH = %8x,", (UINT) psh);
+ printk("DC390: Index %02i,", index);
+#endif
+
+ DC390_initACB( psh, io_port, Irq, index );
+ if( !DC390_initAdapter( psh, io_port, Irq, index ) )
+ {
+ pACB = (PACB) psh->hostdata;
+ if( !pACB_start )
+ {
+ pACB_start = pACB;
+ pACB_current = pACB;
+ pACB->pNextACB = (PACB) -1;
+ }
+ else
+ {
+ pACB_current->pNextACB = pACB;
+ pACB_current = pACB;
+ pACB->pNextACB = (PACB) -1;
+ }
+
+#ifdef DC390_DEBUG0
+ printk("DC390: pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n",
+ (UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array);
+ printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",
+ sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );
+#endif
+
+ }
+ else
+ {
+ pSH_start = NULL;
+ scsi_unregister( psh );
+ return( -1 );
+ }
+ return( 0 );
+ }
+ else
+ {
+ printk("DC390_init: EEPROM reading error!\n");
+ return( -1 );
+ }
+}
+
+
+/***********************************************************************
+ * Function : int DC390_detect(Scsi_Host_Template *psht)
+ *
+ * Purpose : detects and initializes AMD53C974 SCSI chips
+ * that were autoprobed, overridden on the LILO command line,
+ * or specified at compile time.
+ *
+ * Inputs : psht - template for this SCSI adapter
+ *
+ * Returns : number of host adapters detected
+ *
+ ***********************************************************************/
+
+int
+DC390_detect(Scsi_Host_Template *psht)
+{
+#ifdef FOR_PCI_OK
+ UCHAR pci_bus, pci_device_fn;
+ int error = 0;
+ USHORT chipType = 0;
+ USHORT i;
+#endif
+
+ UCHAR irq;
+ UCHAR istatus;
+#ifndef VERSION_ELF_1_2_13
+ UINT io_port;
+#else
+ ULONG io_port;
+#endif
+ USHORT adaptCnt = 0; /* Number of boards detected */
+ USHORT pci_index = 0; /* Device index to PCI BIOS calls */
+ USHORT MechNum, BusDevFunNum;
+ ULONG wlval;
+
+#ifndef VERSION_ELF_1_2_13
+ psht->proc_dir = &proc_scsi_tmscsim;
+#endif
+
+ InitialTime = 1;
+ pSHT_start = psht;
+ pACB_start = NULL;
+
+ MechNum = 1;
+ for( ; (MechNum < 3) && (!adaptCnt); MechNum++)
+ {
+ BusDevFunNum = 0;
+ for (; adaptCnt < MAX_ADAPTER_NUM ;)
+ {
+ if( !DC390_ToMech( MechNum, BusDevFunNum) )
+ {
+ wlval = DC390_inDword( MechNum, PCI_VENDOR_ID);
+ if(wlval == ( (PCI_DEVICE_ID_AMD53C974 << 16)+
+ PCI_VENDOR_ID_AMD) )
+ {
+ io_port =DC390_inDword(MechNum,PCI_BASE_ADDRESS_0) & 0xFFFE;
+ irq = DC390_inByte( MechNum, PCI_INTERRUPT_LINE);
+#ifdef DC390_DEBUG0
+ printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
+#endif
+ if( !DC390_init(psht, io_port, irq, pci_index, MechNum) )
+ {
+ adaptCnt++;
+ pci_index++;
+ istatus = inb( (USHORT)io_port+INT_Status ); /* Reset Pending INT */
+#ifdef DC390_DEBUG0
+ printk("DC390: Mech=%2x,\n",(UCHAR) MechNum);
+#endif
+ }
+ }
+ }
+ if( BusDevFunNum != 0xfff8 )
+ BusDevFunNum += 8; /* next device # */
+ else
+ break;
+ }
+ }
+
+#ifdef FOR_PCI_OK
+ if ( pcibios_present() )
+ {
+ for (i = 0; i < MAX_ADAPTER_NUM; ++i)
+ {
+ if( !pcibios_find_device( PCI_VENDOR_ID_AMD,
+ PCI_DEVICE_ID_AMD53C974,
+ pci_index, &pci_bus, &pci_device_fn) )
+ {
+ chipType = PCI_DEVICE_ID_AMD53C974;
+ pci_index++;
+ }
+
+ if( chipType )
+ {
+
+ error = pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &io_port);
+ error |= pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &irq);
+ if( error )
+ {
+ printk("DC390_detect: reading configuration registers error!\n");
+ InitialTime = 0;
+ return( 0 );
+ }
+
+ (USHORT) io_port = (USHORT) io_port & 0xFFFE;
+#ifdef DC390_DEBUG0
+ printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
+#endif
+ if( !DC390_init(psht, io_port, irq, i) )
+ adaptCnt++;
+ chipType = 0;
+ }
+ else
+ break;
+ }
+ }
+#endif
+
+ InitialTime = 0;
+ adapterCnt = adaptCnt;
+ return( adaptCnt );
+}
+
+
+#ifndef VERSION_ELF_1_2_13
+
+/********************************************************************
+ * Function: tmscsim_set_info()
+ *
+ * Purpose: Set adapter info (!)
+ *
+ * Not yet implemented
+ *
+ *******************************************************************/
+
+int tmscsim_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
+{
+ return(-ENOSYS); /* Currently this is a no-op */
+}
+
+/********************************************************************
+ * Function: tmscsim_proc_info(char* buffer, char **start,
+ * off_t offset, int length, int hostno, int inout)
+ *
+ * Purpose: return SCSI Adapter/Device Info
+ *
+ * Input: buffer: Pointer to a buffer where to write info
+ * start :
+ * offset:
+ * hostno: Host adapter index
+ * inout : Read (=0) or set(!=0) info
+ *
+ * Output: buffer: contains info
+ * length; length of info in buffer
+ *
+ * return value: length
+ *
+ ********************************************************************/
+
+/* KG: proc_info taken from driver aha152x.c */
+
+#undef SPRINTF
+#define SPRINTF(args...) pos += sprintf(pos, ## args)
+
+#define YESNO(YN)\
+if (YN) SPRINTF(" Yes ");\
+else SPRINTF(" No ")
+
+int tmscsim_proc_info(char *buffer, char **start,
+ off_t offset, int length, int hostno, int inout)
+{
+ int dev, spd, spd1;
+ char *pos = buffer;
+ PSH shpnt;
+ PACB acbpnt;
+ PDCB dcbpnt;
+ unsigned long flags;
+/* Scsi_Cmnd *ptr; */
+
+ acbpnt = pACB_start;
+
+ while(acbpnt != (PACB)-1)
+ {
+ shpnt = acbpnt->pScsiHost;
+ if (shpnt->host_no == hostno) break;
+ acbpnt = acbpnt->pNextACB;
+ }
+
+ if (acbpnt == (PACB)-1) return(-ESRCH);
+ if(!shpnt) return(-ESRCH);
+
+ if(inout) // Has data been written to the file ?
+ return(tmscsim_set_info(buffer, length, shpnt));
+
+ SPRINTF("Tekram DC390(T) PCI SCSI Host Adadpter, ");
+ SPRINTF("Driver Version 1.10, 1996/12/05\n");
+
+ save_flags(flags);
+ cli();
+
+ SPRINTF("SCSI Host Nr %i, ", shpnt->host_no);
+ SPRINTF("DC390 Adapter Nr %i\n", acbpnt->AdapterIndex);
+ SPRINTF("IOPortBase 0x%04x, ", acbpnt->IOPortBase);
+ SPRINTF("IRQLevel 0x%02x\n", acbpnt->IRQLevel);
+
+ SPRINTF("MaxID %i, MaxLUN %i, ",acbpnt->max_id, acbpnt->max_lun);
+ SPRINTF("AdapterID %i, AdapterLUN %i\n", acbpnt->AdaptSCSIID, acbpnt->AdaptSCSILUN);
+
+ SPRINTF("TagMaxNum %i, Status %i\n", acbpnt->TagMaxNum, acbpnt->status);
+
+ SPRINTF("Nr of attached devices: %i\n", acbpnt->DeviceCnt);
+
+ SPRINTF("Un ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs\n");
+
+ dcbpnt = acbpnt->pLinkDCB;
+ for (dev = 0; dev < acbpnt->DeviceCnt; dev++)
+ {
+ SPRINTF("%02i %02i %02i ", dev, dcbpnt->UnitSCSIID, dcbpnt->UnitSCSILUN);
+ YESNO(dcbpnt->DevMode & PARITY_CHK_);
+ YESNO(dcbpnt->SyncMode & SYNC_NEGO_DONE);
+ YESNO(dcbpnt->DevMode & EN_DISCONNECT_);
+ YESNO(dcbpnt->DevMode & SEND_START_);
+ YESNO(dcbpnt->SyncMode & EN_TAG_QUEUING);
+ SPRINTF(" %03i ns ", (dcbpnt->NegoPeriod) << 2);
+ if (dcbpnt->SyncOffset & 0x0f)
+ {
+ spd = 1000/(dcbpnt->NegoPeriod <<2);
+ spd1 = 1000%(dcbpnt->NegoPeriod <<2);
+ spd1 = (spd1 * 10)/(dcbpnt->NegoPeriod <<2);
+ SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (dcbpnt->SyncOffset & 0x0f));
+ }
+ else SPRINTF("\n");
+ /* Add more info ...*/
+ dcbpnt = dcbpnt->pNextDCB;
+ }
+
+ restore_flags(flags);
+ *start = buffer + offset;
+
+ if (pos - buffer < offset)
+ return 0;
+ else if (pos - buffer - offset < length)
+ return pos - buffer - offset;
+ else
+ return length;
+}
+#endif /* VERSION_ELF_1_2_13 */
+
+
+#ifdef MODULE
+
+/***********************************************************************
+ * Function : static int DC390_shutdown (struct Scsi_Host *host)
+ *
+ * Purpose : does a clean (we hope) shutdown of the SCSI chip.
+ * Use prior to dumping core, unloading the driver, etc.
+ *
+ * Returns : 0 on success
+ ***********************************************************************/
+static int
+DC390_shutdown (struct Scsi_Host *host)
+{
+ UCHAR bval;
+ USHORT ioport;
+ unsigned long flags;
+ PACB pACB = (PACB)(host->hostdata);
+
+ ioport = (unsigned int) pACB->IOPortBase;
+
+ save_flags (flags);
+ cli();
+
+/* pACB->soft_reset(host); */
+
+#ifdef DC390_DEBUG0
+ printk("DC390: shutdown,");
+#endif
+
+ bval = inb(ioport+CtrlReg1);
+ bval |= DIS_INT_ON_SCSI_RST;
+ outb(bval,ioport+CtrlReg1); /* disable interrupt */
+ DC390_ResetSCSIBus( pACB );
+
+ restore_flags (flags);
+ return( 0 );
+}
+
+
+int DC390_release(struct Scsi_Host *host)
+{
+ int irq_count;
+ struct Scsi_Host *tmp;
+
+ DC390_shutdown (host);
+
+ if (host->irq != IRQ_NONE)
+ {
+ for (irq_count = 0, tmp = pSH_start; tmp; tmp = tmp->next)
+ {
+ if ( tmp->irq == host->irq )
+ ++irq_count;
+ }
+ if (irq_count == 1)
+ {
+#ifdef DC390_DEBUG0
+ printk("DC390: Free IRQ %i.",host->irq);
+#endif
+#ifndef VERSION_ELF_1_2_13
+ free_irq(host->irq,NULL);
+#else
+ free_irq(host->irq);
+#endif
+ }
+ }
+
+ release_region(host->io_port,host->n_io_port);
+
+ return( 1 );
+}
+
+Scsi_Host_Template driver_template = DC390_T;
+#include "scsi_module.c"
+#endif /* def MODULE */
+
diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h
new file mode 100644
index 000000000..361c488ac
--- /dev/null
+++ b/drivers/scsi/tmscsim.h
@@ -0,0 +1,680 @@
+/***********************************************************************
+;* File Name : TMSCSIM.H *
+;* TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter *
+;* Device Driver *
+;***********************************************************************/
+
+#ifndef TMSCSIM_H
+#define TMSCSIM_H
+
+#define IRQ_NONE 255
+
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef unsigned long ULONG;
+typedef unsigned int UINT;
+
+typedef UCHAR *PUCHAR;
+typedef USHORT *PUSHORT;
+typedef ULONG *PULONG;
+typedef Scsi_Host_Template *PSHT;
+typedef struct Scsi_Host *PSH;
+typedef Scsi_Device *PSCSIDEV;
+typedef Scsi_Cmnd *PSCSICMD;
+typedef void *PVOID;
+typedef struct scatterlist *PSGL, SGL;
+
+
+/*;-----------------------------------------------------------------------*/
+typedef struct _SyncMsg
+{
+UCHAR ExtendMsg;
+UCHAR ExtMsgLen;
+UCHAR SyncXferReq;
+UCHAR Period;
+UCHAR ReqOffset;
+} SyncMsg;
+/*;-----------------------------------------------------------------------*/
+typedef struct _Capacity
+{
+ULONG BlockCount;
+ULONG BlockLength;
+} Capacity;
+/*;-----------------------------------------------------------------------*/
+typedef struct _SGentry
+{
+ULONG SGXferDataPtr;
+ULONG SGXferDataLen;
+} SGentry;
+
+typedef struct _SGentry1
+{
+ULONG SGXLen;
+ULONG SGXPtr;
+} SGentry1, *PSGE;
+
+
+#define MAX_ADAPTER_NUM 4
+#define MAX_DEVICES 10
+#define MAX_SG_LIST_BUF 16
+#define MAX_CMD_QUEUE 20
+#define MAX_CMD_PER_LUN 8
+#define MAX_SCSI_ID 8
+#define MAX_SRB_CNT MAX_CMD_QUEUE+4
+#define END_SCAN 2
+
+#define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */
+
+/*
+;-----------------------------------------------------------------------
+; SCSI Request Block
+;-----------------------------------------------------------------------
+*/
+struct _SRB
+{
+UCHAR CmdBlock[12];
+
+struct _SRB *pNextSRB;
+struct _DCB *pSRBDCB;
+PSCSICMD pcmd;
+PSGL pSegmentList;
+
+ULONG PhysSRB;
+ULONG TotalXferredLen;
+ULONG SGPhysAddr; /*;a segment starting address */
+ULONG SGToBeXferLen; /*; to be xfer length */
+
+SGL Segmentx; /* make a one entry of S/G list table */
+
+PUCHAR pMsgPtr;
+USHORT SRBState;
+USHORT Revxx2; /* ??? */
+
+UCHAR MsgInBuf[6];
+UCHAR MsgOutBuf[6];
+
+UCHAR AdaptStatus;
+UCHAR TargetStatus;
+UCHAR MsgCnt;
+UCHAR EndMessage;
+UCHAR TagNumber;
+UCHAR SGcount;
+UCHAR SGIndex;
+UCHAR IORBFlag; /*;81h-Reset, 2-retry */
+
+UCHAR SRBStatus;
+UCHAR RetryCnt;
+UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */
+ /*; b4-settimeout,b5-Residual valid */
+UCHAR ScsiCmdLen;
+UCHAR ScsiPhase;
+UCHAR Reserved3[3]; /*;for dword alignment */
+ULONG Segment0[2];
+ULONG Segment1[2];
+};
+
+typedef struct _SRB DC390_SRB, *PSRB;
+
+/*
+;-----------------------------------------------------------------------
+; Device Control Block
+;-----------------------------------------------------------------------
+*/
+struct _DCB
+{
+struct _DCB *pNextDCB;
+struct _ACB *pDCBACB;
+
+PSCSICMD pQIORBhead;
+PSCSICMD pQIORBtail;
+PSCSICMD AboIORBhead;
+PSCSICMD AboIORBtail;
+USHORT QIORBCnt;
+USHORT AboIORBcnt;
+
+PSRB pWaitingSRB;
+PSRB pWaitLast;
+PSRB pGoingSRB;
+PSRB pGoingLast;
+PSRB pActiveSRB;
+USHORT GoingSRBCnt;
+USHORT WaitSRBCnt; /* ??? */
+
+ULONG TagMask;
+
+USHORT MaxCommand;
+USHORT AdaptIndex; /*; UnitInfo struc start */
+USHORT UnitIndex; /*; nth Unit on this card */
+UCHAR UnitSCSIID; /*; SCSI Target ID (SCSI Only) */
+UCHAR UnitSCSILUN; /*; SCSI Log. Unit (SCSI Only) */
+
+UCHAR IdentifyMsg;
+UCHAR CtrlR1;
+UCHAR CtrlR3;
+UCHAR CtrlR4;
+
+UCHAR InqDataBuf[8];
+UCHAR CapacityBuf[8];
+UCHAR DevMode;
+UCHAR AdpMode;
+UCHAR SyncMode; /*; 0:async mode */
+UCHAR NegoPeriod; /*;for nego. */
+UCHAR SyncPeriod; /*;for reg. */
+UCHAR SyncOffset; /*;for reg. and nego.(low nibble) */
+UCHAR UnitCtrlFlag;
+UCHAR DCBFlag;
+UCHAR DevType;
+UCHAR Reserved2[3]; /*;for dword alignment */
+};
+
+typedef struct _DCB DC390_DCB, *PDCB;
+/*
+;-----------------------------------------------------------------------
+; Adapter Control Block
+;-----------------------------------------------------------------------
+*/
+struct _ACB
+{
+ULONG PhysACB;
+PSH pScsiHost;
+struct _ACB *pNextACB;
+USHORT IOPortBase;
+USHORT Revxx1; /* ??? */
+
+PDCB pLinkDCB;
+PDCB pDCBRunRobin;
+PDCB pActiveDCB;
+PDCB pDCB_free;
+PSRB pFreeSRB;
+PSRB pTmpSRB;
+USHORT SRBCount;
+USHORT AdapterIndex; /*; nth Adapter this driver */
+USHORT max_id;
+USHORT max_lun;
+
+UCHAR msgin123[4];
+UCHAR status;
+UCHAR AdaptSCSIID; /*; Adapter SCSI Target ID */
+UCHAR AdaptSCSILUN; /*; Adapter SCSI LUN */
+UCHAR DeviceCnt;
+UCHAR IRQLevel;
+UCHAR TagMaxNum;
+UCHAR ACBFlag;
+UCHAR Gmode2;
+UCHAR LUNchk;
+UCHAR scan_devices;
+UCHAR HostID_Bit;
+UCHAR Reserved1[1]; /*;for dword alignment */
+UCHAR DCBmap[MAX_SCSI_ID];
+DC390_DCB DCB_array[MAX_DEVICES]; /* +74h, Len=3E8 */
+DC390_SRB SRB_array[MAX_SRB_CNT]; /* +45Ch, Len= */
+DC390_SRB TmpSRB;
+};
+
+typedef struct _ACB DC390_ACB, *PACB;
+
+/*;-----------------------------------------------------------------------*/
+
+
+#define BIT31 0x80000000
+#define BIT30 0x40000000
+#define BIT29 0x20000000
+#define BIT28 0x10000000
+#define BIT27 0x08000000
+#define BIT26 0x04000000
+#define BIT25 0x02000000
+#define BIT24 0x01000000
+#define BIT23 0x00800000
+#define BIT22 0x00400000
+#define BIT21 0x00200000
+#define BIT20 0x00100000
+#define BIT19 0x00080000
+#define BIT18 0x00040000
+#define BIT17 0x00020000
+#define BIT16 0x00010000
+#define BIT15 0x00008000
+#define BIT14 0x00004000
+#define BIT13 0x00002000
+#define BIT12 0x00001000
+#define BIT11 0x00000800
+#define BIT10 0x00000400
+#define BIT9 0x00000200
+#define BIT8 0x00000100
+#define BIT7 0x00000080
+#define BIT6 0x00000040
+#define BIT5 0x00000020
+#define BIT4 0x00000010
+#define BIT3 0x00000008
+#define BIT2 0x00000004
+#define BIT1 0x00000002
+#define BIT0 0x00000001
+
+/*;---UnitCtrlFlag */
+#define UNIT_ALLOCATED BIT0
+#define UNIT_INFO_CHANGED BIT1
+#define FORMATING_MEDIA BIT2
+#define UNIT_RETRY BIT3
+
+/*;---UnitFlags */
+#define DASD_SUPPORT BIT0
+#define SCSI_SUPPORT BIT1
+#define ASPI_SUPPORT BIT2
+
+/*;----SRBState machine definition */
+#define SRB_FREE 0
+#define SRB_WAIT BIT0
+#define SRB_READY BIT1
+#define SRB_MSGOUT BIT2 /*;arbitration+msg_out 1st byte*/
+#define SRB_MSGIN BIT3
+#define SRB_MSGIN_MULTI BIT4
+#define SRB_COMMAND BIT5
+#define SRB_START_ BIT6 /*;arbitration+msg_out+command_out*/
+#define SRB_DISCONNECT BIT7
+#define SRB_DATA_XFER BIT8
+#define SRB_XFERPAD BIT9
+#define SRB_STATUS BIT10
+#define SRB_COMPLETED BIT11
+#define SRB_ABORT_SENT BIT12
+#define DO_SYNC_NEGO BIT13
+#define SRB_UNEXPECT_RESEL BIT14
+
+/*;---ACBFlag */
+#define RESET_DEV BIT0
+#define RESET_DETECT BIT1
+#define RESET_DONE BIT2
+
+/*;---DCBFlag */
+#define ABORT_DEV_ BIT0
+
+/*;---SRBstatus */
+#define SRB_OK BIT0
+#define ABORTION BIT1
+#define OVER_RUN BIT2
+#define UNDER_RUN BIT3
+#define PARITY_ERROR BIT4
+#define SRB_ERROR BIT5
+
+/*;---SRBFlag */
+#define DATAOUT BIT7
+#define DATAIN BIT6
+#define RESIDUAL_VALID BIT5
+#define ENABLE_TIMER BIT4
+#define RESET_DEV0 BIT2
+#define ABORT_DEV BIT1
+#define AUTO_REQSENSE BIT0
+
+/*;---Adapter status */
+#define H_STATUS_GOOD 0
+#define H_SEL_TIMEOUT 0x11
+#define H_OVER_UNDER_RUN 0x12
+#define H_UNEXP_BUS_FREE 0x13
+#define H_TARGET_PHASE_F 0x14
+#define H_INVALID_CCB_OP 0x16
+#define H_LINK_CCB_BAD 0x17
+#define H_BAD_TARGET_DIR 0x18
+#define H_DUPLICATE_CCB 0x19
+#define H_BAD_CCB_OR_SG 0x1A
+#define H_ABORT 0x0FF
+
+/*; SCSI Status byte codes*/
+#define SCSI_STAT_GOOD 0x0 /*; Good status */
+#define SCSI_STAT_CHECKCOND 0x02 /*; SCSI Check Condition */
+#define SCSI_STAT_CONDMET 0x04 /*; Condition Met */
+#define SCSI_STAT_BUSY 0x08 /*; Target busy status */
+#define SCSI_STAT_INTER 0x10 /*; Intermediate status */
+#define SCSI_STAT_INTERCONDMET 0x14 /*; Intermediate condition met */
+#define SCSI_STAT_RESCONFLICT 0x18 /*; Reservation conflict */
+#define SCSI_STAT_CMDTERM 0x22 /*; Command Terminated */
+#define SCSI_STAT_QUEUEFULL 0x28 /*; Queue Full */
+
+#define SCSI_STAT_UNEXP_BUS_F 0xFD /*; Unexpect Bus Free */
+#define SCSI_STAT_BUS_RST_DETECT 0xFE /*; Scsi Bus Reset detected */
+#define SCSI_STAT_SEL_TIMEOUT 0xFF /*; Selection Time out */
+
+/*;---Sync_Mode */
+#define SYNC_DISABLE 0
+#define SYNC_ENABLE BIT0
+#define SYNC_NEGO_DONE BIT1
+#define WIDE_ENABLE BIT2
+#define WIDE_NEGO_DONE BIT3
+#define EN_TAG_QUEUING BIT4
+#define EN_ATN_STOP BIT5
+
+#define SYNC_NEGO_OFFSET 15
+
+/*;---SCSI bus phase*/
+#define SCSI_DATA_OUT 0
+#define SCSI_DATA_IN 1
+#define SCSI_COMMAND 2
+#define SCSI_STATUS_ 3
+#define SCSI_NOP0 4
+#define SCSI_NOP1 5
+#define SCSI_MSG_OUT 6
+#define SCSI_MSG_IN 7
+
+/*;----SCSI MSG BYTE*/
+#define MSG_COMPLETE 0x00
+#define MSG_EXTENDED 0x01
+#define MSG_SAVE_PTR 0x02
+#define MSG_RESTORE_PTR 0x03
+#define MSG_DISCONNECT 0x04
+#define MSG_INITIATOR_ERROR 0x05
+#define MSG_ABORT 0x06
+#define MSG_REJECT_ 0x07
+#define MSG_NOP 0x08
+#define MSG_PARITY_ERROR 0x09
+#define MSG_LINK_CMD_COMPL 0x0A
+#define MSG_LINK_CMD_COMPL_FLG 0x0B
+#define MSG_BUS_RESET 0x0C
+#define MSG_ABORT_TAG 0x0D
+#define MSG_SIMPLE_QTAG 0x20
+#define MSG_HEAD_QTAG 0x21
+#define MSG_ORDER_QTAG 0x22
+#define MSG_IDENTIFY 0x80
+#define MSG_HOST_ID 0x0C0
+
+/*;----SCSI STATUS BYTE*/
+#define STATUS_GOOD 0x00
+#define CHECK_CONDITION_ 0x02
+#define STATUS_BUSY 0x08
+#define STATUS_INTERMEDIATE 0x10
+#define RESERVE_CONFLICT 0x18
+
+/* cmd->result */
+#define STATUS_MASK_ 0xFF
+#define MSG_MASK 0xFF00
+#define RETURN_MASK 0xFF0000
+
+/*
+** Inquiry Data format
+*/
+
+typedef struct _SCSIInqData { /* INQ */
+
+ UCHAR DevType; /* Periph Qualifier & Periph Dev Type*/
+ UCHAR RMB_TypeMod; /* rem media bit & Dev Type Modifier */
+ UCHAR Vers; /* ISO, ECMA, & ANSI versions */
+ UCHAR RDF; /* AEN, TRMIOP, & response data format*/
+ UCHAR AddLen; /* length of additional data */
+ UCHAR Res1; /* reserved */
+ UCHAR Res2; /* reserved */
+ UCHAR Flags; /* RelADr,Wbus32,Wbus16,Sync,etc. */
+ UCHAR VendorID[8]; /* Vendor Identification */
+ UCHAR ProductID[16]; /* Product Identification */
+ UCHAR ProductRev[4]; /* Product Revision */
+
+
+} SCSI_INQDATA, *PSCSI_INQDATA;
+
+
+/* Inquiry byte 0 masks */
+
+
+#define SCSI_DEVTYPE 0x1F /* Peripheral Device Type */
+#define SCSI_PERIPHQUAL 0xE0 /* Peripheral Qualifier */
+
+
+/* Inquiry byte 1 mask */
+
+#define SCSI_REMOVABLE_MEDIA 0x80 /* Removable Media bit (1=removable) */
+
+
+/* Peripheral Device Type definitions */
+
+#define SCSI_DASD 0x00 /* Direct-access Device */
+#define SCSI_SEQACESS 0x01 /* Sequential-access device */
+#define SCSI_PRINTER 0x02 /* Printer device */
+#define SCSI_PROCESSOR 0x03 /* Processor device */
+#define SCSI_WRITEONCE 0x04 /* Write-once device */
+#define SCSI_CDROM 0x05 /* CD-ROM device */
+#define SCSI_SCANNER 0x06 /* Scanner device */
+#define SCSI_OPTICAL 0x07 /* Optical memory device */
+#define SCSI_MEDCHGR 0x08 /* Medium changer device */
+#define SCSI_COMM 0x09 /* Communications device */
+#define SCSI_NODEV 0x1F /* Unknown or no device type */
+
+/*
+** Inquiry flag definitions (Inq data byte 7)
+*/
+
+#define SCSI_INQ_RELADR 0x80 /* device supports relative addressing*/
+#define SCSI_INQ_WBUS32 0x40 /* device supports 32 bit data xfers */
+#define SCSI_INQ_WBUS16 0x20 /* device supports 16 bit data xfers */
+#define SCSI_INQ_SYNC 0x10 /* device supports synchronous xfer */
+#define SCSI_INQ_LINKED 0x08 /* device supports linked commands */
+#define SCSI_INQ_CMDQUEUE 0x02 /* device supports command queueing */
+#define SCSI_INQ_SFTRE 0x01 /* device supports soft resets */
+
+
+/*
+;==========================================================
+; EEPROM byte offset
+;==========================================================
+*/
+typedef struct _EEprom
+{
+UCHAR EE_MODE1;
+UCHAR EE_SPEED;
+UCHAR xx1;
+UCHAR xx2;
+} EEprom, *PEEprom;
+
+#define EE_ADAPT_SCSI_ID 64
+#define EE_MODE2 65
+#define EE_DELAY 66
+#define EE_TAG_CMD_NUM 67
+
+/*; EE_MODE1 bits definition*/
+#define PARITY_CHK_ BIT0
+#define SYNC_NEGO_ BIT1
+#define EN_DISCONNECT_ BIT2
+#define SEND_START_ BIT3
+#define TAG_QUEUING_ BIT4
+
+/*; EE_MODE2 bits definition*/
+#define MORE2_DRV BIT0
+#define GREATER_1G BIT1
+#define RST_SCSI_BUS BIT2
+#define ACTIVE_NEGATION BIT3
+#define NO_SEEK BIT4
+#define LUN_CHECK BIT5
+
+#define ENABLE_CE 1
+#define DISABLE_CE 0
+#define EEPROM_READ 0x80
+
+/*
+;==========================================================
+; AMD 53C974 Registers bit Definition
+;==========================================================
+*/
+/*
+;====================
+; SCSI Register
+;====================
+*/
+
+/*; Command Reg.(+0CH) */
+#define DMA_COMMAND BIT7
+#define NOP_CMD 0
+#define CLEAR_FIFO_CMD 1
+#define RST_DEVICE_CMD 2
+#define RST_SCSI_BUS_CMD 3
+#define INFO_XFER_CMD 0x10
+#define INITIATOR_CMD_CMPLTE 0x11
+#define MSG_ACCEPTED_CMD 0x12
+#define XFER_PAD_BYTE 0x18
+#define SET_ATN_CMD 0x1A
+#define RESET_ATN_CMD 0x1B
+#define SELECT_W_ATN 0x42
+#define SEL_W_ATN_STOP 0x43
+#define EN_SEL_RESEL 0x44
+#define SEL_W_ATN2 0x46
+#define DATA_XFER_CMD INFO_XFER_CMD
+
+
+/*; SCSI Status Reg.(+10H) */
+#define INTERRUPT BIT7
+#define ILLEGAL_OP_ERR BIT6
+#define PARITY_ERR BIT5
+#define COUNT_2_ZERO BIT4
+#define GROUP_CODE_VALID BIT3
+#define SCSI_PHASE_MASK (BIT2+BIT1+BIT0)
+
+/*; Interrupt Status Reg.(+14H) */
+#define SCSI_RESET BIT7
+#define INVALID_CMD BIT6
+#define DISCONNECTED BIT5
+#define SERVICE_REQUEST BIT4
+#define SUCCESSFUL_OP BIT3
+#define RESELECTED BIT2
+#define SEL_ATTENTION BIT1
+#define SELECTED BIT0
+
+/*; Internal State Reg.(+18H) */
+#define SYNC_OFFSET_FLAG BIT3
+#define INTRN_STATE_MASK (BIT2+BIT1+BIT0)
+
+/*; Clock Factor Reg.(+24H) */
+#define CLK_FREQ_40MHZ 0
+#define CLK_FREQ_35MHZ (BIT2+BIT1+BIT0)
+#define CLK_FREQ_30MHZ (BIT2+BIT1)
+#define CLK_FREQ_25MHZ (BIT2+BIT0)
+#define CLK_FREQ_20MHZ BIT2
+#define CLK_FREQ_15MHZ (BIT1+BIT0)
+#define CLK_FREQ_10MHZ BIT1
+
+/*; Control Reg. 1(+20H) */
+#define EXTENDED_TIMING BIT7
+#define DIS_INT_ON_SCSI_RST BIT6
+#define PARITY_ERR_REPO BIT4
+#define SCSI_ID_ON_BUS (BIT2+BIT1+BIT0)
+
+/*; Control Reg. 2(+2CH) */
+#define EN_FEATURE BIT6
+#define EN_SCSI2_CMD BIT3
+
+/*; Control Reg. 3(+30H) */
+#define ID_MSG_CHECK BIT7
+#define EN_QTAG_MSG BIT6
+#define EN_GRP2_CMD BIT5
+#define FAST_SCSI BIT4 /* ;10MB/SEC */
+#define FAST_CLK BIT3 /* ;25 - 40 MHZ */
+
+/*; Control Reg. 4(+34H) */
+#define EATER_12NS 0
+#define EATER_25NS BIT7
+#define EATER_35NS BIT6
+#define EATER_0NS (BIT7+BIT6)
+#define NEGATE_REQACKDATA BIT2
+#define NEGATE_REQACK BIT3
+/*
+;====================
+; DMA Register
+;====================
+*/
+/*; DMA Command Reg.(+40H) */
+#define READ_DIRECTION BIT7
+#define WRITE_DIRECTION 0
+#define EN_DMA_INT BIT6
+#define MAP_TO_MDL BIT5
+#define DIAGNOSTIC BIT4
+#define DMA_IDLE_CMD 0
+#define DMA_BLAST_CMD BIT0
+#define DMA_ABORT_CMD BIT1
+#define DMA_START_CMD (BIT1+BIT0)
+
+/*; DMA Status Reg.(+54H) */
+#define PCI_MS_ABORT BIT6
+#define BLAST_COMPLETE BIT5
+#define SCSI_INTERRUPT BIT4
+#define DMA_XFER_DONE BIT3
+#define DMA_XFER_ABORT BIT2
+#define DMA_XFER_ERROR BIT1
+#define POWER_DOWN BIT0
+
+/*
+; DMA SCSI Bus and Ctrl.(+70H)
+;EN_INT_ON_PCI_ABORT
+*/
+
+/*
+;==========================================================
+; SCSI Chip register address offset
+;==========================================================
+*/
+#define CtcReg_Low 0x00
+#define CtcReg_Mid 0x04
+#define ScsiFifo 0x08
+#define ScsiCmd 0x0C
+#define Scsi_Status 0x10
+#define INT_Status 0x14
+#define Sync_Period 0x18
+#define Sync_Offset 0x1C
+#define CtrlReg1 0x20
+#define Clk_Factor 0x24
+#define CtrlReg2 0x2C
+#define CtrlReg3 0x30
+#define CtrlReg4 0x34
+#define CtcReg_High 0x38
+#define DMA_Cmd 0x40
+#define DMA_XferCnt 0x44
+#define DMA_XferAddr 0x48
+#define DMA_Wk_ByteCntr 0x4C
+#define DMA_Wk_AddrCntr 0x50
+#define DMA_Status 0x54
+#define DMA_MDL_Addr 0x58
+#define DMA_Wk_MDL_Cntr 0x5C
+#define DMA_ScsiBusCtrl 0x70
+
+#define StcReg_Low CtcReg_Low
+#define StcReg_Mid CtcReg_Mid
+#define Scsi_Dest_ID Scsi_Status
+#define Scsi_TimeOut INT_Status
+#define Intern_State Sync_Period
+#define Current_Fifo Sync_Offset
+#define StcReg_High CtcReg_High
+
+#define am_target Scsi_Status
+#define am_timeout INT_Status
+#define am_seq_step Sync_Period
+#define am_fifo_count Sync_Offset
+
+
+#define DC390_read8(address) \
+ inb(DC390_ioport + (address)))
+
+#define DC390_read16(address) \
+ inw(DC390_ioport + (address)))
+
+#define DC390_read32(address) \
+ inl(DC390_ioport + (address)))
+
+#define DC390_write8(address,value) \
+ outb((value), DC390_ioport + (address)))
+
+#define DC390_write16(address,value) \
+ outw((value), DC390_ioport + (address)))
+
+#define DC390_write32(address,value) \
+ outl((value), DC390_ioport + (address)))
+
+
+/* Configuration method #1 */
+#define PCI_CFG1_ADDRESS_REG 0xcf8
+#define PCI_CFG1_DATA_REG 0xcfc
+#define PCI_CFG1_ENABLE 0x80000000
+#define PCI_CFG1_TUPPLE(bus, device, function, register) \
+ (PCI_CFG1_ENABLE | (((bus) << 16) & 0xff0000) | \
+ (((device) << 11) & 0xf800) | (((function) << 8) & 0x700)| \
+ (((register) << 2) & 0xfc))
+
+/* Configuration method #2 */
+#define PCI_CFG2_ENABLE_REG 0xcf8
+#define PCI_CFG2_FORWARD_REG 0xcfa
+#define PCI_CFG2_ENABLE 0x0f0
+#define PCI_CFG2_TUPPLE(function) \
+ (PCI_CFG2_ENABLE | (((function) << 1) & 0xe))
+
+
+#endif /* TMSCSIM_H */
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index d89a90a7b..6a0076dde 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -1,6 +1,11 @@
/*
* u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
*
+ * 17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38
+ * Use of serial_number_at_timeout in abort and reset processing.
+ * Use of the __initfunc and __initdata macro in setup code.
+ * Minor cleanups in the list_statistics code.
+ *
* 24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26
* When loading as a module, parameter passing is now supported
* both in 2.0 and in 2.1 style.
@@ -220,10 +225,12 @@
* between increasing or decreasing by minimizing the seek distance between
* the sector of the commands just completed and the sector of the first
* command in the list to be sorted.
- * Trivial math assures that if there are (Q-1) outstanding request for
- * random seeks over S sectors, the unsorted average seek distance is S/2,
- * while the sorted average seek distance is S/(Q-1). The seek distance is
- * hence divided by a factor (Q-1)/2.
+ * Trivial math assures that the unsorted average seek distance when doing
+ * random seeks over S sectors is S/3.
+ * When (Q-1) requests are uniformly distributed over S sectors, the average
+ * distance between two adjacent requests is S/((Q-1) + 1), so the sorted
+ * average seek distance for (Q-1) random requests over S sectors is S/Q.
+ * The elevator sorting hence divides the seek distance by a factor Q/3.
* The above pure geometric remarks are valid in all cases and the
* driver effectively reduces the seek distance by the predicted factor
* when there are Q concurrent read i/o operations on the device, but this
@@ -273,8 +280,16 @@ MODULE_AUTHOR("Dario Ballabio");
#include <asm/dma.h>
#include <asm/irq.h>
#include "u14-34f.h"
-#include<linux/stat.h>
-#include<linux/config.h>
+#include <linux/stat.h>
+#include <linux/config.h>
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,36)
+#include <linux/init.h>
+#else
+#define __initfunc(A) A
+#define __initdata
+#define __init
+#endif
struct proc_dir_entry proc_scsi_u14_34f = {
PROC_SCSI_U14_34F, 6, "u14_34f",
@@ -419,7 +434,7 @@ static struct Scsi_Host *sh[MAX_BOARDS + 1];
static const char *driver_name = "Ux4F";
static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
-static unsigned int io_port[] = {
+static unsigned int io_port[] __initdata = {
/* Space for MAX_INT_PARAM ports usable while loading as a module */
SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
@@ -534,8 +549,7 @@ static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
return;
}
-static inline int wait_on_busy(unsigned int iobase) {
- unsigned int loop = MAXLOOP;
+static inline int wait_on_busy(unsigned int iobase, unsigned int loop) {
while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED)
if (--loop == 0) return TRUE;
@@ -556,7 +570,7 @@ static int board_inquiry(unsigned int j) {
cpp->scsi_cdbs_len = 6;
cpp->scsi_cdbs[0] = HA_CMD_INQUIRY;
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: board_inquiry, adapter busy.\n", BN(j));
return TRUE;
}
@@ -586,8 +600,8 @@ static int board_inquiry(unsigned int j) {
return FALSE;
}
-static inline int port_detect(unsigned int port_base, unsigned int j,
- Scsi_Host_Template *tpnt) {
+__initfunc (static inline int port_detect \
+ (unsigned int port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
unsigned char irq, dma_channel, subversion, i;
unsigned char in_byte;
char *bus_type, dma_name[16];
@@ -748,7 +762,7 @@ static inline int port_detect(unsigned int port_base, unsigned int j,
}
}
- if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "NO DMA");
+ if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST");
else sprintf(dma_name, "DMA %u", dma_channel);
for (i = 0; i < sh[j]->can_queue; i++)
@@ -781,7 +795,7 @@ static inline int port_detect(unsigned int port_base, unsigned int j,
return TRUE;
}
-void u14_34f_setup(char *str, int *ints) {
+__initfunc (void u14_34f_setup(char *str, int *ints)) {
int i, argc = ints[0];
char *cur = str, *pc;
@@ -813,7 +827,7 @@ void u14_34f_setup(char *str, int *ints) {
return;
}
-int u14_34f_detect(Scsi_Host_Template *tpnt) {
+__initfunc (int u14_34f_detect(Scsi_Host_Template *tpnt)) {
unsigned long flags;
unsigned int j = 0, k;
@@ -983,12 +997,12 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
if (linked_comm && SCpnt->device->queue_depth > 2
&& TLDEV(SCpnt->device->type)) {
HD(j)->cp_stat[i] = READY;
- flush_dev(SCpnt->device, 0, j, FALSE);
+ flush_dev(SCpnt->device, SCpnt->request.sector, j, FALSE);
restore_flags(flags);
return 0;
}
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
SCpnt->result = DID_ERROR << 16;
SCpnt->host_scribble = NULL;
printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy, DID_ERROR,"\
@@ -1018,7 +1032,8 @@ int u14_34f_abort(Scsi_Cmnd *SCarg) {
cli();
j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
- if (SCarg->host_scribble == NULL) {
+ if (SCarg->host_scribble == NULL
+ || SCarg->serial_number != SCarg->serial_number_at_timeout) {
printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
restore_flags(flags);
@@ -1032,7 +1047,7 @@ int u14_34f_abort(Scsi_Cmnd *SCarg) {
if (i >= sh[j]->can_queue)
panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: abort, timeout error.\n", BN(j));
restore_flags(flags);
return SCSI_ABORT_ERROR;
@@ -1101,13 +1116,19 @@ int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
if (SCarg->host_scribble == NULL)
printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
+ if (SCarg->serial_number != SCarg->serial_number_at_timeout) {
+ printk("%s: reset, pid %ld, reset not running.\n", BN(j), SCarg->pid);
+ restore_flags(flags);
+ return SCSI_RESET_NOT_RUNNING;
+ }
+
if (HD(j)->in_reset) {
printk("%s: reset, exit, already in reset.\n", BN(j));
restore_flags(flags);
return SCSI_RESET_ERROR;
}
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: reset, exit, timeout error.\n", BN(j));
restore_flags(flags);
return SCSI_RESET_ERROR;
@@ -1158,7 +1179,7 @@ int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
if (SCpnt == SCarg) arg_done = TRUE;
}
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: reset, cannot reset, timeout error.\n", BN(j));
restore_flags(flags);
return SCSI_RESET_ERROR;
@@ -1271,7 +1292,7 @@ static inline void reorder(unsigned int j, unsigned long cursec,
unsigned int rev = FALSE, s = TRUE, r = TRUE;
unsigned int input_only = TRUE, overlap = FALSE;
unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
- unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0;
+ unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
@@ -1282,8 +1303,8 @@ static inline void reorder(unsigned int j, unsigned long cursec,
printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\
" av %ldK as %ldK.\n", flushcount, batchcount, inputcount,
ovlcount, readycount, readysorted, sortcount, revcount,
- seeknosort / (readycount - batchcount + 1),
- seeksorted / (readycount - batchcount + 1));
+ seeknosort / (readycount + 1),
+ seeksorted / (readycount + 1));
if (n_ready <= 1) return;
@@ -1311,6 +1332,10 @@ static inline void reorder(unsigned int j, unsigned long cursec,
}
+ if (link_statistics) {
+ if (cursec > sl[0]) seek += cursec - sl[0]; else seek += sl[0] - cursec;
+ }
+
if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
@@ -1328,10 +1353,11 @@ static inline void reorder(unsigned int j, unsigned long cursec,
if (overlap) sort(pl, il, n_ready, FALSE);
if (link_statistics) {
+ if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
batchcount++; readycount += n_ready, seeknosort += seek / 1024;
if (input_only) inputcount++;
if (overlap) { ovlcount++; seeksorted += seek / 1024; }
- else seeksorted += (maxsec - minsec) / 1024;
+ else seeksorted += (iseek + maxsec - minsec) / 1024;
if (rev && !r) { revcount++; readysorted += n_ready; }
if (!rev && !s) { sortcount++; readysorted += n_ready; }
}
@@ -1375,7 +1401,7 @@ static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
for (n = 0; n < n_ready; n++) {
k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
- if (wait_on_busy(sh[j]->io_port)) {
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: %s, target %d.%d:%d, pid %ld, Mbox %d, adapter"\
" busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"),
SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k);
diff --git a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h
index 588259e10..9381f7729 100644
--- a/drivers/scsi/u14-34f.h
+++ b/drivers/scsi/u14-34f.h
@@ -11,7 +11,7 @@ int u14_34f_abort(Scsi_Cmnd *);
int u14_34f_reset(Scsi_Cmnd *, unsigned int);
int u14_34f_biosparam(Disk *, kdev_t, int *);
-#define U14_34F_VERSION "3.00.09"
+#define U14_34F_VERSION "3.10.00"
#define ULTRASTOR_14_34F { \
NULL, /* Ptr for modules */ \
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index 29d74ccea..14cb0f37a 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -84,24 +84,20 @@
#include "scsi.h"
#include "hosts.h"
+#define WD33C93_VERSION "1.24"
+#define WD33C93_DATE "29/Jan/1997"
-#define PROC_INTERFACE /* add code for /proc/scsi/wd33c93/xxx interface */
-#ifdef PROC_INTERFACE
-#define PROC_STATISTICS /* add code for keeping various real time stats */
-#endif
-
-#define SYNC_DEBUG /* extra info on sync negotiation printed */
-#undef DEBUGGING_ON /* enable command-line debugging bitmask */
-#define DEBUG_DEFAULTS 0 /* default debugging bitmask */
-
-#define WD33C93_VERSION "1.23"
-#define WD33C93_DATE "04/Nov/1996"
+/*
+ * Note - the following defines have been moved to 'wd33c93.h':
+ *
+ * PROC_INTERFACE
+ * PROC_STATISTICS
+ * SYNC_DEBUG
+ * DEBUGGING_ON
+ * DEBUG_DEFAULTS
+ *
+ */
-#ifdef DEBUGGING_ON
-#define DB(f,a) if (hostdata->args & (f)) (a)
-#else
-#define DB(f,a)
-#endif
#include "wd33c93.h"
@@ -162,7 +158,7 @@ static char *setup_strings[] =
{"","","","","","","","","","","",""};
-static inline uchar read_wd33c93(wd33c93_regs *regp, uchar reg_num)
+static inline uchar read_wd33c93(wd33c93_regs *regp,uchar reg_num)
{
regp->SASR = reg_num;
return regp->SCMD;
@@ -216,6 +212,31 @@ static inline unsigned long read_wd33c93_count(wd33c93_regs *regp)
return value;
}
+/* The 33c93 needs to be told which direction a command transfers its
+ * data; we use this function to figure it out. Returns true if there
+ * will be a DATA_OUT phase with this command, false otherwise.
+ * (Thanks to Joerg Dorchain for the research and suggestion.)
+ */
+static int is_dir_out(Scsi_Cmnd *cmd)
+{
+ switch (cmd->cmnd[0]) {
+ case WRITE_6: case WRITE_10: case WRITE_12:
+ case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER:
+ case WRITE_VERIFY: case WRITE_VERIFY_12:
+ case COMPARE: case COPY: case COPY_VERIFY:
+ case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW:
+ case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12:
+ case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE:
+ case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT:
+ case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK:
+ case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG:
+ case 0xea:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static struct sx_period sx_table[] = {
{ 1, 0x20},
{252, 0x20},
@@ -252,12 +273,13 @@ static inline uchar calc_sync_xfer(unsigned int period, unsigned int offset)
return result;
}
-void wd33c93_execute(struct Scsi_Host *instance);
+static void wd33c93_execute(struct Scsi_Host *instance);
int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
struct WD33C93_hostdata *hostdata = CMDHOSTDATA(cmd);
Scsi_Cmnd *tmp;
+ unsigned long flags;
disable_irq(cmd->host->irq);
DB(DB_QCMD,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid));
@@ -304,6 +326,10 @@ int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
* commands are added to the head of the queue so that the desired
* sense data is not lost before REQUEST_SENSE executes.
*/
+
+ save_flags(flags);
+ cli();
+
if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
cmd->host_scribble = (uchar *) hostdata->input_Q;
hostdata->input_Q = cmd;
@@ -322,7 +348,7 @@ int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
wd33c93_execute(cmd->host);
DB(DB_QCMD,printk(")Q-%ld ",cmd->pid));
- enable_irq(cmd->host->irq);
+ restore_flags(flags);
return 0;
}
@@ -330,17 +356,19 @@ int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
* already connected, we give up immediately. Otherwise, look through
* the input_Q, using the first command we find that's intended
* for a currently non-busy target/lun.
+ *
+ * wd33c93_execute() is always called with interrupts disabled or from
+ * the wd33c93_intr itself, which means that a wd33c93 interrupt
+ * cannot occur while we are in here.
*/
-void wd33c93_execute(struct Scsi_Host *instance)
+static void wd33c93_execute(struct Scsi_Host *instance)
{
struct WD33C93_hostdata *hostdata = INSTHOSTDATA(instance);
wd33c93_regs *regp = hostdata->regp;
Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->input_Q;
Scsi_Cmnd *prev = 0;
- unsigned long flags;
int i;
- disable_irq(instance->irq);
DB(DB_EXECUTE, printk("EX("));
if (hostdata->selecting || hostdata->connected) {
@@ -453,18 +481,16 @@ no:
* to the default/safe value. SS_UNSET means that the
* parameters are undetermined as yet, and that we
* need to send an SDTR message to this device after
- * selection is complete. We set SS_FIRST to tell the
- * interrupt routine to do so, unless we've been asked
- * not to try synchronous transfers on this target
- * (and _all_ luns within it): In this case we set
- * SS_SET to make the defaults final.
+ * selection is complete: We set SS_FIRST to tell the
+ * interrupt routine to do so. If we've been asked not to
+ * try synchronous transfers on this target (and _all_ luns
+ * within it), we'll still send the SDTR message later, but
+ * at that time we'll negotiate for async by specifying a
+ * sync fifo depth of 0.
*/
- if (hostdata->sync_stat[cmd->target] == SS_UNSET) {
- if (hostdata->no_sync & (1 << cmd->target))
- hostdata->sync_stat[cmd->target] = SS_SET;
- else
- hostdata->sync_stat[cmd->target] = SS_FIRST;
- }
+
+ if (hostdata->sync_stat[cmd->target] == SS_UNSET)
+ hostdata->sync_stat[cmd->target] = SS_FIRST;
hostdata->state = S_SELECTING;
/* guarantee a DATA_PHASE interrupt */
@@ -525,11 +551,10 @@ no:
*/
DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:":"", cmd->pid));
execute_out:
- enable_irq(instance->irq);
}
-void transfer_pio(wd33c93_regs *regp, uchar *buf, int cnt,
- int data_in_dir, struct WD33C93_hostdata *hostdata)
+static void transfer_pio(wd33c93_regs *regp, uchar *buf, int cnt,
+ int data_in_dir, struct WD33C93_hostdata *hostdata)
{
uchar asr;
@@ -561,6 +586,7 @@ void transfer_pio(wd33c93_regs *regp, uchar *buf, int cnt,
static void transfer_bytes(wd33c93_regs *regp, Scsi_Cmnd *cmd, int data_in_dir)
{
struct WD33C93_hostdata *hostdata = CMDHOSTDATA(cmd);
+ unsigned long length;
/* Normally, you'd expect 'this_residual' to be non-zero here.
* In a series of scatter-gather transfers, however, this
@@ -596,8 +622,7 @@ use_transfer_pio:
hostdata->pio_cnt++;
#endif
transfer_pio(regp, (uchar *)cmd->SCp.ptr,
- cmd->SCp.this_residual, cmd->SCp.this_residual,
- data_in_dir, hostdata);
+ cmd->SCp.this_residual, data_in_dir, hostdata);
length = cmd->SCp.this_residual;
cmd->SCp.this_residual = read_wd33c93_count(regp);
cmd->SCp.ptr += (length - cmd->SCp.this_residual);
@@ -637,13 +662,13 @@ void wd33c93_intr (struct Scsi_Host *instance)
wd33c93_regs *regp = hostdata->regp;
Scsi_Cmnd *patch, *cmd;
uchar asr, sr, phs, id, lun, *ucp, msg;
- unsigned long length;
+ unsigned long length, flags;
asr = READ_AUX_STAT();
if (!(asr & ASR_INT) || (asr & ASR_BSY))
return;
- save_flags(flags);
+ save_flags(flags);
#ifdef PROC_STATISTICS
hostdata->int_cnt++;
@@ -669,13 +694,13 @@ void wd33c93_intr (struct Scsi_Host *instance)
* interrupt normally.
*/
if (hostdata->dma == D_DMA_RUNNING) {
- DB(DB_TRANS,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual));
+ DB(DB_TRANSFER,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual));
hostdata->dma_stop(cmd->host, cmd, 1);
hostdata->dma = D_DMA_OFF;
length = cmd->SCp.this_residual;
cmd->SCp.this_residual = read_wd33c93_count(regp);
cmd->SCp.ptr += (length - cmd->SCp.this_residual);
- DB(DB_TRANS,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual));
+ DB(DB_TRANSFER,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual));
}
/* Respond to the specific WD3393 interrupt - there are quite a few! */
@@ -683,9 +708,6 @@ void wd33c93_intr (struct Scsi_Host *instance)
case CSR_TIMEOUT:
DB(DB_INTR, printk("TIMEOUT"));
-#ifndef NOINTS_IN_WDINTR
- disable_irq(instance->irq);
-#endif
if (hostdata->state == S_RUNNING_LEVEL2) {
hostdata->connected = NULL;
} else {
@@ -698,20 +720,25 @@ void wd33c93_intr (struct Scsi_Host *instance)
hostdata->state = S_UNCONNECTED;
cmd->scsi_done(cmd);
+ /* From esp.c:
+ * There is a window of time within the scsi_done() path
+ * of execution where interrupts are turned back on full
+ * blast and left that way. During that time we could
+ * reconnect to a disconnected command, then we'd bomb
+ * out below. We could also end up executing two commands
+ * at _once_. ...just so you know why the restore_flags()
+ * is here...
+ */
+ restore_flags(flags);
+
/* We are not connected to a target - check to see if there
* are commands waiting to be executed.
*/
-#ifndef NOINTS_IN_WDINTR
- enable_irq(instance->irq);
-#endif
wd33c93_execute(instance);
break;
case CSR_SELECT:
/* Note: this interrupt should not occur in a LEVEL2 command */
-#ifndef NOINTS_IN_WDINTR
- disable_irq(instance->irq);
-#endif
DB(DB_INTR, printk("SELECT"));
hostdata->connected = cmd = (Scsi_Cmnd *) hostdata->selecting;
hostdata->selecting = NULL;
@@ -726,14 +753,24 @@ void wd33c93_intr (struct Scsi_Host *instance)
#endif
hostdata->sync_stat[cmd->target] = SS_WAITING;
- /* tack on a 2nd message to ask about
- * synchronous transfers
- */
+ /* Tack on a 2nd message to ask about synchronous
+ transfers. If we've been asked to do only
+ asynchronous transfers on this device, we request a
+ fifo depth of 0, which is equivalent to async -
+ should solve the problems some people have had with
+ GVP's Guru ROM. */
+
hostdata->outgoing_msg[1] = EXTENDED_MESSAGE;
hostdata->outgoing_msg[2] = 3;
hostdata->outgoing_msg[3] = EXTENDED_SDTR;
- hostdata->outgoing_msg[4] = OPTIMUM_SX_PER/4;
- hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;
+ if (hostdata->no_sync & (1 << cmd->target)) {
+ hostdata->outgoing_msg[4] = hostdata->default_sx_per/4;
+ hostdata->outgoing_msg[5] = 0;
+ }
+ else {
+ hostdata->outgoing_msg[4] = OPTIMUM_SX_PER/4;
+ hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;
+ }
hostdata->outgoing_len = 6;
} else {
hostdata->outgoing_len = 1;
@@ -790,9 +827,6 @@ void wd33c93_intr (struct Scsi_Host *instance)
case CSR_SRV_REQ |PHS_MESS_IN:
DB(DB_INTR, printk("MSG_IN="));
-#ifndef NOINTS_IN_WDINTR
- disable_irq(instance->irq);
-#endif
msg = read_1_byte(regp);
sr = read_wd33c93(regp, WD_SCSI_STATUS); /* clear interrupt */
@@ -951,40 +985,11 @@ void wd33c93_intr (struct Scsi_Host *instance)
write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK);
hostdata->state = S_CONNECTED;
}
+ restore_flags(flags);
break;
-/* The 33c93 needs to be told which direction a command transfers its
- * data; we use this function to figure it out. Returns true if there
- * will be a DATA_OUT phase with this command, false otherwise.
- * (Thanks to Joerg Dorchain for the research and suggestion.)
- */
-static int is_dir_out(Scsi_Cmnd *cmd)
-{
- switch (cmd->cmnd[0]) {
- case WRITE_6: case WRITE_10: case WRITE_12:
- case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER:
- case WRITE_VERIFY: case WRITE_VERIFY_12:
- case COMPARE: case COPY: case COPY_VERIFY:
- case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW:
- case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12:
- case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE:
- case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT:
- case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK:
- case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG:
- case 0xea:
- return 1;
- default:
- return 0;
- }
-}
-
-
-
case CSR_SEL_XFER_DONE:
/* Note: this interrupt will occur only after a LEVEL2 command */
-#ifndef NOINTS_IN_WDINTR
- disable_irq(instance->irq);
-#endif
/* Make sure that reselection is enabled at this point - it may
* have been turned off for the command that just completed.
@@ -1010,7 +1015,7 @@ static int is_dir_out(Scsi_Cmnd *cmd)
/* We are no longer connected to a target - check to see if
* there are commands waiting to be executed.
*/
- enable_irq(instance->irq);
+ restore_flags(flags);
wd33c93_execute(instance);
} else {
printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE "
@@ -1062,9 +1067,6 @@ static int is_dir_out(Scsi_Cmnd *cmd)
* in a legal manner (like a command that provokes a request-sense),
* so we treat it as a normal command-complete-disconnect.
*/
-#ifndef NOINTS_IN_WDINTR
- disable_irq(instance->irq);
-#endif
/* Make sure that reselection is enabled at this point - it may
* have been turned off for the command that just completed.
@@ -1088,15 +1090,12 @@ static int is_dir_out(Scsi_Cmnd *cmd)
/* We are no longer connected to a target - check to see if
* there are commands waiting to be executed.
*/
- enable_irq(instance->irq);
wd33c93_execute(instance);
+ /* look above for comments on scsi_done() */
+ restore_flags(flags);
break;
case CSR_DISC:
-#ifndef NOINTS_IN_WDINTR
- disable_irq(instance->irq);
-#endif
-
/* Make sure that reselection is enabled at this point - it may
* have been turned off for the command that just completed.
*/
@@ -1118,6 +1117,7 @@ static int is_dir_out(Scsi_Cmnd *cmd)
cmd->result = ((cmd->result & 0x00ffff) |
(DID_ERROR << 16));
cmd->scsi_done(cmd);
+ restore_flags(flags);
break;
case S_PRE_TMP_DISC:
case S_RUNNING_LEVEL2:
@@ -1134,7 +1134,6 @@ static int is_dir_out(Scsi_Cmnd *cmd)
printk("*** Unexpected DISCONNECT interrupt! ***");
hostdata->state = S_UNCONNECTED;
}
- enable_irq(instance->irq);
/* We are no longer connected to a target - check to see if
* there are commands waiting to be executed.
*/
@@ -1144,9 +1143,6 @@ static int is_dir_out(Scsi_Cmnd *cmd)
case CSR_RESEL_AM:
DB(DB_INTR,printk("RESEL"));
-#ifndef NOINTS_IN_WDINTR
- disable_irq(instance->irq);
-#endif
/* First we have to make sure this reselection didn't
* happen during Arbitration/Selection of some other device.
* If yes, put losing command back on top of input_Q.
@@ -1241,12 +1237,12 @@ static int is_dir_out(Scsi_Cmnd *cmd)
printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--", asr, sr, phs);
}
-#ifndef NOINTS_IN_WDINTR
- enable_irq(instance->irq);
-#endif
DB(DB_INTR,printk("} "));
}
+/*
+ * Not static 'cause called from outside ...
+ */
void reset_wd33c93(struct Scsi_Host *instance)
{
struct WD33C93_hostdata *hostdata = INSTHOSTDATA(instance);
@@ -1508,7 +1504,7 @@ void wd33c93_setup (char *str, int *ints)
}
/* check_setup_strings() returns index if key found, 0 if not */
-int check_setup_strings(char *key, int *flags, int *val, char *buf)
+static int check_setup_strings(char *key, int *flags, int *val, char *buf)
{
int x;
char *cp;
@@ -1634,10 +1630,9 @@ void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs,
printk("WD93: Driver version %s ", WD33C93_VERSION);
printk("compiled on %s at %s\n", __DATE__, __TIME__);
#ifdef DEBUGGING_ON
- printk(" debug_flags=0x%02x setup_strings=",
- hostdata->args);
+ printk(" debug_flags=0x%02x\n",hostdata->args);
#else
- printk(" debugging=OFF setup_strings=");
+ printk(" debugging=OFF\n");
#endif
#if 0
printk("wd33c93-%d: setup_strings=", instance->host_no);
@@ -1649,7 +1644,7 @@ void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs,
#endif
}
- printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d\n",
+ printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d",
instance->host_no,
(hostdata->chip==C_WD33C93)?"WD33c93":
(hostdata->chip==C_WD33C93A)?"WD33c93A":
@@ -1659,9 +1654,6 @@ void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs,
MOD_INC_USE_COUNT;
}
-
-}
-
int wd33c93_proc_info(char *buf, char **start, off_t off, int len, int hn, int in)
{
#ifdef PROC_INTERFACE
diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h
index 3a2cec4ab..3b8b4cf3a 100644
--- a/drivers/scsi/wd33c93.h
+++ b/drivers/scsi/wd33c93.h
@@ -246,13 +246,17 @@ struct WD33C93_hostdata {
uchar sync_stat[8]; /* status of sync negotiation per target */
uchar no_sync; /* bitmask: don't do sync on these targets */
uchar no_dma; /* set this flag to disable DMA */
+#ifdef PROC_INTERFACE
uchar proc; /* bitmask: what's in proc output */
+#ifdef PROC_STATISTICS
unsigned long cmd_cnt[8]; /* # of commands issued per target */
unsigned long int_cnt; /* # of interrupts serviced */
unsigned long pio_cnt; /* # of pio data transfers */
unsigned long dma_cnt; /* # of DMA data transfers */
unsigned long disc_allowed_cnt[8]; /* # of disconnects allowed per target */
unsigned long disc_done_cnt[8]; /* # of disconnects done per target*/
+#endif
+#endif
};
#define CMDHOSTDATA(cmd) ((struct WD33C93_hostdata *) (cmd)->host->hostdata)
@@ -302,7 +306,7 @@ struct WD33C93_hostdata {
#define DB_QCMD (1<<2)
#define DB_EXECUTE (1<<3)
#define DB_INTR (1<<4)
-#define DB_TRANS (1<<5)
+#define DB_TRANSFER (1<<5)
#define DB_MASK (0x3f)
/* defines for hostdata->sync_stat[] */
diff --git a/drivers/sgi/char/sgicons.c b/drivers/sgi/char/sgicons.c
index c5051702d..097ed1359 100644
--- a/drivers/sgi/char/sgicons.c
+++ b/drivers/sgi/char/sgicons.c
@@ -1,14 +1,15 @@
-/* $Id: sgicons.c,v 1.6 1996/07/29 11:10:22 dm Exp $
+/*
* sgicons.c: Setting up and registering console I/O on the SGI.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*/
+#include <linux/init.h>
#include <linux/kernel.h>
extern void newport_init(void);
extern unsigned long video_mem_base, video_screen_size, video_mem_term;
-unsigned long con_type_init(unsigned long start_mem, const char **name)
+__initfunc(unsigned long con_type_init(unsigned long start_mem, const char **name))
{
extern int serial_console;
@@ -26,3 +27,7 @@ unsigned long con_type_init(unsigned long start_mem, const char **name)
return start_mem;
}
+
+__initfunc(void con_type_init_finish(void))
+{
+}
diff --git a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c
index 843870e94..c48c9ac45 100644
--- a/drivers/sgi/char/sgiserial.c
+++ b/drivers/sgi/char/sgiserial.c
@@ -31,6 +31,8 @@
#define NUM_SERIAL 1 /* One chip on board. */
#define NUM_CHANNELS (NUM_SERIAL * 2)
+extern struct wait_queue * keypress_wait;
+
struct sgi_zslayout *zs_chips[NUM_SERIAL] = { 0, };
struct sgi_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, };
struct sgi_zschannel *zs_conschan;
@@ -351,7 +353,7 @@ static _INLINE_ void rs_sched_event(struct sgi_serial *info,
int event)
{
info->event |= 1 << event;
- queue_task_irq_off(&info->tqueue, &tq_serial);
+ queue_task(&info->tqueue, &tq_serial);
mark_bh(SERIAL_BH);
}
@@ -400,7 +402,7 @@ static _INLINE_ void receive_chars(struct sgi_serial *info, struct pt_regs *regs
goto clear_and_exit;
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+ queue_task(&tty->flip.tqueue, &tq_timer);
tty->flip.count++;
if(stat & PAR_ERR)
*tty->flip.flag_buf_ptr++ = TTY_PARITY;
@@ -412,7 +414,7 @@ static _INLINE_ void receive_chars(struct sgi_serial *info, struct pt_regs *regs
*tty->flip.flag_buf_ptr++ = 0; /* XXX */
*tty->flip.char_buf_ptr++ = ch;
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+ queue_task(&tty->flip.tqueue, &tq_timer);
clear_and_exit:
rs_recv_clear(info->zs_channel);
@@ -596,7 +598,7 @@ static void do_softint(void *private_)
if (!tty)
return;
- if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in
index f7567a496..fb8a76753 100644
--- a/drivers/sound/Config.in
+++ b/drivers/sound/Config.in
@@ -1,277 +1,15 @@
-bool 'ProAudioSpectrum 16 support' CONFIG_PAS
-bool '_TRUE_ Sound Blaster (SB, SBPro, SB16/32/64, ESS, Jazz16) support' CONFIG_SB
-bool 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB
-bool 'Gravis Ultrasound support' CONFIG_GUS
-bool 'MPU-401 support (NOT for SB16)' CONFIG_MPU401
-bool 'PSS (ECHO-ADI2111) support' CONFIG_PSS
-bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16
-bool 'GUS MAX support' CONFIG_GUSMAX
-bool 'Microsoft Sound System support' CONFIG_MSS
-bool 'Ensoniq SoundScape support' CONFIG_SSCAPE
-bool 'MediaTrix AudioTrix Pro support' CONFIG_TRIX
-bool 'Support for MAD16 and/or Mozart based cards' CONFIG_MAD16
-bool 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232
-bool 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI
-bool 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812
-
-if [ "$CONFIG_AEDSP16" = "y" ]; then
-hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220
-fi
-
-if [ "$CONFIG_SB" = "y" ]; then
-hex 'I/O base for SB Check from manual of the card' SBC_BASE 220
-fi
-
-if [ "$CONFIG_SB" = "y" ]; then
-int 'Sound Blaster IRQ Check from manual of the card' SBC_IRQ 7
-fi
-
-if [ "$CONFIG_SB" = "y" ]; then
-int 'Sound Blaster DMA 0, 1 or 3' SBC_DMA 1
-fi
-
-if [ "$CONFIG_SB" = "y" ]; then
-int 'Sound Blaster 16 bit DMA (SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' SB_DMA2 5
-fi
-
-if [ "$CONFIG_SB" = "y" ]; then
-hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' SB_MPU_BASE 330
-fi
-
-
-if [ "$CONFIG_SB" = "y" ]; then
-comment 'MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688.'
-fi
-
-
-if [ "$CONFIG_SB" = "y" ]; then
-comment 'Enter -1 to the following question if you have something else such as SB16/32.'
-fi
-
-if [ "$CONFIG_SB" = "y" ]; then
-int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' SB_MPU_IRQ -1
-fi
-
-if [ "$CONFIG_PAS" = "y" ]; then
-int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' PAS_IRQ 10
-fi
-
-if [ "$CONFIG_PAS" = "y" ]; then
-int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' PAS_DMA 3
-fi
-
-if [ "$CONFIG_GUS" = "y" ]; then
-hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' GUS_BASE 220
-fi
-
-if [ "$CONFIG_GUS" = "y" ]; then
-int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' GUS_IRQ 15
-fi
-
-if [ "$CONFIG_GUS" = "y" ]; then
-int 'GUS DMA 1, 3, 5, 6 or 7' GUS_DMA 6
-fi
-
-if [ "$CONFIG_GUS" = "y" ]; then
-int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' GUS_DMA2 -1
-fi
-
-if [ "$CONFIG_GUS16" = "y" ]; then
-hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' GUS16_BASE 530
-fi
-
-if [ "$CONFIG_GUS16" = "y" ]; then
-int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' GUS16_IRQ 7
-fi
-
-if [ "$CONFIG_GUS16" = "y" ]; then
-int 'GUS DMA 0, 1 or 3' GUS16_DMA 3
-fi
-
-if [ "$CONFIG_MPU401" = "y" ]; then
-hex 'I/O base for MPU401 Check from manual of the card' MPU_BASE 330
-fi
-
-if [ "$CONFIG_MPU401" = "y" ]; then
-int 'MPU401 IRQ Check from manual of the card' MPU_IRQ 9
-fi
-
-
-if [ "$CONFIG_MAUI" = "y" ]; then
-comment 'ERROR! You have to use old sound configuration method with Maui.'
-fi
-
-if [ "$CONFIG_MAUI" = "y" ]; then
-hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' MAUI_BASE 330
-fi
-
-if [ "$CONFIG_MAUI" = "y" ]; then
-int 'Maui IRQ 5, 9, 12 or 15' MAUI_IRQ 9
-fi
-
-if [ "$CONFIG_UART6850" = "y" ]; then
-hex 'I/O base for UART 6850 MIDI port (Unknown)' U6850_BASE 0
-fi
-
-if [ "$CONFIG_UART6850" = "y" ]; then
-int 'UART6850 IRQ (Unknown)' U6850_IRQ -1
-fi
-
-
-if [ "$CONFIG_PSS" = "y" ]; then
-comment 'ERROR! You have to use old sound configuration method with PSS cards.'
-fi
-
-if [ "$CONFIG_PSS" = "y" ]; then
-hex 'PSS I/O base 220 or 240' PSS_BASE 220
-fi
-
-if [ "$CONFIG_PSS" = "y" ]; then
-hex 'PSS audio I/O base 530, 604, E80 or F40' PSS_MSS_BASE 530
-fi
-
-if [ "$CONFIG_PSS" = "y" ]; then
-int 'PSS audio IRQ 7, 9, 10 or 11' PSS_MSS_IRQ 11
-fi
-
-if [ "$CONFIG_PSS" = "y" ]; then
-int 'PSS audio DMA 0, 1 or 3' PSS_MSS_DMA 3
-fi
-
-if [ "$CONFIG_PSS" = "y" ]; then
-hex 'PSS MIDI I/O base ' PSS_MPU_BASE 330
-fi
-
-if [ "$CONFIG_PSS" = "y" ]; then
-int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' PSS_MPU_IRQ 9
-fi
-
-if [ "$CONFIG_MSS" = "y" ]; then
-hex 'MSS/WSS I/O base 530, 604, E80 or F40' MSS_BASE 530
-fi
-
-if [ "$CONFIG_MSS" = "y" ]; then
-int 'MSS/WSS IRQ 7, 9, 10 or 11' MSS_IRQ 11
-fi
-
-if [ "$CONFIG_MSS" = "y" ]; then
-int 'MSS/WSS DMA 0, 1 or 3' MSS_DMA 3
-fi
-
-if [ "$CONFIG_MSS" = "y" ]; then
-int 'MSS/WSS second DMA (if possible) 0, 1 or 3' MSS_DMA2 -1
-fi
-
-if [ "$CONFIG_SSCAPE" = "y" ]; then
-hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' SSCAPE_BASE 330
-fi
-
-if [ "$CONFIG_SSCAPE" = "y" ]; then
-int 'SoundScape MIDI IRQ ' SSCAPE_IRQ 9
-fi
-
-if [ "$CONFIG_SSCAPE" = "y" ]; then
-int 'SoundScape initialization DMA 0, 1 or 3' SSCAPE_DMA 3
-fi
-
-if [ "$CONFIG_SSCAPE" = "y" ]; then
-hex 'SoundScape audio I/O base 534, 608, E84 or F44' SSCAPE_MSS_BASE 534
-fi
-
-if [ "$CONFIG_SSCAPE" = "y" ]; then
-int 'SoundScape audio IRQ 7, 9, 10 or 11' SSCAPE_MSS_IRQ 11
-fi
-
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-comment 'ERROR! You have to use old sound configuration method with AudioTrix.'
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-hex 'AudioTrix audio I/O base 530, 604, E80 or F40' TRIX_BASE 530
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-int 'AudioTrix audio IRQ 7, 9, 10 or 11' TRIX_IRQ 11
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-int 'AudioTrix audio DMA 0, 1 or 3' TRIX_DMA 0
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-int 'AudioTrix second (duplex) DMA 0, 1 or 3' TRIX_DMA2 3
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-hex 'AudioTrix MIDI I/O base 330, 370, 3B0 or 3F0' TRIX_MPU_BASE 330
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-int 'AudioTrix MIDI IRQ 3, 4, 5, 7 or 9' TRIX_MPU_IRQ 9
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-hex 'AudioTrix SB I/O base 220, 210, 230, 240, 250, 260 or 270' TRIX_SB_BASE 220
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-int 'AudioTrix SB IRQ 3, 4, 5 or 7' TRIX_SB_IRQ 7
-fi
-
-if [ "$CONFIG_TRIX" = "y" ]; then
-int 'AudioTrix SB DMA 1 or 3' TRIX_SB_DMA 1
-fi
-
-if [ "$CONFIG_CS4232" = "y" ]; then
-hex 'CS4232 audio I/O base 530, 604, E80 or F40' CS4232_BASE 530
-fi
-
-if [ "$CONFIG_CS4232" = "y" ]; then
-int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CS4232_IRQ 11
-fi
-
-if [ "$CONFIG_CS4232" = "y" ]; then
-int 'CS4232 audio DMA 0, 1 or 3' CS4232_DMA 0
-fi
-
-if [ "$CONFIG_CS4232" = "y" ]; then
-int 'CS4232 second (duplex) DMA 0, 1 or 3' CS4232_DMA2 3
-fi
-
-if [ "$CONFIG_CS4232" = "y" ]; then
-hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CS4232_MPU_BASE 330
-fi
-
-if [ "$CONFIG_CS4232" = "y" ]; then
-int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CS4232_MPU_IRQ 9
-fi
-
-if [ "$CONFIG_MAD16" = "y" ]; then
-hex 'MAD16 audio I/O base 530, 604, E80 or F40' MAD16_BASE 530
-fi
-
-if [ "$CONFIG_MAD16" = "y" ]; then
-int 'MAD16 audio IRQ 7, 9, 10 or 11' MAD16_IRQ 11
-fi
-
-if [ "$CONFIG_MAD16" = "y" ]; then
-int 'MAD16 audio DMA 0, 1 or 3' MAD16_DMA 3
-fi
-
-if [ "$CONFIG_MAD16" = "y" ]; then
-int 'MAD16 second (duplex) DMA 0, 1 or 3' MAD16_DMA2 0
-fi
-
-if [ "$CONFIG_MAD16" = "y" ]; then
-hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' MAD16_MPU_BASE 330
-fi
-
-if [ "$CONFIG_MAD16" = "y" ]; then
-int 'MAD16 MIDI IRQ 5, 7, 9 or 10' MAD16_MPU_IRQ 9
-fi
#
-$MAKE -C drivers/sound kernelconfig || exit 1
+# Sound driver configuration
+#
+#--------
+# There is another confic script which is compatible with rest of
+# the kernel. It can be activated by running 'make mkscript' in this
+# directory. Please note that this is an _experimental_ feature which
+# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui).
+#--------
+#
+$MAKE -C drivers/sound config || exit 1
+
bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND
if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
diff --git a/drivers/sound/lowlevel/.cvsignore b/drivers/sound/lowlevel/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/drivers/sound/lowlevel/.cvsignore
@@ -0,0 +1 @@
+.depend