From b6e9c71946f808f012cfc7b89923b9549eb1ac3a Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:10:31 -0500 Subject: [PATCH] Import 1.3.58 --- CREDITS | 9 +- Documentation/Configure.help | 6 +- Documentation/cdrom/optcd | 4 + MAGIC | 2 +- Makefile | 2 +- Rules.make | 2 +- arch/alpha/config.in | 7 + arch/alpha/kernel/Makefile | 13 +- arch/alpha/kernel/ksyms.c | 55 + arch/i386/config.in | 7 + arch/i386/defconfig | 4 +- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/ksyms.c | 17 + arch/i386/kernel/setup.c | 2 +- arch/mips/config.in | 7 + arch/sparc/config.in | 3 + drivers/block/Config.in | 9 +- drivers/block/Makefile | 4 + drivers/block/README.ide | 10 +- drivers/block/cmd640.c | 152 +- drivers/block/ide-cd.c | 1 - drivers/block/ide-tape.c | 2 - drivers/block/ide.c | 78 +- drivers/block/ide.h | 9 +- drivers/block/triton.c | 136 +- drivers/cdrom/mcdx.c | 22 +- drivers/cdrom/optcd.c | 2803 +++++----- drivers/cdrom/optcd_isp16.h | 337 ++ drivers/char/Config.in | 1 + drivers/char/Makefile | 15 +- drivers/char/apm_bios.c | 162 +- drivers/char/keyboard.c | 18 +- drivers/char/mouse.c | 11 +- drivers/char/tga.c | 3 + drivers/char/tpqic02.c | 2 - drivers/char/tty_io.c | 17 +- drivers/char/wd501p.h | 2 + drivers/net/Config.in | 2 +- drivers/net/Makefile | 4 +- drivers/net/README.tunnel | 4 +- drivers/net/ne.c | 52 +- drivers/net/seeq8005.h | 4 +- drivers/net/slhc.c | 25 + drivers/pci/pci.c | 1 + drivers/scsi/Config.in | 4 +- drivers/scsi/Makefile | 9 + drivers/scsi/advansys.c | 9061 ++++++++++++++++++++++++++++++++ drivers/scsi/advansys.h | 131 + drivers/scsi/aha1542.c | 3 - drivers/scsi/aic7xxx.seq | 6 +- drivers/scsi/hosts.c | 7 + drivers/scsi/scsi.c | 11 +- drivers/scsi/scsi_debug.c | 3 - drivers/sound/.blurb | 4 - drivers/sound/.objects | 14 +- drivers/sound/.version | 2 +- drivers/sound/CHANGELOG | 34 +- drivers/sound/Config.in | 8 +- drivers/sound/Makefile | 51 +- drivers/sound/Readme | 10 +- drivers/sound/Readme.cards | 59 +- drivers/sound/Readme.modules | 11 + drivers/sound/ad1848.c | 159 +- drivers/sound/ad1848_mixer.h | 25 +- drivers/sound/adlib_card.c | 2 +- drivers/sound/aedsp16.c | 6 +- drivers/sound/audio.c | 145 +- drivers/sound/configure.c | 1551 +++--- drivers/sound/cs4232.c | 23 +- drivers/sound/dev_table.c | 94 +- drivers/sound/dev_table.h | 111 +- drivers/sound/dmabuf.c | 339 +- drivers/sound/experimental.txt | 165 - drivers/sound/gus_card.c | 21 +- drivers/sound/gus_midi.c | 56 +- drivers/sound/gus_vol.c | 2 +- drivers/sound/gus_wave.c | 27 +- drivers/sound/ics2101.c | 4 +- drivers/sound/mad16.c | 20 +- drivers/sound/mad16_sb_midi.c | 24 +- drivers/sound/maui.c | 14 +- drivers/sound/midi_synth.c | 20 +- drivers/sound/midi_synth.h | 1 - drivers/sound/midibuf.c | 79 +- drivers/sound/mpu401.c | 30 +- drivers/sound/opl3.c | 26 +- drivers/sound/os.h | 18 +- drivers/sound/pas2_card.c | 21 +- drivers/sound/pas2_midi.c | 6 +- drivers/sound/pas2_mixer.c | 4 +- drivers/sound/pas2_pcm.c | 6 +- drivers/sound/patmgr.c | 95 +- drivers/sound/pss.c | 17 +- drivers/sound/sb16_dsp.c | 60 +- drivers/sound/sb16_midi.c | 65 +- drivers/sound/sb_card.c | 8 +- drivers/sound/sb_dsp.c | 672 ++- drivers/sound/sb_midi.c | 2 +- drivers/sound/sb_mixer.c | 28 +- drivers/sound/sb_mixer.h | 33 +- drivers/sound/sequencer.c | 100 +- drivers/sound/sound_calls.h | 16 +- drivers/sound/sound_config.h | 29 +- drivers/sound/sound_pnp.c | 2 +- drivers/sound/sound_switch.c | 51 +- drivers/sound/sound_timer.c | 5 +- drivers/sound/soundcard.c | 238 +- drivers/sound/soundvers.h | 2 +- drivers/sound/sscape.c | 69 +- drivers/sound/sys_timer.c | 6 +- drivers/sound/trix.c | 14 +- drivers/sound/uart6850.c | 13 +- drivers/sound/ulaw.h | 133 +- fs/Config.in | 1 + fs/buffer.c | 123 +- fs/ext/inode.c | 13 +- fs/ext2/CHANGES | 2 + fs/ext2/ioctl.c | 5 +- fs/ext2/super.c | 14 +- fs/filesystems.c | 45 +- fs/hpfs/hpfs_fs.c | 14 +- fs/isofs/inode.c | 14 +- fs/minix/inode.c | 14 +- fs/msdos/Makefile | 3 +- fs/msdos/inode.c | 44 +- fs/ncpfs/dir.c | 24 +- fs/ncpfs/inode.c | 18 +- fs/nfs/inode.c | 14 +- fs/nfs/nfsroot.c | 10 +- fs/proc/Makefile | 8 +- fs/proc/inode.c | 3 - fs/proc/net.c | 6 +- fs/proc/procfs_syms.c | 35 + fs/proc/scsi.c | 4 +- fs/smbfs/inode.c | 18 +- fs/smbfs/proc.c | 2 +- fs/sysv/inode.c | 16 +- fs/umsdos/inode.c | 14 +- fs/xiafs/inode.c | 14 +- include/asm-alpha/param.h | 3 +- include/asm-i386/delay.h | 6 +- include/linux/blk.h | 4 +- include/linux/ext2_fs.h | 1 + include/linux/ext2_fs_sb.h | 2 + include/linux/ext_fs.h | 1 + include/linux/fs.h | 36 +- include/linux/hpfs_fs.h | 1 + include/linux/iso_fs.h | 1 + include/linux/locks.h | 38 + include/linux/mcdx.h | 2 +- include/linux/minix_fs.h | 1 + include/linux/mm.h | 22 +- include/linux/msdos_fs.h | 1 + include/linux/ncp_fs.h | 1 + include/linux/nfs_fs.h | 1 + include/linux/optcd.h | 216 +- include/linux/pagemap.h | 7 + include/linux/pci.h | 1 + include/linux/proc_fs.h | 2 + include/linux/quota.h | 2 - include/linux/sched.h | 2 + include/linux/smb_fs.h | 1 + include/linux/soundcard.h | 40 +- include/linux/swapctl.h | 11 + include/linux/sysctl.h | 1 + include/linux/sysv_fs.h | 1 + include/linux/umsdos_fs.h | 1 + include/linux/wrapper.h | 40 + include/linux/xia_fs.h | 1 + include/net/route.h | 2 + init/main.c | 6 + ipc/msg.c | 6 +- ipc/util.c | 3 + kernel/ksyms.c | 169 +- kernel/sched.c | 3 + kernel/sysctl.c | 28 +- mm/filemap.c | 101 +- mm/swap.c | 2 + mm/vmscan.c | 15 +- net/Config.in | 1 + net/ipv4/proc.c | 1 - net/ipv4/tcp.c | 16 +- scripts/Configure | 32 + scripts/tkparse.c | 7 + scripts/tkparse.h | 2 + 185 files changed, 15116 insertions(+), 4316 deletions(-) create mode 100644 arch/alpha/kernel/ksyms.c create mode 100644 arch/i386/kernel/ksyms.c create mode 100644 drivers/cdrom/optcd_isp16.h create mode 100644 drivers/scsi/advansys.c create mode 100644 drivers/scsi/advansys.h delete mode 100644 drivers/sound/experimental.txt create mode 100644 fs/proc/procfs_syms.c create mode 100644 include/linux/wrapper.h diff --git a/CREDITS b/CREDITS index 5593317e725d..c303b0edbf98 100644 --- a/CREDITS +++ b/CREDITS @@ -149,7 +149,7 @@ S: USA N: Andries Brouwer E: aeb@cwi.nl -D: International character handling for keyboard and console +D: random Linux hacker S: Bessemerstraat 21 S: Amsterdam S: The Netherlands @@ -601,7 +601,7 @@ S: Boulder, Colorado 80303 S: USA N: H.J. Lu -E: hjl@nynexst.com +E: hjl@gnu.ai.mit.edu D: GCC + libraries hacker N: Tuomas J. Lukka @@ -722,7 +722,7 @@ S: Muskego, Wisconsin 53150 S: USA N: Harald Milz -E: hm@ix.de +E: hm@seneca.linux.de D: Linux Projects Map, Linux Commercial-HOWTO D: general Linux publicity in Germany, vacation port D: UUCP and CNEWS binary packages for LST @@ -894,7 +894,8 @@ S: B2240 Zandhoven S: Belgium N: Martin Schulze -E: joey@infodrom.north.de +E: joey@linux.de +W: http://home.pages.de/~joey/ D: Random Linux Hacker, Linux Promoter D: CD-List, Books-List, Ex-FAQ D: Linux-Support, -Mailbox, -Stammtisch diff --git a/Documentation/Configure.help b/Documentation/Configure.help index de9864ef069f..d30ce7a5bcf9 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -221,7 +221,7 @@ CONFIG_MAX_16M This is for some buggy motherboards which cannot properly deal with the memory above 16MB. If you have more than 16MB of RAM and experience weird problems, you might want to try Y, everyone else - says N. Note for machines with more that 64MB of RAM: in order for the + says N. Note for machines with more than 64MB of RAM: in order for the kernel to be able to use the memory above 64MB, pass the command line option "mem=XXXM" (where XXX is the memory size in megabytes) to your kernel. See the documentation of your boot loader @@ -379,7 +379,7 @@ CONFIG_MODVERSIONS Kernel daemon support CONFIG_KERNELD - Normally when you have seleceted some drivers and/or filesystems + Normally when you have selected some drivers and/or filesystems to be created as loadable modules, you also have the responsibility to load the corresponding module (via insmod/modprobe) before you use it. If you select Y here, the kernel will take care of this @@ -1861,7 +1861,7 @@ CONFIG_QUOTA ext2 filesystem; you need the software available via ftp (user: anonymous) from sunsite.unc.edu:/pub/Linux/systm/Admin/quota_acct.tar.gz in order to - use it. Obviously, this is only useful for multi user systems. If + use it. Probably this is only useful for multi user systems. If unsure, say N. Standard (minix) fs support diff --git a/Documentation/cdrom/optcd b/Documentation/cdrom/optcd index 514c9d9ccb12..279684c508d4 100644 --- a/Documentation/cdrom/optcd +++ b/Documentation/cdrom/optcd @@ -43,4 +43,8 @@ try recompiling the driver with some strategically chosen #undef DEBUG_...'s changed into #defines (you'll find them in .../include/linux/optcd.h) and include the messages generated in your bug report. Good luck. +I have inserted code to support multisession. It works for me, although +it is very slow during disk detection. At this time multisession support +is to be considered experimental. Please mail me your experiences. + Leo Spiekman (spiekman@dutette.et.tudelft.nl) diff --git a/MAGIC b/MAGIC index 7a5830e6f28a..5f912b286863 100644 --- a/MAGIC +++ b/MAGIC @@ -74,6 +74,7 @@ Ioctl Include File Comments 0x06 linux/lp.h 0x12 linux/fs.h 0x20 linux/cm206.h +0x22 linux/scc.h 'A' linux/apm_bios.h 'C' linux/soundcard.h 'K' linux/kd.h @@ -83,7 +84,6 @@ Ioctl Include File Comments 'S' linux/cdrom.h conflict! 'S' linux/scsi.h conflict! 'T' linux/soundcard.h conflict! -'T' linux/scc.h conflict! 'T' asm/termios.h conflict! 'V' linux/vt.h 'Y' linux/cyclades.h codes in 0x004359NN diff --git a/Makefile b/Makefile index 14476b8e8d05..7ff17758f954 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 57 +SUBLEVEL = 58 ARCH = i386 diff --git a/Rules.make b/Rules.make index e6ff1ce6a60c..fa2a4daa84aa 100644 --- a/Rules.make +++ b/Rules.make @@ -146,7 +146,7 @@ $(MODINCL)/%.ver: %.c $(SYMTAB_OBJS:.o=.ver): $(TOPDIR)/include/linux/autoconf.h -$(TOPDIR)/include/linux/modversions.h: $(join $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver)) +$(TOPDIR)/include/linux/modversions.h: $(addprefix $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver)) @echo updating $(TOPDIR)/include/linux/modversions.h @(echo "#ifdef MODVERSIONS";\ echo "#undef CONFIG_MODVERSIONS";\ diff --git a/arch/alpha/config.in b/arch/alpha/config.in index a18f99ef58bf..2852caa8a146 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -16,6 +16,7 @@ if [ "$CONFIG_MODULES" = "y" ]; then MODULES=y bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS fi +endmenu mainmenu_option next_comment comment 'General setup' @@ -57,6 +58,7 @@ fi bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +endmenu source drivers/block/Config.in @@ -72,6 +74,7 @@ tristate 'SCSI support' CONFIG_SCSI if [ "$CONFIG_SCSI" != "n" ]; then source drivers/scsi/Config.in fi +endmenu if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment @@ -81,6 +84,7 @@ if [ "$CONFIG_NET" = "y" ]; then if [ "$CONFIG_NETDEVICES" = "y" ]; then source drivers/net/Config.in fi + endmenu fi mainmenu_option next_comment @@ -90,6 +94,7 @@ bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then source drivers/cdrom/Config.in fi +endmenu source fs/Config.in @@ -102,6 +107,7 @@ tristate 'Sound card support' CONFIG_SOUND if [ "$CONFIG_SOUND" != "n" ]; then source drivers/sound/Config.in fi +endmenu mainmenu_option next_comment comment 'Kernel hacking' @@ -111,3 +117,4 @@ bool 'Kernel profiling support' CONFIG_PROFILE if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +endmenu diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index 6b6bc961c0a9..99fddc9ed430 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -12,8 +12,11 @@ .S.o: $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o -OBJS = entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \ - bios32.o ptrace.o time.o apecs.o lca.o +all: kernel.o head.o + +O_TARGET := kernel.o +O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \ + bios32.o ptrace.o time.o apecs.o lca.o ksyms.c all: kernel.o head.o @@ -22,10 +25,4 @@ head.o: head.s head.s: head.S $(TOPDIR)/include/asm-alpha/system.h $(CPP) -traditional -o $*.s $< -kernel.o: $(OBJS) - $(LD) -r -o kernel.o $(OBJS) - -dep: - $(CPP) -M *.c > .depend - include $(TOPDIR)/Rules.make diff --git a/arch/alpha/kernel/ksyms.c b/arch/alpha/kernel/ksyms.c new file mode 100644 index 000000000000..c8269abee597 --- /dev/null +++ b/arch/alpha/kernel/ksyms.c @@ -0,0 +1,55 @@ +/* + * linux/arch/alpha/kernel/ksyms.c + * + * Export the alpha-specific functions that are needed for loadable + * modules. + */ + +#include +#include +# include +# include + +extern void bcopy (const char *src, char *dst, int len); +extern struct hwrpb_struct *hwrpb; + +/* these are C runtime functions with special calling conventions: */ +extern void __divl (void); +extern void __reml (void); +extern void __divq (void); +extern void __remq (void); +extern void __divlu (void); +extern void __remlu (void); +extern void __divqu (void); +extern void __remqu (void); + +static struct symbol_table arch_symbol_table = { +#include + /* platform dependent support */ + X(_inb), + X(_inw), + X(_inl), + X(_outb), + X(_outw), + X(_outl), + X(bcopy), /* generated by gcc-2.7.0 for string assignments */ + X(hwrpb), + X(__divl), + X(__reml), + X(__divq), + X(__remq), + X(__divlu), + X(__remlu), + X(__divqu), + X(__remqu), + X(strlen), /* used by ftape */ + X(memcmp), + X(memmove), + X(__constant_c_memset), +#include +}; + +void arch_syms_export(void) +{ + register_symtab(&arch_symbol_table); +} diff --git a/arch/i386/config.in b/arch/i386/config.in index 5110e2633f49..d7437bc401a5 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -12,6 +12,7 @@ if [ "$CONFIG_MODULES" = "y" ]; then bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD fi +endmenu mainmenu_option next_comment comment 'General setup' @@ -32,6 +33,7 @@ choice 'Processor type' \ "386 CONFIG_M386 \ 486 CONFIG_M486 \ Pentium CONFIG_M586" Pentium +endmenu source drivers/block/Config.in @@ -47,6 +49,7 @@ tristate 'SCSI support' CONFIG_SCSI if [ "$CONFIG_SCSI" != "n" ]; then source drivers/scsi/Config.in fi +endmenu if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment @@ -56,6 +59,7 @@ if [ "$CONFIG_NET" = "y" ]; then if [ "$CONFIG_NETDEVICES" = "y" ]; then source drivers/net/Config.in fi + endmenu fi mainmenu_option next_comment @@ -65,6 +69,7 @@ bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then source drivers/cdrom/Config.in fi +endmenu source fs/Config.in @@ -77,6 +82,7 @@ tristate 'Sound card support' CONFIG_SOUND if [ "$CONFIG_SOUND" != "n" ]; then source drivers/sound/Config.in fi +endmenu mainmenu_option next_comment comment 'Kernel hacking' @@ -86,3 +92,4 @@ bool 'Kernel profiling support' CONFIG_PROFILE if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +endmenu diff --git a/arch/i386/defconfig b/arch/i386/defconfig index d0201388509c..d227d2f77818 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -6,7 +6,7 @@ # Loadable module support # CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set +CONFIG_MODVERSIONS=y # CONFIG_KERNELD is not set # @@ -36,9 +36,9 @@ CONFIG_ST506=y # # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDE=y -CONFIG_BLK_DEV_IDEATAPI=y CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_CMD640=y # CONFIG_BLK_DEV_TRITON is not set # CONFIG_BLK_DEV_XD is not set diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 1186c23064d7..daed0ea7cc2e 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -28,7 +28,7 @@ all: kernel.o head.o O_TARGET := kernel.o O_OBJS := process.o signal.o entry.o traps.o irq.o vm86.o bios32.o \ - ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o + ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o ksyms.o ifdef SMP diff --git a/arch/i386/kernel/ksyms.c b/arch/i386/kernel/ksyms.c new file mode 100644 index 000000000000..0e24808feff3 --- /dev/null +++ b/arch/i386/kernel/ksyms.c @@ -0,0 +1,17 @@ +#include +#include + + +static struct symbol_table arch_symbol_table = { +#include + /* platform dependent support */ +#ifdef __SMP__ + X(apic_reg), /* Needed internally for the I386 inlines */ +#endif +#include +}; + +void arch_syms_export(void) +{ + register_symtab(&arch_symbol_table); +} diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 920b880cd86b..435df48a2807 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -196,7 +196,7 @@ static const char * i486model(unsigned int nr) static const char * i586model(unsigned int nr) { static const char *model[] = { - "0", "Pentium 60/66","Pentium 75+" + "0", "Pentium 60/66","Pentium 75+","OverDrive PODP5V83" }; if (nr < sizeof(model)/sizeof(char *)) return model[nr]; diff --git a/arch/mips/config.in b/arch/mips/config.in index 19b2fbbdd009..ac77d884e4f4 100644 --- a/arch/mips/config.in +++ b/arch/mips/config.in @@ -47,10 +47,12 @@ bool 'Networking support' CONFIG_NET # bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE #fi bool 'System V IPC' CONFIG_SYSVIPC +endmenu mainmenu_option next_comment comment 'Loadable module support' bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS +endmenu source drivers/block/Config.in @@ -66,6 +68,7 @@ tristate 'SCSI support' CONFIG_SCSI if [ "$CONFIG_SCSI" != "n" ]; then source drivers/scsi/Config.in fi +endmenu if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment @@ -75,6 +78,7 @@ if [ "$CONFIG_NET" = "y" ]; then if [ "$CONFIG_NETDEVICES" = "y" ]; then source drivers/net/Config.in fi + endmenu fi mainmenu_option next_comment @@ -84,6 +88,7 @@ bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then source drivers/cdrom/Config.in fi +endmenu source fs/Config.in @@ -97,6 +102,7 @@ tristate 'Sound card support' CONFIG_SOUND if [ "$CONFIG_SOUND" != "n" ]; then source drivers/sound/Config.in fi +endmenu mainmenu_option next_comment comment 'Kernel hacking' @@ -106,3 +112,4 @@ bool 'Kernel profiling support' CONFIG_PROFILE if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +endmenu diff --git a/arch/sparc/config.in b/arch/sparc/config.in index e8ad90b43aba..9b4e9cdf8e8d 100644 --- a/arch/sparc/config.in +++ b/arch/sparc/config.in @@ -17,6 +17,7 @@ define_bool CONFIG_SUN_CONSOLE y bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +endmenu source drivers/block/Config.in @@ -32,6 +33,7 @@ tristate 'SCSI support' CONFIG_SCSI if [ "$CONFIG_SCSI" != "n" ]; then source drivers/scsi/Config.in fi +endmenu if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment @@ -41,6 +43,7 @@ if [ "$CONFIG_NET" = "y" ]; then if [ "$CONFIG_NETDEVICES" = "y" ]; then source drivers/net/Config.in fi + endmenu fi source fs/Config.in diff --git a/drivers/block/Config.in b/drivers/block/Config.in index b0dade40f683..e4234419066e 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -16,11 +16,9 @@ if [ "$CONFIG_ST506" = "y" ]; then bool ' Use new IDE driver for primary/secondary i/f' CONFIG_BLK_DEV_IDE fi if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then - bool ' Include support for IDE/ATAPI CDROM or TAPE' CONFIG_BLK_DEV_IDEATAPI - if [ "$CONFIG_BLK_DEV_IDEATAPI" = "y" ]; then - bool ' Include support for IDE/ATAPI CDROM' CONFIG_BLK_DEV_IDECD - bool ' Include ALPHA support for IDE/ATAPI TAPE' CONFIG_BLK_DEV_IDETAPE - fi + bool ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD + bool ' Include (ALPHA) IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE + bool ' Special CMD640 chipset support' CONFIG_BLK_DEV_CMD640 if [ "$CONFIG_PCI" = "y" ]; then bool ' PCI Triton IDE Bus Master DMA support' CONFIG_BLK_DEV_TRITON fi @@ -28,3 +26,4 @@ if [ "$CONFIG_ST506" = "y" ]; then fi bool 'XT harddisk support' CONFIG_BLK_DEV_XD +endmenu diff --git a/drivers/block/Makefile b/drivers/block/Makefile index a6bfeeb7dd4a..7da812f5504e 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -48,6 +48,10 @@ ifeq ($(CONFIG_BLK_DEV_TRITON),y) L_OBJS += triton.o endif +ifeq ($(CONFIG_BLK_DEV_CMD640),y) +L_OBJS += cmd640.o +endif + ifeq ($(CONFIG_BLK_DEV_IDECD),y) L_OBJS += ide-cd.o endif diff --git a/drivers/block/README.ide b/drivers/block/README.ide index b52c9a845a93..b040bc376046 100644 --- a/drivers/block/README.ide +++ b/drivers/block/README.ide @@ -350,13 +350,19 @@ then use the kernel command line parameters to pass the *logical* geometry, as in: hda=525,64,63 If the BIOS does not support this form of drive translation, then several -options remain, listed below in inverse order of popularity: +options remain, listed below in order of popularity: - - boot from a floppy disk instead of the hard drive (takes 10 seconds). - use a partition below the 1024 cyl boundary to hold the linux boot files (kernel images and /boot directory), and place the rest of linux anywhere else on the drive. These files can reside in a DOS partition, or in a tailor-made linux boot partition. + - use DiskManager software from OnTrack, supplied free with + many new hard drive purchases. + - use EZ-Drive software (similar to DiskManager). Note though, + that LILO must *not* use the MBR when EZ-Drive is present. + Instead, install LILO on the first sector of your linux partition, + and mark it as "active" or "bootable" with fdisk. + - boot from a floppy disk instead of the hard drive (takes 10 seconds). If you cannot use drive translation, *and* your BIOS also restricts you to entering no more than 1024 cylinders in the geometry field in the CMOS setup, diff --git a/drivers/block/cmd640.c b/drivers/block/cmd640.c index c0fbaab01c07..9082404f99af 100644 --- a/drivers/block/cmd640.c +++ b/drivers/block/cmd640.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/cmd640.c Version 0.02 Nov 30, 1995 + * linux/drivers/block/cmd640.c Version 0.04 Jan 11, 1996 * - * Copyright (C) 1995 Linus Torvalds & author (see below) + * Copyright (C) 1995-1996 Linus Torvalds & author (see below) */ /* @@ -18,8 +18,49 @@ * read-ahead for versions 'B' and 'C' of chip by * default, some code cleanup. * + * Version 0.03 Added reset of secondary interface, + * and black list for devices which are not compatible + * with read ahead mode. Separate function for setting + * readahead is added, possibly it will be called some + * day from ioctl processing code. + * + * Version 0.04 Now configs/compiles separate from ide.c -ml + */ + +/* + * There is a known problem with current version of this driver. + * If the only device on secondary interface is CD-ROM, at some + * computers it is not recognized. In all reported cases CD-ROM + * was 2x or 4x speed Mitsumi drive. + * + * The following workarounds could work: + * + * 1. put CD-ROM as slave on primary interface + * + * 2. or define symbol at next line as 0 + * */ +#define CMD640_NORMAL_INIT 1 + +#undef REALLY_SLOW_IO /* most systems can safely undef this */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ide.h" + +extern ide_hwif_t ide_hwifs[]; + +int cmd640_vlb = 0; + /* * CMD640 specific registers definition. */ @@ -76,7 +117,7 @@ static int bus_speed; /* MHz */ /* * For some unknown reasons pcibios functions which read and write registers - * do not work with cmd640. We use direct io instead. + * do not always work with cmd640. We use direct io instead. */ /* PCI method 1 access */ @@ -229,6 +270,35 @@ static int probe_for_cmd640_vlb(void) { return 1; } +/* + * Low level reset for controller, actually it has nothing specific for + * CMD640, but I don't know how to use standard reset routine before + * we recognized any drives. + */ + +static void cmd640_reset_controller(int iface_no) +{ + int retry_count = 600; + int base_port = iface_no ? 0x170 : 0x1f0; + + outb_p(4, base_port + 7); + udelay(5); + outb_p(0, base_port + 7); + + do { + udelay(5); + retry_count -= 1; + } while ((inb_p(base_port + 7) & 0x80) && retry_count); + + if (retry_count == 0) + printk("cmd640: failed to reset controller %d\n", iface_no); +#if 0 + else + printk("cmd640: controller %d reset [%d]\n", + iface_no, retry_count); +#endif +} + /* * Probe for Cmd640x and initialize it if found */ @@ -282,31 +352,34 @@ int ide_probe_for_cmd640x(void) /* * Set the maximum allowed bus speed (it is safest until we - * find how detect bus speed) + * find how to detect bus speed) * Normally PCI bus runs at 33MHz, but often works overclocked to 40 */ bus_speed = (bus_type == vlb) ? 50 : 40; -#if 1 /* don't know if this is reliable yet */ /* * Enable readahead for versions above 'A' */ cmd_read_ahead = (cmd640_chip_version > 1); -#else - cmd_read_ahead = 0; -#endif + /* * Setup Control Register */ b = get_cmd640_reg(cmd640_key, CNTRL); + +#if CMD640_NORMAL_INIT if (second_port) b |= CNTRL_ENA_2ND; else b &= ~CNTRL_ENA_2ND; +#endif + if (cmd_read_ahead) b &= ~(CNTRL_DIS_RA0 | CNTRL_DIS_RA1); else b |= (CNTRL_DIS_RA0 | CNTRL_DIS_RA1); + + put_cmd640_reg(cmd640_key, CNTRL, b); /* @@ -317,9 +390,11 @@ int ide_probe_for_cmd640x(void) b = cmd_read_ahead ? 0 : (DIS_RA2 | DIS_RA3); put_cmd640_reg(cmd640_key, ARTTIM23, b); put_cmd640_reg(cmd640_key, DRWTIM23, 0); + + cmd640_reset_controller(1); } - serialized = 1; + ide_hwifs[0].serialized = 1; printk("ide: buggy CMD640%c interface at ", 'A' - 1 + cmd640_chip_version); @@ -359,6 +434,48 @@ static int as_clocks(int a) { } } +/* + * Sets readahead mode for specific drive + * in the future it could be called from ioctl + */ + +static void set_readahead_mode(int mode, int if_num, int dr_num) +{ + static int masks[2][2] = + { + {CNTRL_DIS_RA0, CNTRL_DIS_RA1}, + {DIS_RA2, DIS_RA3} + }; + + int port = (if_num == 0) ? CNTRL : ARTTIM23; + int mask = masks[if_num][dr_num]; + byte b; + + b = get_cmd640_reg(cmd640_key, port); + if (mode) + b &= mask; /* Enable readahead for specific drive */ + else + b |= mask; /* Disable readahed for specific drive */ + put_cmd640_reg(cmd640_key, port, b); +} + +static struct readahead_black_list { + const char* name; + int mode; +} drives_ra[] = { + { "ST3655A", 0 }, + { NULL, 0 } +}; + +static int known_drive_readahead(char* name) { + int i; + + for (i = 0; drives_ra[i].name != NULL; i++) + if (strcmp(name, drives_ra[i].name) == 0) + return drives_ra[i].mode; + return -1; +} + /* * Tuning of drive parameters */ @@ -400,7 +517,7 @@ static void cmd640_set_timing(int if_num, int dr_num, int r1, int r2) { } } -struct pio_timing { +static struct pio_timing { int mc_time; /* Minimal cycle time (ns) */ int av_time; /* Address valid to DIOR-/DIOW- setup (ns) */ int ds_time; /* DIOR data setup (ns) */ @@ -413,7 +530,7 @@ struct pio_timing { { 20, 50, 100 } /* PIO Mode ? */ }; -struct drive_pio_info { +static struct drive_pio_info { const char *name; int pio; } drive_pios[] = { @@ -426,6 +543,7 @@ struct drive_pio_info { { "QUANTUM LPS240A", 0 }, { "QUANTUM LPS270A", 3 }, { "QUANTUM LPS540A", 3 }, + { "QUANTUM FIREBALL1080A", 3 }, { NULL, 0 } }; @@ -480,7 +598,7 @@ static void set_pio_mode(int if_num, int drv_num, int mode_num) { outb_p((drv_num | 0xa) << 4, p_base + 6); outb_p(0xef, p_base + 7); for (i = 0; (i < 100) && (inb (p_base + 7) & 0x80); i++) - delay_10ms(); + udelay(10000); } void cmd640_tune_drive(ide_drive_t* drive) { @@ -491,6 +609,7 @@ void cmd640_tune_drive(ide_drive_t* drive) { int mc_time, av_time, ds_time; struct hd_driveid* id; int r1, r2; + int mode; /* * Determine if drive is under cmd640 control @@ -530,6 +649,13 @@ void cmd640_tune_drive(ide_drive_t* drive) { &r1, &r2); set_pio_mode(interface_number, drive_number, max_pio); cmd640_set_timing(interface_number, drive_number, r1, r2); + + /* + * Disable (or set) readahead mode for known drive + */ + if ((mode = known_drive_readahead(id->model)) != -1) { + set_readahead_mode(mode, interface_number, drive_number); + printk("Readahead %s,", mode ? "enabled" : "disabled"); + } printk ("Mode and Timing set to PIO%d (0x%x 0x%x)\n", max_pio, r1, r2); } - diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index 3dbdd42a2776..12d22d324b83 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -108,7 +108,6 @@ #include #include -#define _IDE_CD_C /* used in blk.h */ #include "ide.h" diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c index 47d2797271d1..8b36dce83611 100644 --- a/drivers/block/ide-tape.c +++ b/drivers/block/ide-tape.c @@ -300,8 +300,6 @@ #include #include -#define _IDE_TAPE_C /* For ide_end_request in blk.h */ - /* * Main Linux ide driver include file * diff --git a/drivers/block/ide.c b/drivers/block/ide.c index d6219de37e37..ef8bf7fe498c 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -1,8 +1,9 @@ /* - * linux/drivers/block/ide.c Version 5.24 Jan 4, 1996 + * linux/drivers/block/ide.c Version 5.25 Jan 11, 1996 * * Copyright (C) 1994-1996 Linus Torvalds & authors (see below) */ +#define _IDE_C /* needed by */ /* * This is the multiple IDE interface driver, as evolved from hd.c. @@ -109,7 +110,7 @@ * assembly syntax tweak to vlb_sync * removeable drive support from scuba@cs.tu-berlin.de * add transparent support for DiskManager-6.0x "Dynamic - * Disk Overlay" (DDO), most of this in in genhd.c + * Disk Overlay" (DDO), most of this is in genhd.c * eliminate "multiple mode turned off" message at boot * Version 4.10 fix bug in ioctl for "hdparm -c3" * fix DM6:DDO support -- now works with LILO, fdisk, ... @@ -180,11 +181,13 @@ * Version 5.22 fix ide_xlate_1024() to work with/without drive->id * Version 5.23 miscellaneous touch-ups * Version 5.24 fix #if's for SUPPORT_CMD640 + * Version 5.25 more touch-ups, fix cdrom resets, ... + * cmd640.c now configs/compiles separate from ide.c * * Driver compile-time options are in ide.h * * To do, in likely order of completion: - * - make cmd640.c and umc8672.c compile separately from ide.c + * - make umc8672.c compile separately from ide.c * - add ALI M1443/1445 chipset support from derekn@vw.ece.cmu.edu * - add ioctls to get/set interface timings on various interfaces * - add Promise Caching controller support from peterd@pnd-pc.demon.co.uk @@ -222,18 +225,12 @@ #include "ide.h" -#if SUPPORT_CMD640 -void cmd640_tune_drive(ide_drive_t *); -static int cmd640_vlb = 0; -#endif - ide_hwif_t ide_hwifs[MAX_HWIFS]; /* hwif info */ static ide_hwgroup_t *irq_to_hwgroup [16]; static const byte ide_hwif_to_major[MAX_HWIFS] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR}; static const unsigned short default_io_base[MAX_HWIFS] = {0x1f0, 0x170, 0x1e8, 0x168}; static const byte default_irqs[MAX_HWIFS] = {14, 15, 11, 10}; -static int serialized = 0; /* "serialize" option */ static int disallow_unmask = 0; /* for buggy hardware */ #if (DISK_RECOVERY_TIME > 0) @@ -881,7 +878,8 @@ void ide_error (ide_drive_t *drive, const char *msg, byte stat) err = ide_dump_status(drive, msg, stat); if ((rq = HWGROUP(drive)->rq) == NULL || drive == NULL) return; - if (rq->cmd != READ && rq->cmd != WRITE) { /* retry only "normal" i/o */ + /* retry only "normal" I/O: */ + if (rq->cmd != READ && rq->cmd != WRITE && drive->media != ide_cdrom) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); return; @@ -1346,7 +1344,7 @@ static inline void do_request (ide_hwif_t *hwif, struct request *rq) #if FAKE_FDISK_FOR_EZDRIVE if (block == 0 && drive->ezdrive) { block = 1; - printk("%s: [EZD] accessing sector 1 instead of sector 0\n", drive->name); + printk("%s: [EZD] accessing sector 1 in place of sector 0\n", drive->name); } #endif /* FAKE_FDISK_FOR_EZDRIVE */ ((ide_hwgroup_t *)hwif->hwgroup)->drive = drive; @@ -2210,8 +2208,11 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) printk(", DMA"); } printk("\n"); -#if SUPPORT_CMD640 - cmd640_tune_drive(drive); /* but can we tune a fish? */ +#ifdef CONFIG_BLK_DEV_CMD640 + { + extern void cmd640_tune_drive (ide_drive_t *); + cmd640_tune_drive(drive); /* but can we tune a fish? */ + } #endif } @@ -2527,10 +2528,6 @@ static void init_qd6580 (void) #include "umc8672.c" /* until we tidy up the interface some more */ #endif -#if SUPPORT_CMD640 -#include "cmd640.c" /* until we tidy up the interface some more */ -#endif - /* * stridx() returns the offset of c within s, * or -1 if c is '\0' or not found within s. @@ -2699,12 +2696,15 @@ void ide_setup (char *s) init_qd6580(); goto done; #endif /* SUPPORT_QD6580 */ -#if SUPPORT_CMD640 +#ifdef CONFIG_BLK_DEV_CMD640 case -5: /* "cmd640_vlb" */ + { + extern int cmd640_vlb; if (hw > 1) goto bad_hwif; - cmd640_vlb = 1; + cmd640_vlb = 1; + } break; -#endif /* SUPPORT_CMD640 */ +#endif /* CONFIG_BLK_DEV_CMD640 */ #if SUPPORT_HT6560B case -4: /* "ht6560b" */ if (hw > 1) goto bad_hwif; @@ -2736,7 +2736,7 @@ void ide_setup (char *s) case -2: /* "serialize" */ do_serialize: if (hw > 1) goto bad_hwif; - serialized = 1; + ide_hwifs[0].serialized = 1; goto done; case -1: /* "noprobe" */ hwif->noprobe = 1; @@ -2890,7 +2890,7 @@ static int init_irq (ide_hwif_t *hwif) * Check for serialization with ide1. * This code depends on us having already taken care of ide1. */ - if (serialized && hwif->name[3] == '0' && ide_hwifs[1].present) + if (hwif->serialized && hwif->name[3] == '0' && ide_hwifs[1].present) hwgroup = ide_hwifs[1].hwgroup; /* * If this is the first interface in a group, @@ -2941,23 +2941,14 @@ static struct file_operations ide_fops = { #ifdef CONFIG_PCI -void ide_pci_access_error (int rc) -{ - printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc)); -} +#if SUPPORT_RZ1000 -#if SUPPORT_RZ1000 || SUPPORT_CMD640 -void buggy_interface_fallback (int rc) +static void ide_pci_access_error (int rc) { - ide_pci_access_error (rc); - serialized = 1; - disallow_unmask = 1; - printk("serialized, disabled unmasking\n"); + printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc)); } -#endif /* SUPPORT_RZ1000 || SUPPORT_CMD640 */ -#if SUPPORT_RZ1000 -void init_rz1000 (byte bus, byte fn) +static void init_rz1000 (byte bus, byte fn) { int rc; unsigned short reg; @@ -2970,8 +2961,12 @@ void init_rz1000 (byte bus, byte fn) } else { if ((rc = pcibios_read_config_word(bus, fn, 0x40, ®)) || (rc = pcibios_write_config_word(bus, fn, 0x40, reg & 0xdfff))) - buggy_interface_fallback (rc); - else + { + ide_pci_access_error (rc); + ide_hwifs[0].serialized = 1; + disallow_unmask = 1; + printk("serialized, disabled unmasking\n"); + } else printk("disabled read-ahead\n"); } } @@ -3012,7 +3007,7 @@ static void ide_init_pci (void) /* * Apparently the BIOS32 services on Intel motherboards are buggy, * and won't find the PCI_DEVICE_ID_INTEL_82371_1 for us. - * So we instead search for PCI_DEVICE_ID_INTEL_82371_0, and then add 1. + * So instead, we search for PCI_DEVICE_ID_INTEL_82371_0, and then add 1. */ ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371_0, &ide_init_triton, 1); #endif @@ -3038,8 +3033,11 @@ int ide_init (void) if (pcibios_present()) ide_init_pci (); #endif /* CONFIG_PCI */ -#if SUPPORT_CMD640 - ide_probe_for_cmd640x(); +#ifdef CONFIG_BLK_DEV_CMD640 + { + extern void ide_probe_for_cmd640x (void); + ide_probe_for_cmd640x(); + } #endif /* diff --git a/drivers/block/ide.h b/drivers/block/ide.h index a7a51662d997..65db50d8f060 100644 --- a/drivers/block/ide.h +++ b/drivers/block/ide.h @@ -37,9 +37,6 @@ #ifndef SUPPORT_RZ1000 /* 1 to support RZ1000 chipset */ #define SUPPORT_RZ1000 1 /* 0 to reduce kernel size */ #endif -#ifndef SUPPORT_CMD640 /* 1 to support CMD640 chipset */ -#define SUPPORT_CMD640 1 /* 0 to reduce kernel size */ -#endif #ifndef SUPPORT_UMC8672 /* 1 to support UMC8672 chipset */ #define SUPPORT_UMC8672 1 /* 0 to reduce kernel size */ #endif @@ -59,6 +56,10 @@ #define FANCY_STATUS_DUMPS 1 /* 0 to reduce kernel size */ #endif +#if defined(CONFIG_BLK_DEV_IDECD) || defined(CONFIG_BLK_DEV_IDETAPE) +#define CONFIG_BLK_DEV_IDEATAPI 1 +#endif + /* * IDE_DRIVE_CMD is used to implement many features of the hdparm utility */ @@ -393,6 +394,7 @@ typedef struct hwif_s { char name[5]; /* name of interface, eg. "ide0" */ unsigned noprobe : 1; /* don't probe for this interface */ unsigned present : 1; /* this interface exists */ + unsigned serialized : 1; /* valid only for ide_hwifs[0] */ #if (DISK_RECOVERY_TIME > 0) unsigned long last_time; /* time when previous rq was done */ #endif @@ -603,4 +605,3 @@ void idetape_register_chrdev (void); #ifdef CONFIG_BLK_DEV_TRITON void ide_init_triton (byte, byte); #endif /* CONFIG_BLK_DEV_TRITON */ - diff --git a/drivers/block/triton.c b/drivers/block/triton.c index 07ed2bbc42ac..5c1d2ee3031d 100644 --- a/drivers/block/triton.c +++ b/drivers/block/triton.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/triton.c Version 1.04 Dec 1, 1995 + * linux/drivers/block/triton.c Version 1.05 Jan 11, 1996 * - * Copyright (c) 1995 Mark Lord + * Copyright (c) 1995-1996 Mark Lord * May be copied or modified under the terms of the GNU General Public License */ @@ -95,11 +95,6 @@ * * And, yes, Intel Zappa boards really *do* use the Triton IDE ports. */ -#define _TRITON_C -#include -#ifndef CONFIG_BLK_DEV_TRITON -#define CONFIG_BLK_DEV_TRITON y -#endif #include #include #include @@ -127,15 +122,15 @@ const char *good_dma_drives[] = {"Micropolis 2112A"}; * Our Physical Region Descriptor (PRD) table should be large enough * to handle the biggest I/O request we are likely to see. Since requests * can have no more than 256 sectors, and since the typical blocksize is - * two sectors, we can get by with a limit of 128 entries here for the + * two sectors, we could get by with a limit of 128 entries here for the * usual worst case. Most requests seem to include some contiguous blocks, * further reducing the number of table entries required. * - * Note that the driver reverts to PIO mode for individual requests that exceed + * The driver reverts to PIO mode for individual requests that exceed * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling * 100% of all crazy scenarios here is not necessary. * - * As it turns out, though, we must allocate a full 4KB page for this, + * As it turns out though, we must allocate a full 4KB page for this, * so the two PRD tables (ide0 & ide1) will each get half of that, * allowing each to have about 256 entries (8 bytes each) from this. */ @@ -288,7 +283,7 @@ static int triton_dmaproc (ide_dma_action_t func, ide_drive_t *drive) outl(virt_to_bus (HWIF(drive)->dmatable), dma_base + 4); /* PRD table */ outb(reading, dma_base); /* specify r/w */ outb(0x26, dma_base+2); /* clear status bits */ - ide_set_handler (drive, &dma_intr, WAIT_CMD); /* issue cmd to drive */ + ide_set_handler(drive, &dma_intr, WAIT_CMD); /* issue cmd to drive */ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); outb(inb(dma_base)|1, dma_base); /* begin DMA */ return 0; @@ -316,6 +311,48 @@ static void print_triton_drive_flags (unsigned int unit, byte flags) printk(" fastPIO=%s\n", ((flags&9)==1) ? "on " : "off"); } +static void init_triton_dma (ide_hwif_t *hwif, unsigned short base) +{ + static unsigned long dmatable = 0; + + printk(" %s: BusMaster DMA at 0x%04x-0x%04x", hwif->name, base, base+7); + if (check_region(base, 8)) { + printk(" -- ERROR, PORTS ALREADY IN USE"); + } else { + request_region(base, 8, hwif->name); + hwif->dma_base = base; + if (!dmatable) { + /* + * Since we know we are on a PCI bus, we could + * actually use __get_free_pages() here instead + * of __get_dma_pages() -- no ISA limitations. + */ + dmatable = __get_dma_pages(GFP_KERNEL, 0); + } + if (dmatable) { + hwif->dmatable = (unsigned long *) dmatable; + dmatable += (PRD_ENTRIES * PRD_BYTES); + outl(virt_to_bus(hwif->dmatable), base + 4); + hwif->dmaproc = &triton_dmaproc; + } + } + printk("\n"); +} + +/* + * calc_mode() returns the ATA PIO mode number, based on the number + * of cycle clks passed in. Assumes 33Mhz bus operation (30ns per clk). + */ +byte calc_mode (byte clks) +{ + if (clks == 3) return 5; + if (clks == 4) return 4; + if (clks < 6) return 3; + if (clks < 8) return 2; + if (clks < 13) return 1; + return 0; +} + /* * ide_init_triton() prepares the IDE driver for DMA operation. * This routine is called once, from ide.c during driver initialization, @@ -324,26 +361,33 @@ static void print_triton_drive_flags (unsigned int unit, byte flags) void ide_init_triton (byte bus, byte fn) { int rc = 0, h; + int dma_enabled = 0; unsigned short bmiba, pcicmd; unsigned int timings; - unsigned long dmatable = 0; extern ide_hwif_t ide_hwifs[]; + printk("ide: Triton BM-IDE on PCI bus %d function %d\n", bus, fn); /* * See if IDE and BM-DMA features are enabled: */ if ((rc = pcibios_read_config_word(bus, fn, 0x04, &pcicmd))) goto quit; - if ((pcicmd & 5) != 5) { - if ((pcicmd & 1) == 0) - printk("ide: Triton IDE ports are not enabled\n"); - else - printk("ide: Triton BM-DMA feature is not enabled\n"); + if ((pcicmd & 1) == 0) { + printk("ide: Triton IDE ports are not enabled\n"); goto quit; } -#if 0 - (void) pcibios_write_config_word(bus, fn, 0x42, 0x8037); /* for my MC2112A */ -#endif + if ((pcicmd & 4) == 0) { + printk("ide: Triton BM-DMA feature is not enabled -- upgrade your BIOS\n"); + } else { + /* + * Get the bmiba base address + */ + if ((rc = pcibios_read_config_word(bus, fn, 0x20, &bmiba))) + goto quit; + bmiba &= 0xfff0; /* extract port base address */ + dma_enabled = 1; + } + /* * See if ide port(s) are enabled */ @@ -353,52 +397,32 @@ void ide_init_triton (byte bus, byte fn) printk("ide: neither Triton IDE port is enabled\n"); goto quit; } - printk("ide: Triton BM-IDE on PCI bus %d function %d\n", bus, fn); - - /* - * Get the bmiba base address - */ - if ((rc = pcibios_read_config_word(bus, fn, 0x20, &bmiba))) - goto quit; - bmiba &= 0xfff0; /* extract port base address */ /* * Save the dma_base port addr for each interface */ for (h = 0; h < MAX_HWIFS; ++h) { + byte s_clks, r_clks; ide_hwif_t *hwif = &ide_hwifs[h]; - unsigned short base, time; - if (hwif->io_base == 0x1f0 && (timings & 0x8000)) { + unsigned short time; + if (hwif->io_base == 0x1f0) { time = timings & 0xffff; - base = bmiba; - } else if (hwif->io_base == 0x170 && (timings & 0x80000000)) { + if ((timings & 0x8000) == 0) /* interface enabled? */ + continue; + if (dma_enabled) + init_triton_dma(hwif, bmiba); + } else if (hwif->io_base == 0x170) { time = timings >> 16; - base = bmiba + 8; + if ((timings & 0x8000) == 0) /* interface enabled? */ + continue; + if (dma_enabled) + init_triton_dma(hwif, bmiba + 8); } else continue; - printk(" %s: BusMaster DMA at 0x%04x-0x%04x", hwif->name, base, base+7); - if (check_region(base, 8)) { - printk(" -- ERROR, PORTS ALREADY IN USE"); - } else { - request_region(base, 8, hwif->name); - hwif->dma_base = base; - if (!dmatable) { - /* - * Since we know we are on a PCI bus, we could - * actually use __get_free_pages() here instead - * of __get_dma_pages() -- no ISA limitations. - */ - dmatable = __get_dma_pages(GFP_KERNEL, 0); - } - if (dmatable) { - hwif->dmatable = (unsigned long *) dmatable; - dmatable += (PRD_ENTRIES * PRD_BYTES); - outl(virt_to_bus(hwif->dmatable), base + 4); - hwif->dmaproc = &triton_dmaproc; - } - } - printk("\n %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n", - hwif->name, time, ((~time>>12)&3)+2, ((~time>>8)&3)+1); + s_clks = ((~time >> 12) & 3) + 2; + r_clks = ((~time >> 8) & 3) + 1; + printk(" %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d (PIO mode%d)\n", + hwif->name, time, s_clks, r_clks, calc_mode(s_clks+r_clks)); print_triton_drive_flags (0, time & 0xf); print_triton_drive_flags (1, (time >> 4) & 0xf); } diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c index 1f1ef0f0c351..911186233c62 100644 --- a/drivers/cdrom/mcdx.c +++ b/drivers/cdrom/mcdx.c @@ -1,7 +1,7 @@ /* * The Mitsumi CDROM interface * Copyright (C) 1995 Heiko Schlittermann - * VERSION: 1.5 + * VERSION: 1.5a * * 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 @@ -34,7 +34,7 @@ #if RCS static const char *mcdx_c_version - = "mcdx.c,v 1.19 1995/11/20 17:06:25 heiko Exp"; + = "mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp"; #endif #include @@ -768,8 +768,10 @@ mcdx_close(struct inode *ip, struct file *fp) /* invalidate_inodes(ip->i_rdev); */ invalidate_buffers(ip->i_rdev); +#if !MCDX_QUIET if (-1 == mcdx_lockdoor(stuffp, 0, 3)) INFO(("close() Cannot unlock the door\n")); +#endif /* eject if wished */ if (stuffp->eject_sw) mcdx_eject(stuffp, 1); @@ -794,10 +796,8 @@ int check_mcdx_media_change(kdev_t full_dev) void mcdx_setup(char *str, int *pi) { -#if MCDX_DEBUG - printk(MCDX ":: setup(%s, %d) called\n", - str, pi[0]); -#endif + if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1]; + if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2]; } /* DIRTY PART ******************************************************/ @@ -1051,10 +1051,10 @@ int mcdx_init(void) { int drive; - WARN(("Version 1.5 " - "mcdx.c,v 1.19 1995/11/20 17:06:25 heiko Exp\n")); - INFO((": Version 1.5 " - "mcdx.c,v 1.19 1995/11/20 17:06:25 heiko Exp\n")); + WARN(("Version 1.5a " + "mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp\n")); + INFO((": Version 1.5a " + "mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp\n")); /* zero the pointer array */ for (drive = 0; drive < MCDX_NDRIVES; drive++) @@ -1245,7 +1245,7 @@ static int mcdx_transfer(struct s_drive_stuff *stuffp, stuffp->lock = current->pid; do { - int sig = 0; + /* int sig = 0; */ int to = 0; /* wait for the drive become idle */ diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c index 3e33ff1099f4..4f5d52ea5adf 100644 --- a/drivers/cdrom/optcd.c +++ b/drivers/cdrom/optcd.c @@ -1,12 +1,13 @@ -/* $Id: optcd.c,v 1.3 1995/08/24 19:54:27 root Exp root $ - linux/drivers/block/optcd.c - Optics Storage 8000 AT CDROM driver +/* linux/drivers/cdrom/optcd.c - Optics Storage 8000 AT CDROM driver + $Id: optcd.c,v 1.20 1996/01/17 19:44:39 root Exp root $ Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl) + Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks by Eberhard Moenkeberg (emoenke@gwdg.de). ISP16 detection and - configuration by Eric van der Maarel (maarel@marin.nl), with some data - communicated by Vadim V. Model (vadim@rbrf.msk.su). + configuration by Eric van der Maarel (maarel@marin.nl) and + Vadim Model (vadim@cecmow.enet.dec.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 @@ -21,8 +22,11 @@ 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. +*/ + +/* Revision history + - History 14-5-95 v0.0 Plays sound tracks. No reading of data CDs yet. Detection of disk change doesn't work. 21-5-95 v0.1 First ALPHA version. CD can be mounted. The @@ -47,308 +51,379 @@ Updated README.optcd. Submitted for inclusion in 1.3.21 29-9-95 v0.4a Fixed bug that prevented compilation as module + 25-10-95 v0.5 Started multisession code. Implementation + copied from Werner Zimmermann, who copied it + from Heiko Schlittermann's mcdx. + 17-1-96 v0.6 Multisession works; some cleanup too. */ + +/* Includes */ -#include -#include +#include #include -#include -#include -#include -#include #include -#include - #include #define MAJOR_NR OPTICS_CDROM_MAJOR +#include -# include -#define optcd_port optcd /* Needed for the modutils. */ -# include - - -/* Some (Media)Magic */ -/* define types of drive the interface on an ISP16 card may be looking at */ -#define ISP16_DRIVE_X 0x00 -#define ISP16_SONY 0x02 -#define ISP16_PANASONIC0 0x02 -#define ISP16_SANYO0 0x02 -#define ISP16_MITSUMI 0x04 -#define ISP16_PANASONIC1 0x06 -#define ISP16_SANYO1 0x06 -#define ISP16_DRIVE_NOT_USED 0x08 /* not used */ -#define ISP16_DRIVE_SET_MASK 0xF1 /* don't change 0-bit or 4-7-bits*/ -/* ...for port */ -#define ISP16_DRIVE_SET_PORT 0xF8D -/* set io parameters */ -#define ISP16_BASE_340 0x00 -#define ISP16_BASE_330 0x40 -#define ISP16_BASE_360 0x80 -#define ISP16_BASE_320 0xC0 -#define ISP16_IRQ_X 0x00 -#define ISP16_IRQ_5 0x04 /* shouldn't be used due to soundcard conflicts */ -#define ISP16_IRQ_7 0x08 /* shouldn't be used due to soundcard conflicts */ -#define ISP16_IRQ_3 0x0C -#define ISP16_IRQ_9 0x10 -#define ISP16_IRQ_10 0x14 -#define ISP16_IRQ_11 0x18 -#define ISP16_DMA_X 0x03 -#define ISP16_DMA_3 0x00 -#define ISP16_DMA_5 0x00 -#define ISP16_DMA_6 0x01 -#define ISP16_DMA_7 0x02 -#define ISP16_IO_SET_MASK 0x20 /* don't change 5-bit */ -/* ...for port */ -#define ISP16_IO_SET_PORT 0xF8E -/* enable the drive */ -#define ISP16_NO_IDE__ENABLE_CDROM_PORT 0xF90 /* ISP16 without IDE interface */ -#define ISP16_IDE__ENABLE_CDROM_PORT 0xF91 /* ISP16 with IDE interface */ -#define ISP16_ENABLE_CDROM 0x80 /* seven bit */ - -/* the magic stuff */ -#define ISP16_CTRL_PORT 0xF8F -#define ISP16_NO_IDE__CTRL 0xE2 /* ISP16 without IDE interface */ -#define ISP16_IDE__CTRL 0xE3 /* ISP16 with IDE interface */ - -static short isp16_detect(void); -static short isp16_no_ide__detect(void); -static short isp16_with_ide__detect(void); -static short isp16_config( int base, u_char drive_type, int irq, int dma ); -static short isp16_type; /* dependent on type of interface card */ -static u_char isp16_ctrl; -static u_short isp16_enable_cdrom_port; - - -static short optcd_port = OPTCD_PORTBASE; - -/* Read current status/data availability flags */ -inline static int optFlags(void) { - return inb(STATUS_PORT) & FL_STDT; -} +#include +#include -/* Wait for status available; return TRUE on timeout */ -static int sten_low(void) { - int no_status; - unsigned long count = 0; - while ((no_status = (optFlags() & FL_STEN))) - if (++count >= BUSY_TIMEOUT) - break; -#ifdef DEBUG_DRIVE_IF - if (no_status) - printk("optcd: timeout waiting for STEN low\n"); - else - printk("optcd: STEN low after %ld\n", count); +#ifdef PROBE_ISP16 +#include "optcd_isp16.h" /* optional ISP16 detection/configuration */ #endif - return no_status; -} + +/* Debug support */ -/* Wait for data available; return TRUE on timeout */ -static int dten_low(void) { - int no_data; + +/* Don't forget to add new debug flags here. */ +#if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \ + DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS +#define DEBUG(x) debug x +static void debug(int debug_this, const char* fmt, ...) +{ + char s[1024]; + va_list args; + + if (!debug_this) + return; + + va_start(args, fmt); + vsprintf(s, fmt, args); + printk("optcd: %s\n", s); + va_end(args); +} +#else +#define DEBUG(x) +#endif + +/* Drive hardware/firmware characteristics + Identifiers in accordance with Optics Storage documentation */ + + +#define optcd_port optcd /* Needed for the modutils. */ +static short optcd_port = OPTCD_PORTBASE; /* I/O base of drive. */ + +/* Drive registers, read */ +#define DATA_PORT optcd_port /* Read data/status */ +#define STATUS_PORT optcd_port+1 /* Indicate data/status availability */ + +/* Drive registers, write */ +#define COMIN_PORT optcd_port /* For passing command/parameter */ +#define RESET_PORT optcd_port+1 /* Write anything and wait 0.5 sec */ +#define HCON_PORT optcd_port+2 /* Host Xfer Configuration */ + + +/* Command completion/status read from DATA register */ +#define ST_DRVERR 0x80 +#define ST_DOOR_OPEN 0x40 +#define ST_MIXEDMODE_DISK 0x20 +#define ST_MODE_BITS 0x1c +#define ST_M_STOP 0x00 +#define ST_M_READ 0x04 +#define ST_M_AUDIO 0x04 +#define ST_M_PAUSE 0x08 +#define ST_M_INITIAL 0x0c +#define ST_M_ERROR 0x10 +#define ST_M_OTHERS 0x14 +#define ST_MODE2TRACK 0x02 +#define ST_DSK_CHG 0x01 +#define ST_L_LOCK 0x01 +#define ST_CMD_OK 0x00 +#define ST_OP_OK 0x01 +#define ST_PA_OK 0x02 +#define ST_OP_ERROR 0x05 +#define ST_PA_ERROR 0x06 + + +/* Error codes (appear as command completion code from DATA register) */ +/* Player related errors */ +#define ERR_ILLCMD 0x11 /* Illegal command to player module */ +#define ERR_ILLPARM 0x12 /* Illegal parameter to player module */ +#define ERR_SLEDGE 0x13 +#define ERR_FOCUS 0x14 +#define ERR_MOTOR 0x15 +#define ERR_RADIAL 0x16 +#define ERR_PLL 0x17 /* PLL lock error */ +#define ERR_SUB_TIM 0x18 /* Subcode timeout error */ +#define ERR_SUB_NF 0x19 /* Subcode not found error */ +#define ERR_TRAY 0x1a +#define ERR_TOC 0x1b /* Table of Contents read error */ +#define ERR_JUMP 0x1c +/* Data errors */ +#define ERR_MODE 0x21 +#define ERR_FORM 0x22 +#define ERR_HEADADDR 0x23 /* Header Address not found */ +#define ERR_CRC 0x24 +#define ERR_ECC 0x25 /* Uncorrectable ECC error */ +#define ERR_CRC_UNC 0x26 /* CRC error and uncorrectable error */ +#define ERR_ILLBSYNC 0x27 /* Illegal block sync error */ +#define ERR_VDST 0x28 /* VDST not found */ +/* Timeout errors */ +#define ERR_READ_TIM 0x31 /* Read timeout error */ +#define ERR_DEC_STP 0x32 /* Decoder stopped */ +#define ERR_DEC_TIM 0x33 /* Decoder interrupt timeout error */ +/* Function abort codes */ +#define ERR_KEY 0x41 /* Key -Detected abort */ +#define ERR_READ_FINISH 0x42 /* Read Finish */ +/* Second Byte diagnostic codes */ +#define ERR_NOBSYNC 0x01 /* No block sync */ +#define ERR_SHORTB 0x02 /* Short block */ +#define ERR_LONGB 0x03 /* Long block */ +#define ERR_SHORTDSP 0x04 /* Short DSP word */ +#define ERR_LONGDSP 0x05 /* Long DSP word */ + + +/* Status availability flags read from STATUS register */ +#define FL_EJECT 0x20 +#define FL_WAIT 0x10 /* active low */ +#define FL_EOP 0x08 /* active low */ +#define FL_STEN 0x04 /* Status available when low */ +#define FL_DTEN 0x02 /* Data available when low */ +#define FL_DRQ 0x01 /* active low */ +#define FL_RESET 0xde /* These bits are high after a reset */ +#define FL_STDT (FL_STEN|FL_DTEN) + + +/* Transfer mode, written to HCON register */ +#define HCON_DTS 0x08 +#define HCON_SDRQB 0x04 +#define HCON_LOHI 0x02 +#define HCON_DMA16 0x01 + + +/* Drive command set, written to COMIN register */ +/* Quick response commands */ +#define COMDRVST 0x20 /* Drive Status Read */ +#define COMERRST 0x21 /* Error Status Read */ +#define COMIOCTLISTAT 0x22 /* Status Read; reset disk changed bit */ +#define COMINITSINGLE 0x28 /* Initialize Single Speed */ +#define COMINITDOUBLE 0x29 /* Initialize Double Speed */ +#define COMUNLOCK 0x30 /* Unlock */ +#define COMLOCK 0x31 /* Lock */ +#define COMLOCKST 0x32 /* Lock/Unlock Status */ +#define COMVERSION 0x40 /* Get Firmware Revision */ +#define COMVOIDREADMODE 0x50 /* Void Data Read Mode */ +/* Read commands */ +#define COMFETCH 0x60 /* Prefetch Data */ +#define COMREAD 0x61 /* Read */ +#define COMREADRAW 0x62 /* Read Raw Data */ +#define COMREADALL 0x63 /* Read All 2646 Bytes */ +/* Player control commands */ +#define COMLEADIN 0x70 /* Seek To Lead-in */ +#define COMSEEK 0x71 /* Seek */ +#define COMPAUSEON 0x80 /* Pause On */ +#define COMPAUSEOFF 0x81 /* Pause Off */ +#define COMSTOP 0x82 /* Stop */ +#define COMOPEN 0x90 /* Open Tray Door */ +#define COMCLOSE 0x91 /* Close Tray Door */ +#define COMPLAY 0xa0 /* Audio Play */ +#define COMPLAY_TNO 0xa2 /* Audio Play By Track Number */ +#define COMSUBQ 0xb0 /* Read Sub-q Code */ +#define COMLOCATION 0xb1 /* Read Head Position */ +/* Audio control commands */ +#define COMCHCTRL 0xc0 /* Audio Channel Control */ +/* Miscellaneous (test) commands */ +#define COMDRVTEST 0xd0 /* Write Test Bytes */ +#define COMTEST 0xd1 /* Diagnostic Test */ + +/* Low level drive interface. Only here we do actual I/O + Waiting for status / data available */ + + +/* Busy wait until FLAG goes low. Return 0 on timeout. */ +inline static int flag_low(int flag, unsigned long timeout) +{ + int flag_high; unsigned long count = 0; - while ((no_data = (optFlags() & FL_DTEN))) - if (++count >= BUSY_TIMEOUT) + + while ((flag_high = (inb(STATUS_PORT) & flag))) + if (++count >= timeout) break; -#ifdef DEBUG_DRIVE_IF - if (no_data) - printk("optcd: timeout waiting for DTEN low\n"); - else - printk("optcd: DTEN low after %ld\n", count); -#endif - return no_data; + + DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s", + flag, count, flag_high ? " timeout" : "")); + return !flag_high; } -/* Facilities for polled waiting for status or data */ -static int sleep_timeout; /* Max amount of time still to sleep */ -static unsigned char sleep_flags; /* Flags read last time around */ + +/* Timed waiting for status or data */ +static int sleep_timeout; /* max # of ticks to sleep */ static struct wait_queue *waitq = NULL; static struct timer_list delay_timer = {NULL, NULL, 0, 0, NULL}; -/* Timer routine: wake up when either of FL_STEN or FL_DTEN goes down, - * or when timeout expires. Otherwise wait some more. - */ -static void sleep_timer(void) { - if ((sleep_flags = optFlags()) != FL_STDT) { - wake_up(&waitq); - return; - } - if (--sleep_timeout <= 0) { +#define SET_TIMER(func, jifs) \ + delay_timer.expires = jiffies+(jifs); \ + delay_timer.function = (void *) (func); \ + add_timer(&delay_timer); +#define CLEAR_TIMER del_timer(&delay_timer) + + +/* Timer routine: wake up when desired flag goes low, + or when timeout expires. */ +static void sleep_timer(void) +{ + int flags = inb(STATUS_PORT) & FL_STDT; + + if (flags == FL_STDT && --sleep_timeout > 0) { + SET_TIMER(sleep_timer, HZ/100); /* multi-statement macro */ + } else wake_up(&waitq); - return; - } - SET_TIMER(sleep_timer, 1); } -/* Sleep until any of FL_STEN or FL_DTEN go down, or until timeout. - * sleep_timeout must be set first. - */ -static int sleep_status(void) { -#ifdef DEBUG_DRIVE_IF - printk("optcd: sleeping %d on status\n", sleep_timeout); -#endif - if (sleep_timeout <= 0) /* timeout immediately */ - return FL_STDT; - if ((sleep_flags = optFlags()) == FL_STDT) { - SET_TIMER(sleep_timer, 1); + +/* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */ +static int sleep_flag_low(int flag, unsigned long timeout) +{ + int flag_high; + + DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low")); + + sleep_timeout = timeout; + flag_high = inb(STATUS_PORT) & flag; + if (flag_high && sleep_timeout > 0) { + SET_TIMER(sleep_timer, HZ/100); sleep_on(&waitq); + flag_high = inb(STATUS_PORT) & flag; } -#ifdef DEBUG_DRIVE_IF - printk("optcd: woken up with %d to go, flags %d\n", - sleep_timeout, sleep_flags); -#endif - return sleep_flags; -} -/* Sleep until status available; return TRUE on timeout */ -inline static int sleep_sten_low(void) { - int flags; - sleep_timeout = SLEEP_TIMEOUT; - flags = sleep_status(); -#ifdef DEBUG_DRIVE_IF - if (!(flags & FL_DTEN)) - printk("optcd: DTEN while waiting for STEN\n"); -#endif - return flags & FL_STEN; + DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s", + flag, timeout, flag_high ? " timeout" : "")); + return !flag_high; } + +/* Low level drive interface. Only here we do actual I/O + Sending commands and parameters */ + + +/* Errors in the command protocol */ +#define ERR_IF_CMD_TIMEOUT 0x100 +#define ERR_IF_ERR_TIMEOUT 0x101 +#define ERR_IF_RESP_TIMEOUT 0x102 +#define ERR_IF_DATA_TIMEOUT 0x103 +#define ERR_IF_NOSTAT 0x104 -/* Sleep until data available; return TRUE on timeout */ -inline static int sleep_dten_low(void) { - int flags; - sleep_timeout = SLEEP_TIMEOUT; - flags = sleep_status(); -#ifdef DEBUG_DRIVE_IF - if (!(flags & FL_STEN)) - printk("optcd: STEN while waiting for DTEN\n"); -#endif - return flags & FL_DTEN; -} /* Send command code. Return <0 indicates error */ -static int optSendCmd(int cmd) { +static int send_cmd(int cmd) +{ unsigned char ack; -#if defined(DEBUG_DRIVE_IF)||defined(DEBUG_COMMANDS) - printk("optcd: executing command 0x%02x\n", cmd); -#endif + + DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd)); + outb(HCON_DTS, HCON_PORT); /* Enable Suspend Data Transfer */ outb(cmd, COMIN_PORT); /* Send command code */ - if (sten_low()) /* Wait for status available */ + if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */ return -ERR_IF_CMD_TIMEOUT; ack = inb(DATA_PORT); /* read command acknowledge */ -#ifdef DEBUG_DRIVE_IF - printk("optcd: acknowledge code 0x%02x\n", ack); -#endif outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */ return ack==ST_OP_OK ? 0 : -ack; } + /* Send command parameters. Return <0 indicates error */ -static int optSendParams(struct opt_Play_msf *params) { +static int send_params(struct cdrom_msf *params) +{ unsigned char ack; -#if defined(DEBUG_DRIVE_IF)||defined(DEBUG_COMMANDS) - printk("optcd: params %02x:%02x:%02x %02x:%02x:%02x\n", - params->start.min, params->start.sec, params->start.frame, - params->end.min, params->end.sec, params->end.frame); -#endif - outb(params -> start.min, COMIN_PORT); - outb(params -> start.sec, COMIN_PORT); - outb(params -> start.frame, COMIN_PORT); - outb(params -> end.min, COMIN_PORT); - outb(params -> end.sec, COMIN_PORT); - outb(params -> end.frame, COMIN_PORT); - if (sten_low()) /* Wait for status available */ + + DEBUG((DEBUG_DRIVE_IF, "sending parameters" + " %02x:%02x:%02x" + " %02x:%02x:%02x", + params->cdmsf_min0, + params->cdmsf_sec0, + params->cdmsf_frame0, + params->cdmsf_min1, + params->cdmsf_sec1, + params->cdmsf_frame1)); + + outb(params->cdmsf_min0, COMIN_PORT); + outb(params->cdmsf_sec0, COMIN_PORT); + outb(params->cdmsf_frame0, COMIN_PORT); + outb(params->cdmsf_min1, COMIN_PORT); + outb(params->cdmsf_sec1, COMIN_PORT); + outb(params->cdmsf_frame1, COMIN_PORT); + if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */ return -ERR_IF_CMD_TIMEOUT; ack = inb(DATA_PORT); /* read command acknowledge */ -#ifdef DEBUG_DRIVE_IF - printk("optcd: acknowledge code 0x%02x\n", ack); -#endif return ack==ST_PA_OK ? 0 : -ack; } -/* Return execution status for quick response commands, i.e. busy wait. - * Return value <0 indicates timeout. - */ -static int optGetExecStatus(void) { - unsigned char exec_status; - if (sten_low()) /* Wait for status available */ + +/* Send parameters for SEEK command. Return <0 indicates error */ +static int send_seek_params(struct cdrom_msf *params) +{ + unsigned char ack; + + DEBUG((DEBUG_DRIVE_IF, "sending seek parameters" + " %02x:%02x:%02x", + params->cdmsf_min0, + params->cdmsf_sec0, + params->cdmsf_frame0)); + + outb(params->cdmsf_min0, COMIN_PORT); + outb(params->cdmsf_sec0, COMIN_PORT); + outb(params->cdmsf_frame0, COMIN_PORT); + if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */ return -ERR_IF_CMD_TIMEOUT; - exec_status = inb(DATA_PORT); /* read command execution status */ -#ifdef DEBUG_DRIVE_IF - printk("optcd: returned execution status: 0x%02x\n", exec_status); -#endif - return exec_status; + ack = inb(DATA_PORT); /* read command acknowledge */ + return ack==ST_PA_OK ? 0 : -ack; } -/* Return execution status for slow commands. Only use when no data is - * expected. Return value <0 indicates timeout. - */ -static int optSleepTillExecStatus(void) { + +/* Wait for command execution status. Choice between busy waiting + and sleeping. Return value <0 indicates timeout. */ +inline static int get_exec_status(int busy_waiting) +{ unsigned char exec_status; - if (sleep_sten_low()) /* Wait for status available */ + + if (busy_waiting + ? !flag_low(FL_STEN, BUSY_TIMEOUT) + : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT)) return -ERR_IF_CMD_TIMEOUT; - exec_status = inb(DATA_PORT); /* read command execution status */ -#ifdef DEBUG_DRIVE_IF - printk("optcd: returned execution status: 0x%02x\n", exec_status); -#endif + + exec_status = inb(DATA_PORT); + DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status)); return exec_status; } -/* Fetch status that has previously been waited for. <0 means not available */ -inline static int optStatus(void) { - unsigned char status; - if (optFlags() & FL_STEN) - return -ERR_IF_NOSTAT; - status = inb(DATA_PORT); -#ifdef DEBUG_DRIVE_IF - printk("optcd: read status: 0x%02x\n", status); -#endif - return status; -} -/* Wait for extra byte of data that a command returns */ -static int optGetData(void) { +/* Wait busy for extra byte of data that a command returns. + Return value <0 indicates timeout. */ +inline static int get_data(int short_timeout) +{ unsigned char data; - if (sten_low()) + + if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT)) return -ERR_IF_DATA_TIMEOUT; + data = inb(DATA_PORT); -#ifdef DEBUG_DRIVE_IF - printk("optcd: read data: 0x%02x\n", data); -#endif + DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data)); return data; } -/* Read data that has previously been waited for. */ -inline static void optReadData(char *buf, int n) { - insb(DATA_PORT, buf, n); -} - -/* Flush status and data fifos */ -inline static void optFlushData(void) { - while (optFlags() != FL_STDT) - inb(DATA_PORT); -} -/* Write something to RESET_PORT and wait. Return TRUE upon success. */ -static int optResetDrive(void) { +/* Returns 0 if failed */ +static int reset_drive(void) +{ unsigned long count = 0; int flags; -#ifdef DEBUG_DRIVE_IF - printk("optcd: reset drive\n"); -#endif + + DEBUG((DEBUG_DRIVE_IF, "reset drive")); + outb(0, RESET_PORT); while (++count < RESET_WAIT) inb(DATA_PORT); + count = 0; while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET) if (++count >= BUSY_TIMEOUT) break; -#ifdef DEBUG_DRIVE_IF - if (flags == FL_RESET) - printk("optcd: drive reset\n"); - else - printk("optcd: reset failed\n"); -#endif + + DEBUG((DEBUG_DRIVE_IF, "reset %s", + flags == FL_RESET ? "succeeded" : "failed")); + if (flags != FL_RESET) return 0; /* Reset failed */ outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */ @@ -356,345 +431,620 @@ static int optResetDrive(void) { } +/* Facilities for asynchronous operation */ + +/* Read status/data availability flags FL_STEN and FL_DTEN */ +inline static int stdt_flags(void) +{ + return inb(STATUS_PORT) & FL_STDT; +} + + +/* Fetch status that has previously been waited for. <0 means not available */ +inline static int fetch_status(void) +{ + unsigned char status; + + if (inb(STATUS_PORT) & FL_STEN) + return -ERR_IF_NOSTAT; + + status = inb(DATA_PORT); + DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status)); + return status; +} + + +/* Fetch data that has previously been waited for. */ +inline static void fetch_data(char *buf, int n) +{ + insb(DATA_PORT, buf, n); + DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n)); +} + + +/* Flush status and data fifos */ +inline static void flush_data(void) +{ + while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT) + inb(DATA_PORT); + DEBUG((DEBUG_DRIVE_IF, "flushed fifos")); +} + /* Command protocol */ -/* Send a simple command and wait for response */ -inline static int optCmd(int cmd) { - int ack = optSendCmd(cmd); + +/* Send a simple command and wait for response. Command codes < COMFETCH + are quick response commands */ +inline static int exec_cmd(int cmd) +{ + int ack = send_cmd(cmd); if (ack < 0) return ack; - if (cmd < COMFETCH) /* Quick response command */ - return optGetExecStatus(); - else /* Slow command */ - return optSleepTillExecStatus(); + return get_exec_status(cmd < COMFETCH); } -/* Send a command with parameters and wait for response */ -inline static int optPlayCmd(int cmd, struct opt_Play_msf *params) { - int ack = optSendCmd(cmd); + +/* Send a command with parameters. Don't wait for the response, + * which consists of data blocks read from the CD. */ +inline static int exec_read_cmd(int cmd, struct cdrom_msf *params) +{ + int ack = send_cmd(cmd); if (ack < 0) return ack; - if ((ack = optSendParams(params)) < 0) - return ack; - return optSleepTillExecStatus(); + return send_params(params); } -/* Send a command with parameters. Don't wait for the response, - * which consists of the data blocks read. */ -inline static int optReadCmd(int cmd, struct opt_Play_msf *params) { - int ack = optSendCmd(cmd); + +/* Send a seek command with parameters and wait for response */ +inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params) +{ + int ack = send_cmd(cmd); + if (ack < 0) + return ack; + ack = send_seek_params(params); if (ack < 0) return ack; - return optSendParams(params); + return 0; } +/* Send a command with parameters and wait for response */ +inline static int exec_long_cmd(int cmd, struct cdrom_msf *params) +{ + int ack = exec_read_cmd(cmd, params); + if (ack < 0) + return ack; + return get_exec_status(0); +} + /* Address conversion routines */ + /* Binary to BCD (2 digits) */ -inline static unsigned char bin2bcd(unsigned char p) { -#ifdef DEBUG_CONV - if (p > 99) - printk("optcd: error bin2bcd %d\n", p); -#endif - return (p % 10) | ((p / 10) << 4); +inline static void single_bin2bcd(u_char *p) +{ + DEBUG((DEBUG_CONV, "bin2bcd %02d", *p)); + *p = (*p % 10) | ((*p / 10) << 4); } -/* Linear address to minute, second, frame form */ -static void hsg2msf(long hsg, struct msf *msf) { - hsg += 150; - msf -> min = hsg / 4500; - hsg %= 4500; - msf -> sec = hsg / 75; - msf -> frame = hsg % 75; -#ifdef DEBUG_CONV - if (msf -> min >= 70) - printk("optcd: Error hsg2msf address Minutes\n"); - if (msf -> sec >= 60) - printk("optcd: Error hsg2msf address Seconds\n"); - if (msf -> frame >= 75) - printk("optcd: Error hsg2msf address Frames\n"); -#endif - msf -> min = bin2bcd(msf -> min); /* convert to BCD */ - msf -> sec = bin2bcd(msf -> sec); - msf -> frame = bin2bcd(msf -> frame); + +/* Convert entire msf struct */ +static void bin2bcd(struct cdrom_msf *msf) +{ + single_bin2bcd(&msf->cdmsf_min0); + single_bin2bcd(&msf->cdmsf_sec0); + single_bin2bcd(&msf->cdmsf_frame0); + single_bin2bcd(&msf->cdmsf_min1); + single_bin2bcd(&msf->cdmsf_sec1); + single_bin2bcd(&msf->cdmsf_frame1); +} + + +/* Linear block address to minute, second, frame form */ +static void lba2msf(int lba, struct cdrom_msf *msf) +{ + DEBUG((DEBUG_CONV, "lba2msf %d", lba)); + lba += CD_MSF_OFFSET; + msf->cdmsf_min0 = lba / 4500; lba %= 4500; + msf->cdmsf_sec0 = lba / 75; + msf->cdmsf_frame0 = lba % 75; + msf->cdmsf_min1 = 0; + msf->cdmsf_sec1 = 0; + msf->cdmsf_frame1 = 0; + bin2bcd(msf); } + /* Two BCD digits to binary */ -inline static int bcd2bin(unsigned char bcd) { +inline static u_char bcd2bin(u_char bcd) +{ + DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd)); return (bcd >> 4) * 10 + (bcd & 0x0f); } -/* Minute, second, frame address to linear address */ -static long msf2hsg(struct msf *mp) { -#ifdef DEBUG_CONV - if (mp -> min >= 70) - printk("optcd: Error msf2hsg address Minutes\n"); - if (mp -> sec >= 60) - printk("optcd: Error msf2hsg address Seconds\n"); - if (mp -> frame >= 75) - printk("optcd: Error msf2hsg address Frames\n"); -#endif - return bcd2bin(mp -> frame) - + bcd2bin(mp -> sec) * 75 - + bcd2bin(mp -> min) * 4500 - - 150; + +union cd_addr { + struct { + u_char minute; + u_char second; + u_char frame; + } msf; + int lba; +}; + + +static void msf2lba(union cd_addr *addr) +{ + addr->lba = addr->msf.minute * 4500 + + addr->msf.second * 75 + + addr->msf.frame - CD_MSF_OFFSET; +} + + +/* Minute, second, frame address BCD to binary or to linear address, + depending on MODE */ +static void msf_bcd2bin(union cd_addr *addr) +{ + addr->msf.minute = bcd2bin(addr->msf.minute); + addr->msf.second = bcd2bin(addr->msf.second); + addr->msf.frame = bcd2bin(addr->msf.frame); } + +/* High level drive commands */ -/* Drive status and table of contents */ +static int audio_status = CDROM_AUDIO_NO_STATUS; +static char toc_uptodate = 0; -static int optAudioStatus = CDROM_AUDIO_NO_STATUS; -static char optDiskChanged = 1; -static char optTocUpToDate = 0; -static struct opt_DiskInfo DiskInfo; -static struct opt_Toc Toc[MAX_TRACKS]; +/* Get drive status, flagging completion of audio play and disk changes. */ +static int drive_status(void) +{ + int status; -/* Get CDROM status, flagging completion of audio play and disk changes. */ -static int optGetStatus(void) { - int st; - if ((st = optCmd(COMIOCTLISTAT)) < 0) - return st; - if (st == 0xff) + status = exec_cmd(COMIOCTLISTAT); + DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status)); + if (status < 0) + return status; + if (status == 0xff) /* No status available */ return -ERR_IF_NOSTAT; - if (((st & ST_MODE_BITS) != ST_M_AUDIO) && - (optAudioStatus == CDROM_AUDIO_PLAY)) { - optAudioStatus = CDROM_AUDIO_COMPLETED; + + if (((status & ST_MODE_BITS) != ST_M_AUDIO) && + (audio_status == CDROM_AUDIO_PLAY)) { + audio_status = CDROM_AUDIO_COMPLETED; } - if (st & ST_DSK_CHG) { - optDiskChanged = 1; - optTocUpToDate = 0; - optAudioStatus = CDROM_AUDIO_NO_STATUS; + + if (status & ST_DSK_CHG) { + toc_uptodate = 0; + audio_status = CDROM_AUDIO_NO_STATUS; } - return st; + + return status; } -/* - * Read the current Q-channel info. Also used for reading the - * table of contents. - */ -static int optGetQChannelInfo(struct opt_Toc *qp) { - int st; -#ifdef DEBUG_TOC - printk("optcd: starting optGetQChannelInfo\n"); -#endif - if ((st = optGetStatus()) < 0) - return st; - if ((st = optCmd(COMSUBQ)) < 0) - return st; - if ((qp -> ctrl_addr = st = optGetData()), st < 0) return st; - if ((qp -> track = st = optGetData()), st < 0) return st; - if ((qp -> pointIndex = st = optGetData()), st < 0) return st; - if ((qp -> trackTime.min = st = optGetData()), st < 0) return st; - if ((qp -> trackTime.sec = st = optGetData()), st < 0) return st; - if ((qp -> trackTime.frame = st = optGetData()), st < 0) return st; - if ((st = optGetData()) < 0) return st; /* byte not used */ - if ((qp -> diskTime.min = st = optGetData()), st < 0) return st; - if ((qp -> diskTime.sec = st = optGetData()), st < 0) return st; - if ((qp -> diskTime.frame = st = optGetData()), st < 0) return st; -#ifdef DEBUG_TOC - printk("optcd: exiting optGetQChannelInfo\n"); -#endif + +/* Read the current Q-channel info. Also used for reading the + table of contents. qp->cdsc_format must be set on entry to + indicate the desired address format */ +static int get_q_channel(struct cdrom_subchnl *qp) +{ + int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10; + + status = drive_status(); + if (status < 0) + return status; + qp->cdsc_audiostatus = audio_status; + + status = exec_cmd(COMSUBQ); + if (status < 0) + return status; + + d1 = get_data(0); + if (d1 < 0) + return d1; + qp->cdsc_adr = d1; + qp->cdsc_ctrl = d1 >> 4; + + d2 = get_data(0); + if (d2 < 0) + return d2; + qp->cdsc_trk = bcd2bin(d2); + + d3 = get_data(0); + if (d3 < 0) + return d3; + qp->cdsc_ind = bcd2bin(d3); + + d4 = get_data(0); + if (d4 < 0) + return d4; + qp->cdsc_reladdr.msf.minute = d4; + + d5 = get_data(0); + if (d5 < 0) + return d5; + qp->cdsc_reladdr.msf.second = d5; + + d6 = get_data(0); + if (d6 < 0) + return d6; + qp->cdsc_reladdr.msf.frame = d6; + + d7 = get_data(0); + if (d7 < 0) + return d7; + /* byte not used */ + + d8 = get_data(0); + if (d8 < 0) + return d8; + qp->cdsc_absaddr.msf.minute = d8; + + d9 = get_data(0); + if (d9 < 0) + return d9; + qp->cdsc_absaddr.msf.second = d9; + + d10 = get_data(0); + if (d10 < 0) + return d10; + qp->cdsc_absaddr.msf.frame = d10; + + DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + d1, d2, d3, d4, d5, d6, d7, d8, d9, d10)); + + msf_bcd2bin((union cd_addr *)/*%%*/&qp->cdsc_absaddr); + msf_bcd2bin((union cd_addr *)/*%%*/&qp->cdsc_reladdr); + if (qp->cdsc_format == CDROM_LBA) { + msf2lba((union cd_addr *)/*%%*/&qp->cdsc_absaddr); + msf2lba((union cd_addr *)/*%%*/&qp->cdsc_reladdr); + } + return 0; } + +/* Table of contents handling */ -#define QINFO_FIRSTTRACK 0xa0 -#define QINFO_LASTTRACK 0xa1 -#define QINFO_DISKLENGTH 0xa2 -static int optGetDiskInfo(void) { - int st, limit; - unsigned char test = 0; - struct opt_Toc qInfo; -#ifdef DEBUG_TOC - printk("optcd: starting optGetDiskInfo\n"); -#endif - optDiskChanged = 0; - if ((st = optCmd(COMLEADIN)) < 0) - return st; - for (limit = 300; (limit > 0) && (test != 0x0f); limit--) { - if ((st = optGetQChannelInfo(&qInfo)) < 0) - return st; - switch (qInfo.pointIndex) { - case QINFO_FIRSTTRACK: - DiskInfo.first = bcd2bin(qInfo.diskTime.min); -#ifdef DEBUG_TOC - printk("optcd: got first: %d\n", DiskInfo.first); -#endif - test |= 0x01; - break; - case QINFO_LASTTRACK: - DiskInfo.last = bcd2bin(qInfo.diskTime.min); -#ifdef DEBUG_TOC - printk("optcd: got last: %d\n", DiskInfo.last); -#endif - test |= 0x02; - break; - case QINFO_DISKLENGTH: - DiskInfo.diskLength.min = qInfo.diskTime.min; - DiskInfo.diskLength.sec = qInfo.diskTime.sec-2; - DiskInfo.diskLength.frame = qInfo.diskTime.frame; -#ifdef DEBUG_TOC - printk("optcd: got length: %x:%x.%x\n", - DiskInfo.diskLength.min, - DiskInfo.diskLength.sec, - DiskInfo.diskLength.frame); +/* Errors in table of contents */ +#define ERR_TOC_MISSINGINFO 0x120 +#define ERR_TOC_MISSINGENTRY 0x121 + + +struct msf { + u_char minute; + u_char second; + u_char frame; +}; + +struct cdrom_disk_info { + unsigned char first; + unsigned char last; + struct msf disk_length; + struct msf first_track; + /* Multisession info: */ + unsigned char next; + struct msf next_session; + struct msf last_session; + unsigned char multi; + unsigned char xa; + unsigned char audio; +}; +static struct cdrom_disk_info disk_info; + +#define MAX_TRACKS 111 +static struct cdrom_subchnl toc[MAX_TRACKS]; + +#define QINFO_FIRSTTRACK 100 /* bcd2bin(0xa0) */ +#define QINFO_LASTTRACK 101 /* bcd2bin(0xa1) */ +#define QINFO_DISKLENGTH 102 /* bcd2bin(0xa2) */ +#define QINFO_NEXTSESSION 110 /* bcd2bin(0xb0) */ + +#define I_FIRSTTRACK 0x01 +#define I_LASTTRACK 0x02 +#define I_DISKLENGTH 0x04 +#define I_NEXTSESSION 0x08 +#define I_ALL (I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH) + + +#if DEBUG_TOC +void toc_debug_info(int i) +{ + printk("#%3d ctl %1x, adr %1x, track %2d index %3d" + " %2d:%02d.%02d %2d:%02d.%02d\n", + i, toc[i].cdsc_ctrl, toc[i].cdsc_adr, + toc[i].cdsc_trk, toc[i].cdsc_ind, + toc[i].cdsc_reladdr.msf.minute, + toc[i].cdsc_reladdr.msf.second, + toc[i].cdsc_reladdr.msf.frame, + toc[i].cdsc_absaddr.msf.minute, + toc[i].cdsc_absaddr.msf.second, + toc[i].cdsc_absaddr.msf.frame); +} #endif - test |= 0x04; - break; - default: - if ((test & 0x01) /* Got no of first track */ - && (qInfo.pointIndex == DiskInfo.first)) { - /* StartTime of First Track */ - DiskInfo.firstTrack.min = qInfo.diskTime.min; - DiskInfo.firstTrack.sec = qInfo.diskTime.sec; - DiskInfo.firstTrack.frame = qInfo.diskTime.frame; -#ifdef DEBUG_TOC - printk("optcd: got start: %x:%x.%x\n", - DiskInfo.firstTrack.min, - DiskInfo.firstTrack.sec, - DiskInfo.firstTrack.frame); + + +static int read_toc(void) +{ + int status, limit, count; + unsigned char got_info = 0; + struct cdrom_subchnl q_info; +#if DEBUG_TOC + int i; #endif - test |= 0x08; + + DEBUG((DEBUG_TOC, "starting read_toc")); + + count = 0; + for (limit = 60; limit > 0; limit--) { + int index; + + q_info.cdsc_format = CDROM_MSF; + status = get_q_channel(&q_info); + if (status < 0) + return status; + + index = q_info.cdsc_ind; + if (index > 0 && index < MAX_TRACKS + && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) { + toc[index] = q_info; + DEBUG((DEBUG_TOC, "got %d", index)); + if (index < 100) + count++; + + switch (q_info.cdsc_ind) { + case QINFO_FIRSTTRACK: + got_info |= I_FIRSTTRACK; + break; + case QINFO_LASTTRACK: + got_info |= I_LASTTRACK; + break; + case QINFO_DISKLENGTH: + got_info |= I_DISKLENGTH; + break; + case QINFO_NEXTSESSION: + got_info |= I_NEXTSESSION; + break; } } + + if ((got_info & I_ALL) == I_ALL + && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count + >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1) + break; + } + + /* Construct disk_info from TOC */ + if (disk_info.first == 0) { + disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute; + disk_info.first_track.minute = + toc[disk_info.first].cdsc_absaddr.msf.minute; + disk_info.first_track.second = + toc[disk_info.first].cdsc_absaddr.msf.second; + disk_info.first_track.frame = + toc[disk_info.first].cdsc_absaddr.msf.frame; } -#ifdef DEBUG_TOC - printk("optcd: exiting optGetDiskInfo\n"); + disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute; + disk_info.disk_length.minute = + toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute; + disk_info.disk_length.second = + toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2; + disk_info.disk_length.frame = + toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame; + disk_info.next_session.minute = + toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute; + disk_info.next_session.second = + toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second; + disk_info.next_session.frame = + toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame; + disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute; + disk_info.last_session.minute = + toc[disk_info.next].cdsc_absaddr.msf.minute; + disk_info.last_session.second = + toc[disk_info.next].cdsc_absaddr.msf.second; + disk_info.last_session.frame = + toc[disk_info.next].cdsc_absaddr.msf.frame; + toc[disk_info.last + 1].cdsc_absaddr.msf.minute = + disk_info.disk_length.minute; + toc[disk_info.last + 1].cdsc_absaddr.msf.second = + disk_info.disk_length.second; + toc[disk_info.last + 1].cdsc_absaddr.msf.frame = + disk_info.disk_length.frame; +#if DEBUG_TOC + for (i = 1; i <= disk_info.last + 1; i++) + toc_debug_info(i); + toc_debug_info(QINFO_FIRSTTRACK); + toc_debug_info(QINFO_LASTTRACK); + toc_debug_info(QINFO_DISKLENGTH); + toc_debug_info(QINFO_NEXTSESSION); #endif - if (test != 0x0f) + + DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d", + got_info, count)); + if ((got_info & I_ALL) != I_ALL + || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count + < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1) return -ERR_TOC_MISSINGINFO; return 0; } -static int optGetToc(void) { /* Presumes we have got DiskInfo */ - int st, count, px, limit; - struct opt_Toc qInfo; -#ifdef DEBUG_TOC - int i; - printk("optcd: starting optGetToc\n"); -#endif - for (count = 0; count < MAX_TRACKS; count++) - Toc[count].pointIndex = 0; - if ((st = optCmd(COMLEADIN)) < 0) - return st; - st = 0; - count = DiskInfo.last + 3; - for (limit = 300; (limit > 0) && (count > 0); limit--) { - if ((st = optGetQChannelInfo(&qInfo)) < 0) + +#ifdef MULTISESSION +static int get_multi_disk_info(void) +{ + int sessions, status; + struct cdrom_msf multi_index; + + + for (sessions = 2; sessions < 10 /* %%for now */; sessions++) { + int count; + + for (count = 100; count < MAX_TRACKS; count++) + toc[count].cdsc_ind = 0; + + multi_index.cdmsf_min0 = disk_info.next_session.minute; + multi_index.cdmsf_sec0 = disk_info.next_session.second; + multi_index.cdmsf_frame0 = disk_info.next_session.frame; + if (multi_index.cdmsf_sec0 >= 20) + multi_index.cdmsf_sec0 -= 20; + else { + multi_index.cdmsf_sec0 += 40; + multi_index.cdmsf_min0--; + } + DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions, + multi_index.cdmsf_min0, + multi_index.cdmsf_sec0, + multi_index.cdmsf_frame0)); + bin2bcd(&multi_index); + multi_index.cdmsf_min1 = 0; + multi_index.cdmsf_sec1 = 0; + multi_index.cdmsf_frame1 = 1; + + status = exec_read_cmd(COMREAD, &multi_index); + if (status < 0) { + DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x", + -status)); break; - px = bcd2bin(qInfo.pointIndex); - if (px > 0 && px < MAX_TRACKS && qInfo.track == 0) - if (Toc[px].pointIndex == 0) { - Toc[px] = qInfo; - count--; - } + } + status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ? + 0 : -ERR_TOC_MISSINGINFO; + flush_data(); + if (status < 0) { + DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status)); + break; + } + + status = read_toc(); + if (status < 0) { + DEBUG((DEBUG_TOC, "read_toc: %02x", -status)); + break; + } + + disk_info.multi = 1; } - Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength; -#ifdef DEBUG_TOC - printk("optcd: exiting optGetToc\n"); - for (i = 1; i <= DiskInfo.last + 1; i++) - printk("i = %3d ctl-adr = %02x track %2d px " - "%02x %02x:%02x.%02x %02x:%02x.%02x\n", - i, Toc[i].ctrl_addr, - Toc[i].track, - Toc[i].pointIndex, - Toc[i].trackTime.min, - Toc[i].trackTime.sec, - Toc[i].trackTime.frame, - Toc[i].diskTime.min, - Toc[i].diskTime.sec, - Toc[i].diskTime.frame); - for (i = 100; i < 103; i++) - printk("i = %3d ctl-adr = %02x track %2d px " - "%02x %02x:%02x.%02x %02x:%02x.%02x\n", - i, Toc[i].ctrl_addr, - Toc[i].track, - Toc[i].pointIndex, - Toc[i].trackTime.min, - Toc[i].trackTime.sec, - Toc[i].trackTime.frame, - Toc[i].diskTime.min, - Toc[i].diskTime.sec, - Toc[i].diskTime.frame); -#endif - return count ? -ERR_TOC_MISSINGENTRY : 0; + + exec_cmd(COMSTOP); + + if (status < 0) + return -EIO; + return 0; } +#endif MULTISESSION -static int optUpdateToc(void) { -#ifdef DEBUG_TOC - printk("optcd: starting optUpdateToc\n"); -#endif - if (optTocUpToDate) + +static int update_toc(void) +{ + int status, count; + + if (toc_uptodate) return 0; - if (optGetDiskInfo() < 0) + + DEBUG((DEBUG_TOC, "starting update_toc")); + + disk_info.first = 0; + for (count = 0; count < MAX_TRACKS; count++) + toc[count].cdsc_ind = 0; + + status = exec_cmd(COMLEADIN); + if (status < 0) return -EIO; - if (optGetToc() < 0) + + status = read_toc(); + if (status < 0) { + DEBUG((DEBUG_TOC, "read_toc: %02x", -status)); return -EIO; - optTocUpToDate = 1; -#ifdef DEBUG_TOC - printk("optcd: exiting optUpdateToc\n"); -#endif + } + + /* Audio disk detection. Look at first track. */ + disk_info.audio = + (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1; + + /* XA detection */ + disk_info.xa = drive_status() & ST_MODE2TRACK; + + /* Multisession detection: if we want this, define MULTISESSION */ + disk_info.multi = 0; +#ifdef MULTISESSION + if (disk_info.xa) + get_multi_disk_info(); /* Here disk_info.multi is set */ +#endif MULTISESSION + if (disk_info.multi) + printk("optcd: Multisession support experimental, " + "see linux/Documentation/cdrom/optcd\n"); + + DEBUG((DEBUG_TOC, "exiting update_toc")); + + toc_uptodate = 1; return 0; } + +/* Request handling */ + +#define CURRENT_VALID \ + (CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \ + && CURRENT -> cmd == READ && CURRENT -> sector != -1) -/* Buffers */ -#define OPT_BUF_SIZ 16 -#define OPT_BLOCKSIZE 2048 -#define OPT_BLOCKSIZE_RAW 2336 -#define OPT_BLOCKSIZE_ALL 2646 -#define OPT_NOBUF -1 +#define BLOCKSIZE 2048 +#define BLOCKSIZE_RAW 2336 +#define BLOCKSIZE_ALL 2646 +#define N_BUFS 16 +#define NOBUF -1 + /* Buffer for block size conversion. */ -static char opt_buf[OPT_BLOCKSIZE*OPT_BUF_SIZ]; -static volatile int opt_buf_bn[OPT_BUF_SIZ], opt_next_bn; -static volatile int opt_buf_in = 0, opt_buf_out = OPT_NOBUF; +static char buf[BLOCKSIZE * N_BUFS]; +static volatile int buf_bn[N_BUFS], next_bn; +static volatile int buf_in = 0, buf_out = NOBUF; -inline static void opt_invalidate_buffers(void) { +inline static void opt_invalidate_buffers(void) +{ int i; -#ifdef DEBUG_BUFFERS - printk("optcd: executing opt_invalidate_buffers\n"); -#endif - for (i = 0; i < OPT_BUF_SIZ; i++) - opt_buf_bn[i] = OPT_NOBUF; - opt_buf_out = OPT_NOBUF; + + DEBUG((DEBUG_BUFFERS, "executing opt_invalidate_buffers")); + + for (i = 0; i < N_BUFS; i++) + buf_bn[i] = NOBUF; + buf_out = NOBUF; } -/* - * Take care of the different block sizes between cdrom and Linux. - * When Linux gets variable block sizes this will probably go away. - */ -static void opt_transfer(void) { -#if (defined DEBUG_BUFFERS) || (defined DEBUG_REQUEST) - printk("optcd: executing opt_transfer\n"); + +/* Take care of the different block sizes between cdrom and Linux. + When Linux gets variable block sizes this will probably go away. */ +static void transfer(void) +{ +#if DEBUG_BUFFERS | DEBUG_REQUEST + printk("optcd: executing transfer\n"); #endif + if (!CURRENT_VALID) return; while (CURRENT -> nr_sectors) { int bn = CURRENT -> sector / 4; int i, offs, nr_sectors; - for (i = 0; i < OPT_BUF_SIZ && opt_buf_bn[i] != bn; ++i); -#ifdef DEBUG_REQUEST - printk("optcd: found %d\n", i); -#endif - if (i >= OPT_BUF_SIZ) { - opt_buf_out = OPT_NOBUF; + for (i = 0; i < N_BUFS && buf_bn[i] != bn; ++i); + + DEBUG((DEBUG_REQUEST, "found %d", i)); + + if (i >= N_BUFS) { + buf_out = NOBUF; break; } + offs = (i * 4 + (CURRENT -> sector & 3)) * 512; nr_sectors = 4 - (CURRENT -> sector & 3); - if (opt_buf_out != i) { - opt_buf_out = i; - if (opt_buf_bn[i] != bn) { - opt_buf_out = OPT_NOBUF; + + if (buf_out != i) { + buf_out = i; + if (buf_bn[i] != bn) { + buf_out = NOBUF; continue; } } + if (nr_sectors > CURRENT -> nr_sectors) nr_sectors = CURRENT -> nr_sectors; - memcpy(CURRENT -> buffer, opt_buf + offs, nr_sectors * 512); + memcpy(CURRENT -> buffer, buf + offs, nr_sectors * 512); CURRENT -> nr_sectors -= nr_sectors; CURRENT -> sector += nr_sectors; CURRENT -> buffer += nr_sectors * 512; @@ -704,216 +1054,219 @@ static void opt_transfer(void) { /* State machine for reading disk blocks */ -enum opt_state_e { - OPT_S_IDLE, /* 0 */ - OPT_S_START, /* 1 */ - OPT_S_READ, /* 2 */ - OPT_S_DATA, /* 3 */ - OPT_S_STOP, /* 4 */ - OPT_S_STOPPING /* 5 */ +enum state_e { + S_IDLE, /* 0 */ + S_START, /* 1 */ + S_READ, /* 2 */ + S_DATA, /* 3 */ + S_STOP, /* 4 */ + S_STOPPING /* 5 */ }; -static volatile enum opt_state_e opt_state = OPT_S_IDLE; -#ifdef DEBUG_STATE -static volatile enum opt_state_e opt_state_old = OPT_S_STOP; -static volatile int opt_st_old = 0; -static volatile long opt_state_n = 0; +static volatile enum state_e state = S_IDLE; +#if DEBUG_STATE +static volatile enum state_e state_old = S_STOP; +static volatile int flags_old = 0; +static volatile long state_n = 0; #endif -static volatile int opt_transfer_is_active = 0; -static volatile int opt_error = 0; /* do something with this?? */ -static int optTries; /* ibid?? */ -static void opt_poll(void) { - static int optTimeout; - static volatile int opt_read_count = 1; - int st = 0; - int loop_ctl = 1; +static volatile int transfer_is_active = 0; +static volatile int error = 0; /* %% do something with this?? */ +static int tries; /* ibid?? */ + +static void poll(void) +{ + static int timeout; + static volatile int read_count = 1; + int flags; + int loop_again = 1; + int status = 0; int skip = 0; - if (opt_error) { - printk("optcd: I/O error 0x%02x\n", opt_error); + if (error) { + printk("optcd: I/O error 0x%02x\n", error); opt_invalidate_buffers(); -#ifdef WARN_IF_READ_FAILURE - if (optTries == 5) - printk("optcd: read block %d failed; audio disk?\n", - opt_next_bn); -#endif - if (!optTries--) { + if (!tries--) { printk("optcd: read block %d failed; Giving up\n", - opt_next_bn); - if (opt_transfer_is_active) { - optTries = 0; - loop_ctl = 0; - } + next_bn); + if (transfer_is_active) + loop_again = 0; if (CURRENT_VALID) end_request(0); - optTries = 5; + tries = 5; } - opt_error = 0; - opt_state = OPT_S_STOP; + error = 0; + state = S_STOP; } - while (loop_ctl) + while (loop_again) { - loop_ctl = 0; /* each case must flip this back to 1 if we want + loop_again = 0; /* each case must flip this back to 1 if we want to come back up here */ -#ifdef DEBUG_STATE - if (opt_state == opt_state_old) - opt_state_n++; + +#if DEBUG_STATE + if (state == state_old) + state_n++; else { - opt_state_old = opt_state; - if (++opt_state_n > 1) + state_old = state; + if (++state_n > 1) printk("optcd: %ld times in previous state\n", - opt_state_n); - printk("optcd: state %d\n", opt_state); - opt_state_n = 0; + state_n); + printk("optcd: state %d\n", state); + state_n = 0; } #endif - switch (opt_state) { - case OPT_S_IDLE: + + switch (state) { + case S_IDLE: return; - case OPT_S_START: - if (optSendCmd(COMDRVST)) + case S_START: + if (send_cmd(COMDRVST)) return; - opt_state = OPT_S_READ; - optTimeout = 3000; + state = S_READ; + timeout = READ_TIMEOUT; break; - case OPT_S_READ: { - struct opt_Play_msf msf; + case S_READ: { + struct cdrom_msf msf; if (!skip) { - if ((st = optStatus()) < 0) + status = fetch_status(); + if (status < 0) break; - if (st & ST_DSK_CHG) { - optDiskChanged = 1; - optTocUpToDate = 0; + if (status & ST_DSK_CHG) { + toc_uptodate = 0; opt_invalidate_buffers(); } } skip = 0; - if ((st & ST_DOOR_OPEN) || (st & ST_DRVERR)) { - optDiskChanged = 1; - optTocUpToDate = 0; - printk((st & ST_DOOR_OPEN) + if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) { + toc_uptodate = 0; + printk((status & ST_DOOR_OPEN) ? "optcd: door open\n" : "optcd: disk removed\n"); - if (opt_transfer_is_active) { - opt_state = OPT_S_START; - loop_ctl = 1; + if (transfer_is_active) { + state = S_START; + loop_again = 1; break; } - opt_state = OPT_S_IDLE; + state = S_IDLE; while (CURRENT_VALID) end_request(0); return; } if (!CURRENT_VALID) { - opt_state = OPT_S_STOP; - loop_ctl = 1; + state = S_STOP; + loop_again = 1; break; } - opt_next_bn = CURRENT -> sector / 4; - hsg2msf(opt_next_bn, &msf.start); - opt_read_count = OPT_BUF_SIZ; - msf.end.min = 0; - msf.end.sec = 0; - msf.end.frame = opt_read_count; -#ifdef DEBUG_REQUEST - printk("optcd: reading %x:%x.%x %x:%x.%x\n", - msf.start.min, - msf.start.sec, - msf.start.frame, - msf.end.min, - msf.end.sec, - msf.end.frame); - printk("optcd: opt_next_bn:%d opt_buf_in:%d opt_buf_out:%d opt_buf_bn:%d\n", - opt_next_bn, - opt_buf_in, - opt_buf_out, - opt_buf_bn[opt_buf_in]); -#endif - optReadCmd(COMREAD, &msf); - opt_state = OPT_S_DATA; - optTimeout = READ_TIMEOUT; + next_bn = CURRENT -> sector / 4; + lba2msf(next_bn, &msf); + read_count = N_BUFS; + msf.cdmsf_frame1 = read_count; /* Not BCD! */ + + DEBUG((DEBUG_REQUEST, "reading %x:%x.%x %x:%x.%x", + msf.cdmsf_min0, + msf.cdmsf_sec0, + msf.cdmsf_frame0, + msf.cdmsf_min1, + msf.cdmsf_sec1, + msf.cdmsf_frame1)); + DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d" + " buf_out:%d buf_bn:%d", + next_bn, + buf_in, + buf_out, + buf_bn[buf_in])); + + exec_read_cmd(COMREAD, &msf); + state = S_DATA; + timeout = READ_TIMEOUT; break; } - case OPT_S_DATA: - st = optFlags() & (FL_STEN|FL_DTEN); -#ifdef DEBUG_STATE - if (st != opt_st_old) { - opt_st_old = st; - printk("optcd: st:%x\n", st); + case S_DATA: + flags = stdt_flags() & (FL_STEN|FL_DTEN); + +#if DEBUG_STATE + if (flags != flags_old) { + flags_old = flags; + printk("optcd: flags:%x\n", flags); } - if (st == FL_STEN) - printk("timeout cnt: %d\n", optTimeout); -#endif - switch (st) { - case FL_DTEN: -#ifdef WARN_IF_READ_FAILURE - if (optTries == 5) - printk("optcd: read block %d failed; audio disk?\n", - opt_next_bn); + if (flags == FL_STEN) + printk("timeout cnt: %d\n", timeout); #endif - if (!optTries--) { - printk("optcd: read block %d failed; Giving up\n", - opt_next_bn); - if (opt_transfer_is_active) { - optTries = 0; + + switch (flags) { + case FL_DTEN: /* only STEN low */ + if (!tries--) { + printk("optcd: read block %d failed; " + "Giving up\n", next_bn); + if (transfer_is_active) { + tries = 0; break; } if (CURRENT_VALID) end_request(0); - optTries = 5; + tries = 5; } - opt_state = OPT_S_START; - optTimeout = READ_TIMEOUT; - loop_ctl = 1; - case (FL_STEN|FL_DTEN): + state = S_START; + timeout = READ_TIMEOUT; + loop_again = 1; + case (FL_STEN|FL_DTEN): /* both high */ break; - default: - optTries = 5; - if (!CURRENT_VALID && opt_buf_in == opt_buf_out) { - opt_state = OPT_S_STOP; - loop_ctl = 1; + default: /* DTEN low */ + tries = 5; + if (!CURRENT_VALID && buf_in == buf_out) { + state = S_STOP; + loop_again = 1; break; } - if (opt_read_count<=0) - printk("optcd: warning - try to read 0 frames\n"); - while (opt_read_count) { - opt_buf_bn[opt_buf_in] = OPT_NOBUF; - if (dten_low()) { /* should be no waiting here!?? */ - printk("read_count:%d CURRENT->nr_sectors:%ld opt_buf_in:%d\n", - opt_read_count, + if (read_count<=0) + printk("optcd: warning - try to read" + " 0 frames\n"); + while (read_count) { + buf_bn[buf_in] = NOBUF; + if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) { + /* should be no waiting here!?? */ + printk("read_count:%d " + "CURRENT->nr_sectors:%ld " + "buf_in:%d\n", + read_count, CURRENT->nr_sectors, - opt_buf_in); - printk("opt_transfer_is_active:%x\n", - opt_transfer_is_active); - opt_read_count = 0; - opt_state = OPT_S_STOP; - loop_ctl = 1; + buf_in); + printk("transfer active: %x\n", + transfer_is_active); + read_count = 0; + state = S_STOP; + loop_again = 1; end_request(0); break; } - optReadData(opt_buf+OPT_BLOCKSIZE*opt_buf_in, OPT_BLOCKSIZE); - opt_read_count--; -#ifdef DEBUG_REQUEST - printk("OPT_S_DATA; ---I've read data- read_count: %d\n", - opt_read_count); - printk("opt_next_bn:%d opt_buf_in:%d opt_buf_out:%d opt_buf_bn:%d\n", - opt_next_bn, - opt_buf_in, - opt_buf_out, - opt_buf_bn[opt_buf_in]); -#endif - opt_buf_bn[opt_buf_in] = opt_next_bn++; - if (opt_buf_out == OPT_NOBUF) - opt_buf_out = opt_buf_in; - opt_buf_in = opt_buf_in + 1 == - OPT_BUF_SIZ ? 0 : opt_buf_in + 1; + fetch_data(buf+ + BLOCKSIZE*buf_in, + BLOCKSIZE); + read_count--; + + DEBUG((DEBUG_REQUEST, + "S_DATA; ---I've read data- " + "read_count: %d", + read_count)); + DEBUG((DEBUG_REQUEST, + "next_bn:%d buf_in:%d " + "buf_out:%d buf_bn:%d", + next_bn, + buf_in, + buf_out, + buf_bn[buf_in])); + + buf_bn[buf_in] = next_bn++; + if (buf_out == NOBUF) + buf_out = buf_in; + buf_in = buf_in + 1 == + N_BUFS ? 0 : buf_in + 1; } - if (!opt_transfer_is_active) { + if (!transfer_is_active) { while (CURRENT_VALID) { - opt_transfer(); + transfer(); if (CURRENT -> nr_sectors == 0) end_request(1); else @@ -922,442 +1275,663 @@ static void opt_poll(void) { } if (CURRENT_VALID - && (CURRENT -> sector / 4 < opt_next_bn || + && (CURRENT -> sector / 4 < next_bn || CURRENT -> sector / 4 > - opt_next_bn + OPT_BUF_SIZ)) { - opt_state = OPT_S_STOP; - loop_ctl = 1; + next_bn + N_BUFS)) { + state = S_STOP; + loop_again = 1; break; } - optTimeout = READ_TIMEOUT; - if (opt_read_count == 0) { - opt_state = OPT_S_STOP; - loop_ctl = 1; + timeout = READ_TIMEOUT; + if (read_count == 0) { + state = S_STOP; + loop_again = 1; break; } } break; - case OPT_S_STOP: - if (opt_read_count != 0) + case S_STOP: + if (read_count != 0) printk("optcd: discard data=%x frames\n", - opt_read_count); - while (opt_read_count != 0) { - optFlushData(); - opt_read_count--; - } - if (optSendCmd(COMDRVST)) + read_count); + flush_data(); + if (send_cmd(COMDRVST)) return; - opt_state = OPT_S_STOPPING; - optTimeout = 1000; + state = S_STOPPING; + timeout = STOP_TIMEOUT; break; - case OPT_S_STOPPING: - if ((st = optStatus()) < 0 && optTimeout) + case S_STOPPING: + status = fetch_status(); + if (status < 0 && timeout) break; - if ((st != -1) && (st & ST_DSK_CHG)) { - optDiskChanged = 1; - optTocUpToDate = 0; + if ((status >= 0) && (status & ST_DSK_CHG)) { + toc_uptodate = 0; opt_invalidate_buffers(); } if (CURRENT_VALID) { - if (st != -1) { - opt_state = OPT_S_READ; - loop_ctl = 1; + if (status >= 0) { + state = S_READ; + loop_again = 1; skip = 1; break; } else { - opt_state = OPT_S_START; - optTimeout = 1; + state = S_START; + timeout = 1; } } else { - opt_state = OPT_S_IDLE; + state = S_IDLE; return; } break; default: - printk("optcd: invalid state %d\n", opt_state); + printk("optcd: invalid state %d\n", state); return; } /* case */ } /* while */ - if (!optTimeout--) { - printk("optcd: timeout in state %d\n", opt_state); - opt_state = OPT_S_STOP; - if (optCmd(COMSTOP) < 0) + if (!timeout--) { + printk("optcd: timeout in state %d\n", state); + state = S_STOP; + if (exec_cmd(COMSTOP) < 0) return; } - SET_TIMER(opt_poll, 1); + SET_TIMER(poll, HZ/100); } -static void do_optcd_request(void) { -#ifdef DEBUG_REQUEST - printk("optcd: do_optcd_request(%ld+%ld)\n", - CURRENT -> sector, CURRENT -> nr_sectors); -#endif - opt_transfer_is_active = 1; +static void do_optcd_request(void) +{ + DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)", + CURRENT -> sector, CURRENT -> nr_sectors)); + + if (disk_info.audio) { + printk("optcd: Error: tried to mount an Audio CD\n"); + end_request(0); + return; + } + + transfer_is_active = 1; while (CURRENT_VALID) { if (CURRENT->bh) { if (!buffer_locked(CURRENT->bh)) panic(DEVICE_NAME ": block not locked"); } - opt_transfer(); /* First try to transfer block from buffers */ + transfer(); /* First try to transfer block from buffers */ if (CURRENT -> nr_sectors == 0) { end_request(1); } else { /* Want to read a block not in buffer */ - opt_buf_out = OPT_NOBUF; - if (opt_state == OPT_S_IDLE) { - /* Should this block the request queue?? */ - if (optUpdateToc() < 0) { + buf_out = NOBUF; + if (state == S_IDLE) { + /* %% Should this block the request queue?? */ + if (update_toc() < 0) { while (CURRENT_VALID) end_request(0); break; } /* Start state machine */ - opt_state = OPT_S_START; - optTries = 5; - SET_TIMER(opt_poll, 1); /* why not start right away?? */ + state = S_START; + tries = 5; + /* %% why not start right away?? */ + SET_TIMER(poll, HZ/100); } break; } } - opt_transfer_is_active = 0; -#ifdef DEBUG_REQUEST - printk("opt_next_bn:%d opt_buf_in:%d opt_buf_out:%d opt_buf_bn:%d\n", - opt_next_bn, opt_buf_in, opt_buf_out, opt_buf_bn[opt_buf_in]); - printk("optcd: do_optcd_request ends\n"); -#endif + transfer_is_active = 0; + + DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d buf_out:%d buf_bn:%d", + next_bn, buf_in, buf_out, buf_bn[buf_in])); + DEBUG((DEBUG_REQUEST, "do_optcd_request ends")); } + +/* IOCTLs */ -/* VFS calls */ +static char auto_eject = 0; -static int opt_ioctl(struct inode *ip, struct file *fp, - unsigned int cmd, unsigned long arg) { - static struct opt_Play_msf opt_Play; /* pause position */ - int err; -#ifdef DEBUG_VFS - printk("optcd: starting opt_ioctl, command 0x%x\n", cmd); -#endif - if (!ip) +static int cdrompause(void) +{ + int status; + + if (audio_status != CDROM_AUDIO_PLAY) return -EINVAL; - if (optGetStatus() < 0) - return -EIO; - if ((err = optUpdateToc()) < 0) - return err; - switch (cmd) { - case CDROMPAUSE: { - struct opt_Toc qInfo; - - if (optAudioStatus != CDROM_AUDIO_PLAY) - return -EINVAL; - if (optGetQChannelInfo(&qInfo) < 0) { - /* didn't get q channel info */ - optAudioStatus = CDROM_AUDIO_NO_STATUS; - return 0; - } - opt_Play.start = qInfo.diskTime; /* restart point */ - if (optCmd(COMPAUSEON) < 0) - return -EIO; - optAudioStatus = CDROM_AUDIO_PAUSED; - break; - } - case CDROMRESUME: - if (optAudioStatus != CDROM_AUDIO_PAUSED) - return -EINVAL; - if (optPlayCmd(COMPLAY, &opt_Play) < 0) { - optAudioStatus = CDROM_AUDIO_ERROR; - return -EIO; - } - optAudioStatus = CDROM_AUDIO_PLAY; - break; - case CDROMPLAYMSF: { - int st; - struct cdrom_msf msf; - - if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof msf))) - return st; - memcpy_fromfs(&msf, (void *) arg, sizeof msf); - opt_Play.start.min = bin2bcd(msf.cdmsf_min0); - opt_Play.start.sec = bin2bcd(msf.cdmsf_sec0); - opt_Play.start.frame = bin2bcd(msf.cdmsf_frame0); - opt_Play.end.min = bin2bcd(msf.cdmsf_min1); - opt_Play.end.sec = bin2bcd(msf.cdmsf_sec1); - opt_Play.end.frame = bin2bcd(msf.cdmsf_frame1); - if (optPlayCmd(COMPLAY, &opt_Play) < 0) { - optAudioStatus = CDROM_AUDIO_ERROR; - return -EIO; - } - optAudioStatus = CDROM_AUDIO_PLAY; - break; + status = exec_cmd(COMPAUSEON); + if (status < 0) { + DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status)); + return -EIO; } - case CDROMPLAYTRKIND: { - int st; - struct cdrom_ti ti; - - if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof ti))) - return st; - memcpy_fromfs(&ti, (void *) arg, sizeof ti); - if (ti.cdti_trk0 < DiskInfo.first - || ti.cdti_trk0 > DiskInfo.last - || ti.cdti_trk1 < ti.cdti_trk0) - return -EINVAL; - if (ti.cdti_trk1 > DiskInfo.last) - ti.cdti_trk1 = DiskInfo.last; - opt_Play.start = Toc[ti.cdti_trk0].diskTime; - opt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime; -#ifdef DEBUG_VFS - printk("optcd: play %02x:%02x.%02x to %02x:%02x.%02x\n", - opt_Play.start.min, - opt_Play.start.sec, - opt_Play.start.frame, - opt_Play.end.min, - opt_Play.end.sec, - opt_Play.end.frame); -#endif - if (optPlayCmd(COMPLAY, &opt_Play) < 0) { - optAudioStatus = CDROM_AUDIO_ERROR; - return -EIO; - } - optAudioStatus = CDROM_AUDIO_PLAY; - break; + audio_status = CDROM_AUDIO_PAUSED; + return 0; +} + + +static int cdromresume(void) +{ + int status; + + if (audio_status != CDROM_AUDIO_PAUSED) + return -EINVAL; + + status = exec_cmd(COMPAUSEOFF); + if (status < 0) { + DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status)); + audio_status = CDROM_AUDIO_ERROR; + return -EIO; } - case CDROMREADTOCHDR: { /* Read the table of contents header. */ - int st; - struct cdrom_tochdr tocHdr; - - if ((st = verify_area(VERIFY_WRITE,(void *)arg,sizeof tocHdr))) - return st; - if (!optTocUpToDate) - optGetDiskInfo(); - tocHdr.cdth_trk0 = DiskInfo.first; - tocHdr.cdth_trk1 = DiskInfo.last; - memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr); - break; + audio_status = CDROM_AUDIO_PLAY; + return 0; +} + + +static int cdromplaymsf(unsigned long arg) +{ + int status; + struct cdrom_msf msf; + + status = verify_area(VERIFY_READ, (void *) arg, sizeof msf); + if (status) + return status; + memcpy_fromfs(&msf, (void *) arg, sizeof msf); + + bin2bcd(&msf); + status = exec_long_cmd(COMPLAY, &msf); + if (status < 0) { + DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status)); + audio_status = CDROM_AUDIO_ERROR; + return -EIO; } - case CDROMREADTOCENTRY: { /* Read a table of contents entry. */ - int st; - struct cdrom_tocentry entry; - struct opt_Toc *tocPtr; - - if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof entry))) - return st; - if ((st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry))) - return st; - memcpy_fromfs(&entry, (void *) arg, sizeof entry); - if (!optTocUpToDate) - optGetDiskInfo(); - if (entry.cdte_track == CDROM_LEADOUT) - tocPtr = &Toc[DiskInfo.last + 1]; - else if (entry.cdte_track > DiskInfo.last - || entry.cdte_track < DiskInfo.first) - return -EINVAL; - else - tocPtr = &Toc[entry.cdte_track]; - entry.cdte_adr = tocPtr -> ctrl_addr; - entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4; - switch (entry.cdte_format) { - case CDROM_LBA: - entry.cdte_addr.lba = msf2hsg(&tocPtr -> diskTime); - break; - case CDROM_MSF: - entry.cdte_addr.msf.minute = - bcd2bin(tocPtr -> diskTime.min); - entry.cdte_addr.msf.second = - bcd2bin(tocPtr -> diskTime.sec); - entry.cdte_addr.msf.frame = - bcd2bin(tocPtr -> diskTime.frame); - break; - default: - return -EINVAL; - } - memcpy_tofs((void *) arg, &entry, sizeof entry); - break; + + audio_status = CDROM_AUDIO_PLAY; + return 0; +} + + +static int cdromplaytrkind(unsigned long arg) +{ + int status; + struct cdrom_ti ti; + struct cdrom_msf msf; + + status = verify_area(VERIFY_READ, (void *) arg, sizeof ti); + if (status) + return status; + memcpy_fromfs(&ti, (void *) arg, sizeof ti); + + if (ti.cdti_trk0 < disk_info.first + || ti.cdti_trk0 > disk_info.last + || ti.cdti_trk1 < ti.cdti_trk0) + return -EINVAL; + if (ti.cdti_trk1 > disk_info.last) + ti.cdti_trk1 = disk_info.last; + + msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute; + msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second; + msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame; + msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute; + msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second; + msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame; + + DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d", + msf.cdmsf_min0, + msf.cdmsf_sec0, + msf.cdmsf_frame0, + msf.cdmsf_min1, + msf.cdmsf_sec1, + msf.cdmsf_frame1)); + + bin2bcd(&msf); + status = exec_long_cmd(COMPLAY, &msf); + if (status < 0) { + DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status)); + audio_status = CDROM_AUDIO_ERROR; + return -EIO; } - case CDROMSTOP: - optCmd(COMSTOP); - optAudioStatus = CDROM_AUDIO_NO_STATUS; - break; - case CDROMSTART: - optCmd(COMCLOSE); /* What else can we do? */ - break; - case CDROMEJECT: - optCmd(COMUNLOCK); - optCmd(COMOPEN); - break; - case CDROMVOLCTRL: { - int st; - struct cdrom_volctrl volctrl; - - if ((st = verify_area(VERIFY_READ, (void *) arg, - sizeof(volctrl)))) - return st; - memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl)); - opt_Play.start.min = 0x10; - opt_Play.start.sec = 0x32; - opt_Play.start.frame = volctrl.channel0; - opt_Play.end.min = volctrl.channel1; - opt_Play.end.sec = volctrl.channel2; - opt_Play.end.frame = volctrl.channel3; - if (optPlayCmd(COMCHCTRL, &opt_Play) < 0) - return -EIO; - break; + + audio_status = CDROM_AUDIO_PLAY; + return 0; +} + + +static int cdromreadtochdr(unsigned long arg) +{ + int status; + struct cdrom_tochdr tochdr; + + status = verify_area(VERIFY_WRITE, (void *) arg, sizeof tochdr); + if (status) + return status; + + tochdr.cdth_trk0 = disk_info.first; + tochdr.cdth_trk1 = disk_info.last; + + memcpy_tofs((void *) arg, &tochdr, sizeof tochdr); + return 0; +} + + +static int cdromreadtocentry(unsigned long arg) +{ + int status; + struct cdrom_tocentry entry; + struct cdrom_subchnl *tocptr; + + status = verify_area(VERIFY_READ, (void *) arg, sizeof entry); + if (status) + return status; + status = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry); + if (status) + return status; + memcpy_fromfs(&entry, (void *) arg, sizeof entry); + + if (entry.cdte_track == CDROM_LEADOUT) + tocptr = &toc[disk_info.last + 1]; + else if (entry.cdte_track > disk_info.last + || entry.cdte_track < disk_info.first) + return -EINVAL; + else + tocptr = &toc[entry.cdte_track]; + + entry.cdte_adr = tocptr->cdsc_adr; + entry.cdte_ctrl = tocptr->cdsc_ctrl; + entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute; + entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second; + entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame; + /* %% What should go into entry.cdte_datamode? */ + + if (entry.cdte_format == CDROM_LBA) + msf2lba((union cd_addr *)/*%%*/&entry.cdte_addr); + else if (entry.cdte_format != CDROM_MSF) + return -EINVAL; + + memcpy_tofs((void *) arg, &entry, sizeof entry); + return 0; +} + + +static int cdromvolctrl(unsigned long arg) +{ + int status; + struct cdrom_volctrl volctrl; + struct cdrom_msf msf; + + status = verify_area(VERIFY_READ, (void *) arg, sizeof volctrl); + if (status) + return status; + memcpy_fromfs(&volctrl, (char *) arg, sizeof volctrl); + + msf.cdmsf_min0 = 0x10; + msf.cdmsf_sec0 = 0x32; + msf.cdmsf_frame0 = volctrl.channel0; + msf.cdmsf_min1 = volctrl.channel1; + msf.cdmsf_sec1 = volctrl.channel2; + msf.cdmsf_frame1 = volctrl.channel3; + + status = exec_long_cmd(COMCHCTRL, &msf); + if (status < 0) { + DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status)); + return -EIO; } - case CDROMSUBCHNL: { /* Get subchannel info */ - int st; - struct cdrom_subchnl subchnl; - struct opt_Toc qInfo; - - if ((st = verify_area(VERIFY_READ, - (void *) arg, sizeof subchnl))) - return st; - if ((st = verify_area(VERIFY_WRITE, - (void *) arg, sizeof subchnl))) - return st; - memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl); - if (optGetQChannelInfo(&qInfo) < 0) - return -EIO; - subchnl.cdsc_audiostatus = optAudioStatus; - subchnl.cdsc_adr = qInfo.ctrl_addr; - subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4; - subchnl.cdsc_trk = bcd2bin(qInfo.track); - subchnl.cdsc_ind = bcd2bin(qInfo.pointIndex); - switch (subchnl.cdsc_format) { - case CDROM_LBA: - subchnl.cdsc_absaddr.lba = msf2hsg(&qInfo.diskTime); - subchnl.cdsc_reladdr.lba = msf2hsg(&qInfo.trackTime); - break; - case CDROM_MSF: - subchnl.cdsc_absaddr.msf.minute = - bcd2bin(qInfo.diskTime.min); - subchnl.cdsc_absaddr.msf.second = - bcd2bin(qInfo.diskTime.sec); - subchnl.cdsc_absaddr.msf.frame = - bcd2bin(qInfo.diskTime.frame); - subchnl.cdsc_reladdr.msf.minute = - bcd2bin(qInfo.trackTime.min); - subchnl.cdsc_reladdr.msf.second = - bcd2bin(qInfo.trackTime.sec); - subchnl.cdsc_reladdr.msf.frame = - bcd2bin(qInfo.trackTime.frame); - break; - default: - return -EINVAL; - } - memcpy_tofs((void *) arg, &subchnl, sizeof subchnl); - break; + return 0; +} + + +static int cdromsubchnl(unsigned long arg) +{ + int status; + struct cdrom_subchnl subchnl; + + status = verify_area(VERIFY_READ, (void *) arg, sizeof subchnl); + if (status) + return status; + status = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl); + if (status) + return status; + memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl); + + if (subchnl.cdsc_format != CDROM_LBA + && subchnl.cdsc_format != CDROM_MSF) + return -EINVAL; + + status = get_q_channel(&subchnl); + if (status < 0) { + DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status)); + return -EIO; } - case CDROMREADMODE1: { - int st; - struct cdrom_msf msf; - char buf[OPT_BLOCKSIZE]; - - if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof msf))) - return st; - if ((st = verify_area(VERIFY_WRITE,(void *)arg,OPT_BLOCKSIZE))) - return st; - memcpy_fromfs(&msf, (void *) arg, sizeof msf); - opt_Play.start.min = bin2bcd(msf.cdmsf_min0); - opt_Play.start.sec = bin2bcd(msf.cdmsf_sec0); - opt_Play.start.frame = bin2bcd(msf.cdmsf_frame0); - opt_Play.end.min = 0; - opt_Play.end.sec = 0; - opt_Play.end.frame = 1; /* read only one frame */ - st = optReadCmd(COMREAD, &opt_Play); -#ifdef DEBUG_VFS - printk("optcd: COMREAD status 0x%x\n", st); -#endif - sleep_dten_low(); /* error checking here?? */ - optReadData(buf, OPT_BLOCKSIZE); - memcpy_tofs((void *) arg, &buf, OPT_BLOCKSIZE); - break; + + memcpy_tofs((void *) arg, &subchnl, sizeof subchnl); + return 0; +} + + +static int cdromread(unsigned long arg, int blocksize, int cmd) +{ + int status; + struct cdrom_msf msf; + char buf[BLOCKSIZE_ALL]; + + status = verify_area(VERIFY_READ, (void *) arg, sizeof msf); + if (status) + return status; + status = verify_area(VERIFY_WRITE, (void *) arg, blocksize); + if (status) + return status; + memcpy_fromfs(&msf, (void *) arg, sizeof msf); + + bin2bcd(&msf); + msf.cdmsf_min1 = 0; + msf.cdmsf_sec1 = 0; + msf.cdmsf_frame1 = 1; /* read only one frame */ + status = exec_read_cmd(cmd, &msf); + + DEBUG((DEBUG_VFS, "read cmd status 0x%x", status)); + + if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT)) + return -EIO; + fetch_data(buf, blocksize); + + memcpy_tofs((void *) arg, &buf, blocksize); + return 0; +} + + +static int cdromseek(unsigned long arg) +{ + int status; + struct cdrom_msf msf; + + status = verify_area(VERIFY_READ, (void *) arg, sizeof msf); + if (status) + return status; + memcpy_fromfs(&msf, (void *) arg, sizeof msf); + + bin2bcd(&msf); + status = exec_seek_cmd(COMSEEK, &msf); + + DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status)); + + if (status < 0) + return -EIO; + return 0; +} + + +#ifdef MULTISESSION +static int cdrommultisession(unsigned long arg) +{ + int status; + struct cdrom_multisession ms; + + status = verify_area(VERIFY_READ, (void*) arg, sizeof ms); + if (status) + return status; + status = verify_area(VERIFY_WRITE, (void*) arg, sizeof ms); + if (status) + return status; + memcpy_fromfs(&ms, (void*) arg, sizeof ms); + + ms.addr.msf.minute = disk_info.last_session.minute; + ms.addr.msf.second = disk_info.last_session.second; + ms.addr.msf.frame = disk_info.last_session.frame; + + if (ms.addr_format != CDROM_LBA + && ms.addr_format != CDROM_MSF) + return -EINVAL; + if (ms.addr_format == CDROM_LBA) + msf2lba((union cd_addr *)/*%%*/&ms.addr); + + ms.xa_flag = disk_info.xa; + + memcpy_tofs((void*) arg, &ms, + sizeof(struct cdrom_multisession)); + +#if DEBUG_MULTIS + if (ms.addr_format == CDROM_MSF) + printk("optcd: multisession xa:%d, msf:%02d:%02d.%02d\n", + ms.xa_flag, + ms.addr.msf.minute, + ms.addr.msf.second, + ms.addr.msf.frame); + else + printk("optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n", + ms.xa_flag, + ms.addr.lba, + disk_info.last_session.minute, + disk_info.last_session.second, + disk_info.last_session.frame); +#endif DEBUG_MULTIS + + return 0; +} +#endif MULTISESSION + + +static int cdromreset(void) +{ + if (state != S_IDLE) { + error = 1; + tries = 0; } - case CDROMMULTISESSION: - return -EINVAL; /* unluckily, not implemented yet */ - default: + toc_uptodate = 0; + opt_invalidate_buffers(); + audio_status = CDROM_AUDIO_NO_STATUS; + + if (!reset_drive()) + return -EIO; + return 0; +} + +/* VFS calls */ + + +static int opt_ioctl(struct inode *ip, struct file *fp, + unsigned int cmd, unsigned long arg) +{ + int err; + + DEBUG((DEBUG_VFS, "starting opt_ioctl")); + + if (!ip) return -EINVAL; + + if (cmd == CDROMRESET) + return cdromreset(); + + if (state != S_IDLE) + return -EBUSY; + + err = drive_status(); + if (err < 0) { + DEBUG((DEBUG_VFS, "drive_status: %02x", -err)); + return -EIO; } -#ifdef DEBUG_VFS - printk("optcd: exiting opt_ioctl\n"); + err = update_toc(); + if (err < 0) { + DEBUG((DEBUG_VFS, "update_toc: %02x", -err)); + return -EIO; + } + + DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd)); + + switch (cmd) { + case CDROMPAUSE: return cdrompause(); + case CDROMRESUME: return cdromresume(); + case CDROMPLAYMSF: return cdromplaymsf(arg); + case CDROMPLAYTRKIND: return cdromplaytrkind(arg); + case CDROMREADTOCHDR: return cdromreadtochdr(arg); + case CDROMREADTOCENTRY: return cdromreadtocentry(arg); + + case CDROMSTOP: err = exec_cmd(COMSTOP); + if (err < 0) { + DEBUG((DEBUG_VFS, + "exec_cmd COMSTOP: %02x", + -err)); + return -EIO; + } + audio_status = CDROM_AUDIO_NO_STATUS; + break; + case CDROMSTART: err = exec_cmd(COMCLOSE); /* What else? */ + if (err < 0) { + DEBUG((DEBUG_VFS, + "exec_cmd COMCLOSE: %02x", + -err)); + return -EIO; + } + break; + case CDROMEJECT: err = exec_cmd(COMUNLOCK); + if (err < 0) { + DEBUG((DEBUG_VFS, + "exec_cmd COMUNLOCK: %02x", + -err)); + return -EIO; + } + err = exec_cmd(COMOPEN); + if (err < 0) { + DEBUG((DEBUG_VFS, + "exec_cmd COMOPEN: %02x", + -err)); + return -EIO; + } + break; + + case CDROMVOLCTRL: return cdromvolctrl(arg); + case CDROMSUBCHNL: return cdromsubchnl(arg); + + case CDROMREADAUDIO: return -EINVAL; /* not implemented */ + case CDROMEJECT_SW: auto_eject = (char) arg; + break; + +#ifdef MULTISESSION + case CDROMMULTISESSION: return cdrommultisession(arg); #endif + + case CDROM_GET_UPC: return -EINVAL; /* not implemented */ + case CDROMVOLREAD: return -EINVAL; /* not implemented */ + + case CDROMREADRAW: + return cdromread(arg, BLOCKSIZE_RAW, COMREADRAW); + case CDROMREADCOOKED: + return cdromread(arg, BLOCKSIZE, COMREAD); + case CDROMSEEK: return cdromseek(arg); + case CDROMPLAYBLK: return -EINVAL; /* not implemented */ + default: return -EINVAL; + } return 0; } -static int optPresent = 0; -static int opt_open_count = 0; + +static int open_count = 0; /* Open device special file; check that a disk is in. */ -static int opt_open(struct inode *ip, struct file *fp) { -#ifdef DEBUG_VFS - printk("optcd: starting opt_open\n"); -#endif - if (!optPresent) - return -ENXIO; /* no hardware */ - if (!opt_open_count && opt_state == OPT_S_IDLE) { - int st; +static int opt_open(struct inode *ip, struct file *fp) +{ + DEBUG((DEBUG_VFS, "starting opt_open")); + + if (!open_count++ && state == S_IDLE) { + int status; + opt_invalidate_buffers(); - if ((st = optGetStatus()) < 0) + status = drive_status(); + if (status < 0) { + DEBUG((DEBUG_VFS, "drive_status: %02x", -status)); return -EIO; - if (st & ST_DOOR_OPEN) { - optCmd(COMCLOSE); /* close door */ - if ((st = optGetStatus()) < 0) /* try again */ + } + DEBUG((DEBUG_VFS, "status: %02x", status)); + if (status & ST_DOOR_OPEN) { + status = exec_cmd(COMCLOSE); /* close door */ + if (status < 0) { + DEBUG((DEBUG_VFS, + "exec_cmd COMCLOSE: %02x", -status)); + } + status = drive_status(); /* try again */ + if (status < 0) { + DEBUG((DEBUG_VFS, + "drive_status: %02x", -status)); return -EIO; + } + DEBUG((DEBUG_VFS, "status: %02x", status)); } - if (st & (ST_DOOR_OPEN|ST_DRVERR)) { + if (status & (ST_DOOR_OPEN|ST_DRVERR)) { printk("optcd: no disk or door open\n"); return -EIO; } - if (optUpdateToc() < 0) + status = exec_cmd(COMLOCK); /* Lock door */ + if (status < 0) { + DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status)); + } + status = update_toc(); /* Read table of contents */ + if (status < 0) { + DEBUG((DEBUG_VFS, "update_toc: %02x", -status)); return -EIO; + } } - opt_open_count++; MOD_INC_USE_COUNT; - optCmd(COMLOCK); /* Lock door */ -#ifdef DEBUG_VFS - printk("optcd: exiting opt_open\n"); -#endif + + DEBUG((DEBUG_VFS, "exiting opt_open")); + return 0; } + /* Release device special file; flush all blocks from the buffer cache */ -static void opt_release(struct inode *ip, struct file *fp) { -#ifdef DEBUG_VFS - printk("optcd: executing opt_release\n"); - printk("inode: %p, inode -> i_rdev: 0x%x, file: %p\n", - ip, ip -> i_rdev, fp); -#endif - if (!--opt_open_count) { +static void opt_release(struct inode *ip, struct file *fp) +{ + int status; + + DEBUG((DEBUG_VFS, "executing opt_release")); + DEBUG((DEBUG_VFS, "inode: %p, inode -> i_rdev: 0x%x, file: %p\n", + ip, ip -> i_rdev, fp)); + + if (!--open_count) { opt_invalidate_buffers(); sync_dev(ip -> i_rdev); invalidate_buffers(ip -> i_rdev); + status = exec_cmd(COMUNLOCK); /* Unlock door */ + if (status < 0) { + DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status)); + } + if (auto_eject) { + status = exec_cmd(COMOPEN); + DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status)); + } CLEAR_TIMER; - optCmd(COMUNLOCK); /* Unlock door */ } MOD_DEC_USE_COUNT; } + +/* Driver initialisation */ -/* Initialisation */ - -static int version_ok(void) { +/* Returns 1 if a drive is detected with a version string + starting with "DOLPHIN". Otherwise 0. */ +static int version_ok(void) +{ char devname[100]; - int count, i, ch; + int count, i, ch, status; - if (optCmd(COMVERSION) < 0) + status = exec_cmd(COMVERSION); + if (status < 0) { + DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status)); return 0; - if ((count = optGetData()) < 0) + } + if ((count = get_data(1)) < 0) { + DEBUG((DEBUG_VFS, "get_data(1): %02x", -count)); return 0; + } for (i = 0, ch = -1; count > 0; count--) { - if ((ch = optGetData()) < 0) + if ((ch = get_data(1)) < 0) { + DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch)); break; + } if (i < 99) devname[i++] = ch; } devname[i] = '\0'; if (ch < 0) return 0; + printk("optcd: Device %s detected\n", devname); return ((devname[0] == 'D') && (devname[1] == 'O') @@ -1386,17 +1960,57 @@ static struct file_operations opt_fops = { }; +/* Flag indicates if ISP16 detection and initialisation should be skipped */ +#define skip_isp16_init noisp16 /* Needed for the modutils. */ +static int skip_isp16_init = 0; + /* Get kernel parameter when used as a kernel driver */ -void optcd_setup(char *str, int *ints) { +void optcd_setup(char *str, int *ints) +{ if (ints[0] > 0) optcd_port = ints[1]; + if (!strcmp(str ,"noisp16")) + skip_isp16_init = 1; +} + + +#ifdef PROBE_ISP16 +/* If ISP16 I/O ports not already reserved, probe for an ISP16 interface card, + and enable SONY mode with no interrupts and no DMA. + (As far as I know, all Optics 8000 AT drives come with a SONY interface. + Interrupts and DMA are not supported). + Returns false only if ISP16 detected but couldn't be initialised. */ +static int probe_isp16(void) +{ + if (skip_isp16_init) + return 1; + + if (check_region(ISP16_DRIVE_SET_PORT, 5)) + return 1; + + if (isp16_detect() < 0 ) { + printk( "No ISP16 cdrom interface found.\n" ); + return 1; + } + + isp16_sound_config(); /* Enable playing through speakers */ + + printk( "ISP16 cdrom interface detected.\n"); + if (isp16_cdi_config(optcd_port, ISP16_SONY, 0, 0) < 0) { + printk( "ISP16 configure error.\n" ); + return 0; + } + return 1; } +#endif PROBE_ISP16 -/* - * Test for presence of drive and initialize it. Called at boot time. - */ -int optcd_init(void) { +/* Test for presence of drive and initialize it. Called at boot time + or during module initialisation. */ +int optcd_init(void) +{ + int status; + if (optcd_port <= 0) { printk("optcd: no Optics Storage CDROM Initialization\n"); return -EIO; @@ -1407,29 +2021,12 @@ int optcd_init(void) { return -EIO; } - if (!check_region(ISP16_DRIVE_SET_PORT, 5)) { - /* If someone else has'nt already reserved these ports, - probe for an ISP16 interface card, and enable SONY mode - with no interrupts and no DMA. (As far as I know, all optics - drives come with a SONY interface.) */ - if ( (isp16_type=isp16_detect()) < 0 ) - printk( "No ISP16 cdrom interface found.\n" ); - else { - u_char expected_drive; - - printk( "ISP16 cdrom interface (%s optional IDE) detected.\n", - (isp16_type==2)?"with":"without" ); - - expected_drive = (isp16_type?ISP16_SANYO1:ISP16_SANYO0); - - if ( isp16_config( optcd_port, ISP16_SONY, 0, 0 ) < 0 ) { - printk( "ISP16 cdrom interface has not been properly configured.\n" ); - return -EIO; - } - } - } +#ifdef PROBE_ISP16 + if (!probe_isp16()) + return -EIO; +#endif - if (!optResetDrive()) { + if (!reset_drive()) { printk("optcd: drive at 0x%x not ready\n", optcd_port); return -EIO; } @@ -1437,8 +2034,10 @@ int optcd_init(void) { printk("optcd: unknown drive detected; aborting\n"); return -EIO; } - if (optCmd(COMINITDOUBLE) < 0) { + status = exec_cmd(COMINITDOUBLE); + if (status < 0) { printk("optcd: cannot init double speed mode\n"); + DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status)); return -EIO; } if (register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0) @@ -1446,22 +2045,26 @@ int optcd_init(void) { printk("optcd: unable to get major %d\n", MAJOR_NR); return -EIO; } + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; read_ahead[MAJOR_NR] = 4; request_region(optcd_port, 4, "optcd"); - optPresent = 1; - printk("optcd: 8000 AT CDROM at 0x%x\n", optcd_port); + + printk("optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port); return 0; } + #ifdef MODULE int init_module(void) { return optcd_init(); } -void cleanup_module(void) { - if ((unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL)) { + +void cleanup_module(void) +{ + if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) { printk("optcd: what's that: can't unregister\n"); return; } @@ -1469,191 +2072,3 @@ void cleanup_module(void) { printk("optcd: module released.\n"); } #endif MODULE - - -/* - * -- ISP16 detection and configuration - * - * Copyright (c) 1995, Eric van der Maarel - * - * Version 0.5 - * - * Detect cdrom interface on ISP16 soundcard. - * Configure cdrom interface. - * - * Algorithm for the card with no IDE support option taken - * from the CDSETUP.SYS driver for MSDOS, - * by OPTi Computers, version 2.03. - * Algorithm for the IDE supporting ISP16 as communicated - * to me by Vadim Model and Leo Spiekman. - * - * Use, modifification or redistribution of this software is - * allowed under the terms of the GPL. - * - */ - - -#define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p)) -#define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p)) - -static short -isp16_detect(void) -{ - - if ( !( isp16_with_ide__detect() < 0 ) ) - return(2); - else - return( isp16_no_ide__detect() ); -} - -static short -isp16_no_ide__detect(void) -{ - u_char ctrl; - u_char enable_cdrom; - u_char io; - short i = -1; - - isp16_ctrl = ISP16_NO_IDE__CTRL; - isp16_enable_cdrom_port = ISP16_NO_IDE__ENABLE_CDROM_PORT; - - /* read' and write' are a special read and write, respectively */ - - /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */ - ctrl = ISP16_IN( ISP16_CTRL_PORT ) & 0xFC; - ISP16_OUT( ISP16_CTRL_PORT, ctrl ); - - /* read' 3,4 and 5-bit from the cdrom enable port */ - enable_cdrom = ISP16_IN( ISP16_NO_IDE__ENABLE_CDROM_PORT ) & 0x38; - - if ( !(enable_cdrom & 0x20) ) { /* 5-bit not set */ - /* read' last 2 bits of ISP16_IO_SET_PORT */ - io = ISP16_IN( ISP16_IO_SET_PORT ) & 0x03; - if ( ((io&0x01)<<1) == (io&0x02) ) { /* bits are the same */ - if ( io == 0 ) { /* ...the same and 0 */ - i = 0; - enable_cdrom |= 0x20; - } - else { /* ...the same and 1 */ /* my card, first time 'round */ - i = 1; - enable_cdrom |= 0x28; - } - ISP16_OUT( ISP16_NO_IDE__ENABLE_CDROM_PORT, enable_cdrom ); - } - else { /* bits are not the same */ - ISP16_OUT( ISP16_CTRL_PORT, ctrl ); - return(i); /* -> not detected: possibly incorrect conclusion */ - } - } - else if ( enable_cdrom == 0x20 ) - i = 0; - else if ( enable_cdrom == 0x28 ) /* my card, already initialised */ - i = 1; - - ISP16_OUT( ISP16_CTRL_PORT, ctrl ); - - return(i); -} - -static short -isp16_with_ide__detect(void) -{ - u_char ctrl; - u_char tmp; - - isp16_ctrl = ISP16_IDE__CTRL; - isp16_enable_cdrom_port = ISP16_IDE__ENABLE_CDROM_PORT; - - /* read' and write' are a special read and write, respectively */ - - /* read' ISP16_CTRL_PORT and save */ - ctrl = ISP16_IN( ISP16_CTRL_PORT ); - - /* write' zero to the ctrl port and get response */ - ISP16_OUT( ISP16_CTRL_PORT, 0 ); - tmp = ISP16_IN( ISP16_CTRL_PORT ); - - if ( tmp != 2 ) /* isp16 with ide option not detected */ - return(-1); - - /* restore ctrl port value */ - ISP16_OUT( ISP16_CTRL_PORT, ctrl ); - - return(2); -} - -static short -isp16_config( int base, u_char drive_type, int irq, int dma ) -{ - u_char base_code; - u_char irq_code; - u_char dma_code; - u_char i; - - if ( (drive_type == ISP16_MITSUMI) && (dma != 0) ) - printk( "Mitsumi cdrom drive has no dma support.\n" ); - - switch (base) { - case 0x340: base_code = ISP16_BASE_340; break; - case 0x330: base_code = ISP16_BASE_330; break; - case 0x360: base_code = ISP16_BASE_360; break; - case 0x320: base_code = ISP16_BASE_320; break; - default: - printk( "Base address 0x%03X not supported by cdrom interface on ISP16.\n", base ); - return(-1); - } - switch (irq) { - case 0: irq_code = ISP16_IRQ_X; break; /* disable irq */ - case 5: irq_code = ISP16_IRQ_5; - printk( "Irq 5 shouldn't be used by cdrom interface on ISP16," - " due to possible conflicts with the soundcard.\n"); - break; - case 7: irq_code = ISP16_IRQ_7; - printk( "Irq 7 shouldn't be used by cdrom interface on ISP16," - " due to possible conflicts with the soundcard.\n"); - break; - case 3: irq_code = ISP16_IRQ_3; break; - case 9: irq_code = ISP16_IRQ_9; break; - case 10: irq_code = ISP16_IRQ_10; break; - case 11: irq_code = ISP16_IRQ_11; break; - default: - printk( "Irq %d not supported by cdrom interface on ISP16.\n", irq ); - return(-1); - } - switch (dma) { - case 0: dma_code = ISP16_DMA_X; break; /* disable dma */ - case 1: printk( "Dma 1 cannot be used by cdrom interface on ISP16," - " due to conflict with the soundcard.\n"); - return(-1); break; - case 3: dma_code = ISP16_DMA_3; break; - case 5: dma_code = ISP16_DMA_5; break; - case 6: dma_code = ISP16_DMA_6; break; - case 7: dma_code = ISP16_DMA_7; break; - default: - printk( "Dma %d not supported by cdrom interface on ISP16.\n", dma ); - return(-1); - } - - if ( drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 && - drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 && - drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI && - drive_type != ISP16_DRIVE_X ) { - printk( "Drive type (code 0x%02X) not supported by cdrom" - " interface on ISP16.\n", drive_type ); - return(-1); - } - - /* set type of interface */ - i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK; /* clear some bits */ - ISP16_OUT( ISP16_DRIVE_SET_PORT, i|drive_type ); - - /* enable cdrom on interface with ide support */ - if ( isp16_type > 1 ) - ISP16_OUT( isp16_enable_cdrom_port, ISP16_ENABLE_CDROM ); - - /* set base address, irq and dma */ - i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK; /* keep some bits */ - ISP16_OUT( ISP16_IO_SET_PORT, i|base_code|irq_code|dma_code ); - - return(0); -} diff --git a/drivers/cdrom/optcd_isp16.h b/drivers/cdrom/optcd_isp16.h new file mode 100644 index 000000000000..f6bb76d431d6 --- /dev/null +++ b/drivers/cdrom/optcd_isp16.h @@ -0,0 +1,337 @@ +/* linux/drivers/cdrom/optcd_isp16.h - ISP16 CDROM interface configuration + $Id: optcd_isp16.h,v 1.3 1996/01/15 18:43:11 root Exp root $ + + Extracts from linux/drivers/cdrom/sjcd.c + For copyrights see linux/drivers/cdrom/optcd.c +*/ + + +/* Some (Media)Magic */ +/* define types of drive the interface on an ISP16 card may be looking at */ +#define ISP16_DRIVE_X 0x00 +#define ISP16_SONY 0x02 +#define ISP16_PANASONIC0 0x02 +#define ISP16_SANYO0 0x02 +#define ISP16_MITSUMI 0x04 +#define ISP16_PANASONIC1 0x06 +#define ISP16_SANYO1 0x06 +#define ISP16_DRIVE_NOT_USED 0x08 /* not used */ +#define ISP16_DRIVE_SET_MASK 0xF1 /* don't change 0-bit or 4-7-bits*/ +/* ...for port */ +#define ISP16_DRIVE_SET_PORT 0xF8D +/* set io parameters */ +#define ISP16_BASE_340 0x00 +#define ISP16_BASE_330 0x40 +#define ISP16_BASE_360 0x80 +#define ISP16_BASE_320 0xC0 +#define ISP16_IRQ_X 0x00 +#define ISP16_IRQ_5 0x04 /* shouldn't be used due to soundcard conflicts */ +#define ISP16_IRQ_7 0x08 /* shouldn't be used due to soundcard conflicts */ +#define ISP16_IRQ_3 0x0C +#define ISP16_IRQ_9 0x10 +#define ISP16_IRQ_10 0x14 +#define ISP16_IRQ_11 0x18 +#define ISP16_DMA_X 0x03 +#define ISP16_DMA_3 0x00 +#define ISP16_DMA_5 0x00 +#define ISP16_DMA_6 0x01 +#define ISP16_DMA_7 0x02 +#define ISP16_IO_SET_MASK 0x20 /* don't change 5-bit */ +/* ...for port */ +#define ISP16_IO_SET_PORT 0xF8E +/* enable the card */ +#define ISP16_C928__ENABLE_PORT 0xF90 /* ISP16 with OPTi 82C928 chip */ +#define ISP16_C929__ENABLE_PORT 0xF91 /* ISP16 with OPTi 82C929 chip */ +#define ISP16_ENABLE_CDROM 0x80 /* seven bit */ + +/* the magic stuff */ +#define ISP16_CTRL_PORT 0xF8F +#define ISP16_C928__CTRL 0xE2 /* ISP16 with OPTi 82C928 chip */ +#define ISP16_C929__CTRL 0xE3 /* ISP16 with OPTi 82C929 chip */ + +static short isp16_detect(void); +static short isp16_c928__detect(void); +static short isp16_c929__detect(void); +static short isp16_cdi_config( int base, u_char drive_type, int irq, int dma ); +static void isp16_sound_config( void ); +static short isp16_type; /* dependent on type of interface card */ +static u_char isp16_ctrl; +static u_short isp16_enable_port; + +/*static int sjcd_present = 0;*/ +static u_char special_mask = 0; + +static unsigned char defaults[ 16 ] = { + 0xA8, 0xA8, 0x18, 0x18, 0x18, 0x18, 0x8E, 0x8E, + 0x03, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x00, 0x00 +}; +/* ------------- */ +/* + * -- ISP16 detection and configuration + * + * Copyright (c) 1995, Eric van der Maarel + * + * Version 0.5 + * + * Detect cdrom interface on ISP16 soundcard. + * Configure cdrom interface. + * Configure sound interface. + * + * Algorithm for the card with OPTi 82C928 taken + * from the CDSETUP.SYS driver for MSDOS, + * by OPTi Computers, version 2.03. + * Algorithm for the card with OPTi 82C929 as communicated + * to me by Vadim Model and Leo Spiekman. + * + * Use, modifification or redistribution of this software is + * allowed under the terms of the GPL. + * + */ + + +#define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p)) +#define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p)) + +static short +isp16_detect(void) +{ + + if ( !( isp16_c929__detect() < 0 ) ) + return(2); + else + return( isp16_c928__detect() ); +} + +static short +isp16_c928__detect(void) +{ + u_char ctrl; + u_char enable_cdrom; + u_char io; + short i = -1; + + isp16_ctrl = ISP16_C928__CTRL; + isp16_enable_port = ISP16_C928__ENABLE_PORT; + + /* read' and write' are a special read and write, respectively */ + + /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */ + ctrl = ISP16_IN( ISP16_CTRL_PORT ) & 0xFC; + ISP16_OUT( ISP16_CTRL_PORT, ctrl ); + + /* read' 3,4 and 5-bit from the cdrom enable port */ + enable_cdrom = ISP16_IN( ISP16_C928__ENABLE_PORT ) & 0x38; + + if ( !(enable_cdrom & 0x20) ) { /* 5-bit not set */ + /* read' last 2 bits of ISP16_IO_SET_PORT */ + io = ISP16_IN( ISP16_IO_SET_PORT ) & 0x03; + if ( ((io&0x01)<<1) == (io&0x02) ) { /* bits are the same */ + if ( io == 0 ) { /* ...the same and 0 */ + i = 0; + enable_cdrom |= 0x20; + } + else { /* ...the same and 1 */ /* my card, first time 'round */ + i = 1; + enable_cdrom |= 0x28; + } + ISP16_OUT( ISP16_C928__ENABLE_PORT, enable_cdrom ); + } + else { /* bits are not the same */ + ISP16_OUT( ISP16_CTRL_PORT, ctrl ); + return(i); /* -> not detected: possibly incorrect conclusion */ + } + } + else if ( enable_cdrom == 0x20 ) + i = 0; + else if ( enable_cdrom == 0x28 ) /* my card, already initialised */ + i = 1; + + ISP16_OUT( ISP16_CTRL_PORT, ctrl ); + + return(i); +} + +static short +isp16_c929__detect(void) +{ + u_char ctrl; + u_char tmp; + + isp16_ctrl = ISP16_C929__CTRL; + isp16_enable_port = ISP16_C929__ENABLE_PORT; + + /* read' and write' are a special read and write, respectively */ + + /* read' ISP16_CTRL_PORT and save */ + ctrl = ISP16_IN( ISP16_CTRL_PORT ); + + /* write' zero to the ctrl port and get response */ + ISP16_OUT( ISP16_CTRL_PORT, 0 ); + tmp = ISP16_IN( ISP16_CTRL_PORT ); + + if ( tmp != 2 ) /* isp16 with 82C929 not detected */ + return(-1); + + /* restore ctrl port value */ + ISP16_OUT( ISP16_CTRL_PORT, ctrl ); + + return(2); +} + +static short +isp16_cdi_config( int base, u_char drive_type, int irq, int dma ) +{ + u_char base_code; + u_char irq_code; + u_char dma_code; + u_char i; + + if ( (drive_type == ISP16_MITSUMI) && (dma != 0) ) + printk( "Mitsumi cdrom drive has no dma support.\n" ); + + switch (base) { + case 0x340: base_code = ISP16_BASE_340; break; + case 0x330: base_code = ISP16_BASE_330; break; + case 0x360: base_code = ISP16_BASE_360; break; + case 0x320: base_code = ISP16_BASE_320; break; + default: + printk( "Base address 0x%03X not supported by cdrom interface on ISP16.\n", base ); + return(-1); + } + switch (irq) { + case 0: irq_code = ISP16_IRQ_X; break; /* disable irq */ + case 5: irq_code = ISP16_IRQ_5; + printk( "Irq 5 shouldn't be used by cdrom interface on ISP16," + " due to possible conflicts with the soundcard.\n"); + break; + case 7: irq_code = ISP16_IRQ_7; + printk( "Irq 7 shouldn't be used by cdrom interface on ISP16," + " due to possible conflicts with the soundcard.\n"); + break; + case 3: irq_code = ISP16_IRQ_3; break; + case 9: irq_code = ISP16_IRQ_9; break; + case 10: irq_code = ISP16_IRQ_10; break; + case 11: irq_code = ISP16_IRQ_11; break; + default: + printk( "Irq %d not supported by cdrom interface on ISP16.\n", irq ); + return(-1); + } + switch (dma) { + case 0: dma_code = ISP16_DMA_X; break; /* disable dma */ + case 1: printk( "Dma 1 cannot be used by cdrom interface on ISP16," + " due to conflict with the soundcard.\n"); + return(-1); break; + case 3: dma_code = ISP16_DMA_3; break; + case 5: dma_code = ISP16_DMA_5; break; + case 6: dma_code = ISP16_DMA_6; break; + case 7: dma_code = ISP16_DMA_7; break; + default: + printk( "Dma %d not supported by cdrom interface on ISP16.\n", dma ); + return(-1); + } + + if ( drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 && + drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 && + drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI && + drive_type != ISP16_DRIVE_X ) { + printk( "Drive type (code 0x%02X) not supported by cdrom" + " interface on ISP16.\n", drive_type ); + return(-1); + } + + /* set type of interface */ + i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK; /* clear some bits */ + ISP16_OUT( ISP16_DRIVE_SET_PORT, i|drive_type ); + + /* enable cdrom on interface with 82C929 chip */ + if ( isp16_type > 1 ) + ISP16_OUT( isp16_enable_port, ISP16_ENABLE_CDROM ); + + /* set base address, irq and dma */ + i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK; /* keep some bits */ + ISP16_OUT( ISP16_IO_SET_PORT, i|base_code|irq_code|dma_code ); + + return(0); +} + +static void isp16_sound_config( void ) +{ + int i; + u_char saved; + + saved = ISP16_IN( 0xF8D ) & 0x8F; + + ISP16_OUT( 0xF8D, 0x40 ); + + /* + * Now we should wait for a while... + */ + for( i = 16*1024; i--; ); + + ISP16_OUT( 0xF8D, saved ); + + ISP16_OUT( 0xF91, 0x1B ); + + for( i = 5*64*1024; i != 0; i-- ) + if( !( inb( 0x534 ) & 0x80 ) ) break; + + if( i > 0 ) { + saved = ( inb( 0x534 ) & 0xE0 ) | 0x0A; + outb( saved, 0x534 ); + + special_mask = ( inb( 0x535 ) >> 4 ) & 0x08; + + saved = ( inb( 0x534 ) & 0xE0 ) | 0x0C; + outb( saved, 0x534 ); + + switch( inb( 0x535 ) ) { + case 0x09: + case 0x0A: + special_mask |= 0x05; + break; + case 0x8A: + special_mask = 0x0F; + break; + default: + i = 0; + } + } + if ( i == 0 ) { + printk( "Strange MediaMagic, but\n" ); + } + else { + printk( "Conf:" ); + saved = inb( 0x534 ) & 0xE0; + for( i = 0; i < 16; i++ ) { + outb( 0x20 | ( u_char )i, 0x534 ); + outb( defaults[i], 0x535 ); + } + for ( i = 0; i < 16; i++ ) { + outb( 0x20 | ( u_char )i, 0x534 ); + saved = inb( 0x535 ); + printk( " %02X", saved ); + } + printk( "\n" ); + } + + ISP16_OUT( 0xF91, 0xA0 | special_mask ); + + /* + * The following have no explaination yet. + */ + ISP16_OUT( 0xF90, 0xA2 ); + ISP16_OUT( 0xF92, 0x03 ); + + /* + * Turn general sound on and set total volume. + */ + ISP16_OUT( 0xF93, 0x0A ); + +/* + outb( 0x04, 0x224 ); + saved = inb( 0x225 ); + outb( 0x04, 0x224 ); + outb( saved, 0x225 ); +*/ + +} diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 8a37d4a49ecf..b19439cd1c82 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -48,3 +48,4 @@ if [ "$CONFIG_WATCHDOG" = "y" ]; then bool ' Software Watchdog' CONFIG_SOFT_WATCHDOG fi fi +endmenu diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 33fa7f454d75..1f079551d152 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -95,6 +95,7 @@ endif ifdef CONFIG_SOFT_WATCHDOG L_OBJS += softdog.o M = y +# This is not modularized, so if configured then "mouse.c" will be resident endif ifdef CONFIG_QIC02_TAPE @@ -106,16 +107,20 @@ LX_OBJS += apm_bios.o endif ifdef M -L_OBJS += mouse.o +LX_OBJS += mouse.o else ifdef MM - M_OBJS += mouse.o + MX_OBJS += mouse.o endif endif - -ifdef CONFIG_SCC + +ifeq ($(CONFIG_SCC),y) L_OBJS += scc.o -endif +else + ifeq ($(CONFIG_SCC),m) + M_OBJS += scc.o + endif +endif ifdef CONFIG_TGA_CONSOLE L_OBJS += tga.o diff --git a/drivers/char/apm_bios.c b/drivers/char/apm_bios.c index 6196f170efc9..5e24d1bc3c60 100644 --- a/drivers/char/apm_bios.c +++ b/drivers/char/apm_bios.c @@ -1,4 +1,4 @@ -/* +/* -*- linux-c -*- * APM BIOS driver for Linux * Copyright 1994, 1995 Stephen Rothwell (Stephen.Rothwell@pd.necisa.oz.au) * @@ -16,6 +16,10 @@ * * October 1995, Rik Faith (faith@cs.unc.edu): * Minor enhancements and updates (to the patch set) for 1.3.x + * Documentation + * January 1996, Rik Faith (faith@cs.unc.edu): + * Make /proc/apm easy to format (bump driver version) + * * * Reference: * @@ -24,9 +28,9 @@ * Intel Order Number 241704-001. Microsoft Part Number 781-110-X01. * * [This document is available free from Intel by calling 800.628.8686 (fax - * 916.356.6100) or 800.548.4725. It is also available from Microsoft by - * calling 206.882.8080; and is ftpable from - * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc] + * 916.356.6100) or 800.548.4725; or via anonymous ftp from + * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc. It is also + * available from Microsoft by calling 206.882.8080.] * */ @@ -288,7 +292,7 @@ static struct apm_bios_struct * user_list = NULL; static struct timer_list apm_timer; -static char driver_version[] = "0.6b"; +static char driver_version[] = "0.7";/* no spaces */ #ifdef APM_DEBUG static char * apm_event_name[] = { @@ -882,69 +886,91 @@ static int do_open(struct inode * inode, struct file * filp) int apm_proc(char *buf) { char * p; - char * power_stat; - char * bat_stat; unsigned short bx; unsigned short cx; unsigned short dx; unsigned short error; + unsigned short ac_line_status = 0xff; + unsigned short battery_status = 0xff; + unsigned short battery_flag = 0xff; + unsigned short percentage = -1; + int time_units = -1; + char *units = "?"; if (apm_bios_info.version == 0) return 0; p = buf; - p += sprintf(p, "BIOS version: %d.%d\nFlags: 0x%02x\n", - (apm_bios_info.version >> 8) & 0xff, - apm_bios_info.version & 0xff, - apm_bios_info.flags); - if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) - return p - buf; - p += sprintf(p, "Entry %x:%lx cseg16 %x dseg %x", - apm_bios_info.cseg, apm_bios_info.offset, - apm_bios_info.cseg_16, apm_bios_info.dseg); - if (apm_bios_info.version > 0x100) - p += sprintf(p, " cseg len %x, dseg len %x", - apm_bios_info.cseg_len, apm_bios_info.dseg_len); - *p++ = '\n'; - error = apm_get_power_status(&bx, &cx, &dx); - if (error) { - strcpy(p, "Power status not available\n"); - p += strlen(p); - return p - buf; - } - switch ((bx >> 8) & 0xff) { - case 0: power_stat = "off line"; break; - case 1: power_stat = "on line"; break; - case 2: power_stat = "on backup power"; break; - default: power_stat = "unknown"; break; - } - switch (bx & 0xff) { - case 0: bat_stat = "high"; break; - case 1: bat_stat = "low"; break; - case 2: bat_stat = "critical"; break; - case 3: bat_stat = "charging"; break; - default: bat_stat = "unknown"; break; - } - p += sprintf(p, "AC: %s\nBattery status: %s\nBattery life: ", - power_stat, bat_stat); - if ((cx & 0xff) == 0xff) { - strcpy(p, "unknown"); - p += strlen(p); - } else - p += sprintf(p, "%d%%", cx & 0xff); - *p++ = '\n'; - if (apm_bios_info.version > 0x100) { - p += sprintf(p, "Battery flag: 0x%02x\nBattery life: ", - (cx >> 8) & 0xff); - if (dx == 0xffff) { - strcpy(p, "unknown"); - p += strlen(p); + + if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) != 0) { + if (!(error = apm_get_power_status(&bx, &cx, &dx))) { + ac_line_status = (bx >> 8) & 0xff; + battery_status = bx & 0xff; + if ((cx & 0xff) != 0xff) + percentage = cx & 0xff; + + if (apm_bios_info.version > 0x100) { + battery_flag = (cx >> 8) & 0xff; + if (dx != 0xffff) { + if ((dx & 0x8000) == 0x8000) { + units = "min"; + time_units = dx & 0x7ffe; + } else { + units = "sec"; + time_units = dx & 0x7fff; + } + } + } } - else - p += sprintf(p, "%d %s", dx & 0x7fff, - ((dx & 0x8000) == 0) - ? "seconds" : "minutes"); - *p++ = '\n'; } + /* Arguments, with symbols from linux/apm_bios.h. Information is + from the Get Power Status (0x0a) call unless otherwise noted. + + 0) Linux driver version (this will change if format changes) + 1) APM BIOS Version. Usually 1.0 or 1.1. + 2) APM flags from APM Installation Check (0x00): + bit 0: APM_16_BIT_SUPPORT + bit 1: APM_32_BIT_SUPPORT + bit 2: APM_IDLE_SLOWS_CLOCK + bit 3: APM_BIOS_DISABLED + bit 4: APM_BIOS_DISENGAGED + 3) AC line status + 0x00: Off-line + 0x01: On-line + 0x02: On backup power (APM BIOS 1.1 only) + 0xff: Unknown + 4) Battery status + 0x00: High + 0x01: Low + 0x02: Critical + 0x03: Charging + 0xff: Unknown + 5) Battery flag + bit 0: High + bit 1: Low + bit 2: Critical + bit 3: Charging + bit 7: No system battery + 0xff: Unknown + 6) Remaining battery life (percentage of charge): + 0-100: valid + -1: Unknown + 7) Remaining battery life (time units): + Number of remaining minutes or seconds + -1: Unknown + 8) min = minutes; sec = seconds */ + + p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", + driver_version, + (apm_bios_info.version >> 8) & 0xff, + apm_bios_info.version & 0xff, + apm_bios_info.flags, + ac_line_status, + battery_status, + battery_flag, + percentage, + time_units, + units ); + return p - buf; } @@ -1000,12 +1026,12 @@ static int apm_setup(void) set_limit(gdt[APM_DS >> 3], 64 * 1024); } else { set_limit(gdt[APM_CS >> 3], apm_bios_info.cseg_len); - /* - * This is not clear from the spec, but at least one - * machine needs this to be a 64k segment. - */ + /* This is not clear from the spec, but at least one + machine needs CS_16 to be a 64k segment, and the DEC + Hinote Ultra CT475 (and others?) needs DS to be a 64k + segment. */ set_limit(gdt[APM_CS_16 >> 3], 64 * 1024); - set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len); + set_limit(gdt[APM_DS >> 3], 64 * 1024); apm_bios_info.version = 0x0101; error = apm_driver_version(&apm_bios_info.version); if (error != 0) @@ -1047,10 +1073,12 @@ static int apm_setup(void) (cx >> 8) & 0xff); if (dx == 0xffff) printk("unknown\n"); - else - printk("%d %s\n", dx & 0x7fff, - ((dx & 0x8000) == 0) - ? "seconds" : "minutes"); + else { + if ((dx & 0x8000)) + printk("%d minutes\n", dx & 0x7ffe ); + else + printk("%d seconds\n", dx & 0x7fff ); + } } } diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 330b2732ea66..1279e397a1ab 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -87,12 +87,6 @@ extern void change_console(unsigned int new_console); extern void scrollback(int); extern void scrollfront(int); -#ifdef __i386__ -#define fake_keyboard_interrupt() __asm__ __volatile__("int $0x21") -#else -#define fake_keyboard_interrupt() do ; while (0) -#endif - unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */ /* @@ -128,6 +122,8 @@ static struct tty_struct * tty = NULL; static volatile unsigned char reply_expected = 0; static volatile unsigned char acknowledge = 0; static volatile unsigned char resend = 0; +/* used by kbd_bh - set by keyboard_interrupt */ +static volatile unsigned char do_poke_blanked_console = 0; extern void compute_shiftstate(void); @@ -384,6 +380,7 @@ static void keyboard_interrupt(int irq, struct pt_regs *regs) prev_scancode = 0; goto end_kbd_intr; } + do_poke_blanked_console = 1; add_keyboard_randomness(scancode); tty = ttytab[fg_console]; @@ -1178,11 +1175,10 @@ static void kbd_bh(void * unused) } want_console = -1; } - poke_blanked_console(); - cli(); - if ((inb_p(0x64) & kbd_read_mask) == 0x01) - fake_keyboard_interrupt(); - sti(); + if (do_poke_blanked_console) { /* do not unblank for a LED change */ + do_poke_blanked_console = 0; + poke_blanked_console(); + } } int kbd_init(void) diff --git a/drivers/char/mouse.c b/drivers/char/mouse.c index dacc86aa1ed7..a9ed83043c67 100644 --- a/drivers/char/mouse.c +++ b/drivers/char/mouse.c @@ -104,6 +104,14 @@ void cleanup_module(void) #endif +static struct symbol_table mouse_syms = { +/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */ +#include + X(mouse_register), + X(mouse_deregister), +#include +}; + int mouse_init(void) { #ifndef MODULE @@ -128,5 +136,6 @@ int mouse_init(void) MOUSE_MAJOR); return -EIO; } - return 0; + + return register_symtab(&mouse_syms); } diff --git a/drivers/char/tga.c b/drivers/char/tga.c index d43e40cd06d8..f8ba50b12363 100644 --- a/drivers/char/tga.c +++ b/drivers/char/tga.c @@ -421,6 +421,9 @@ set_get_cmap(unsigned char * arg, int set) { * dummy routines for the VESA blanking code, which is VGA only, * so we don't have to carry that stuff around for the TGA... */ +void vesa_powerdown(void) +{ +} void vesa_blank(void) { } diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c index ce4b8747fac4..bf18465a14f7 100644 --- a/drivers/char/tpqic02.c +++ b/drivers/char/tpqic02.c @@ -193,8 +193,6 @@ * Also, be careful to avoid IO conflicts with other devices! */ -#include - /* #define TDEBUG diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index dcf53d7d899b..cd26ac67c908 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -73,6 +73,10 @@ #include "vt_kern.h" #include "selection.h" +#ifdef CONFIG_KERNELD +#include +#endif + #define CONSOLE_DEV MKDEV(TTY_MAJOR,0) #define TTY_DEV MKDEV(TTYAUX_MAJOR,0) @@ -211,8 +215,17 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc) int retval = 0; struct tty_ldisc o_ldisc; - if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) || - !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) + if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) + return -EINVAL; +#ifdef CONFIG_KERNELD + /* Eduardo Blanco */ + if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) { + char modname [20]; + sprintf(modname, "tty-ldisc-%d", ldisc); + request_module (modname); + } +#endif + if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) return -EINVAL; if (tty->ldisc.num == ldisc) diff --git a/drivers/char/wd501p.h b/drivers/char/wd501p.h index 979660928143..002021ed3cb2 100644 --- a/drivers/char/wd501p.h +++ b/drivers/char/wd501p.h @@ -18,6 +18,8 @@ * Release 0.04. * */ + +#include #define WATCHDOG_MINOR 130 /* Watchdog timer */ #define TEMP_MINOR 131 /* Temperature Sensor */ diff --git a/drivers/net/Config.in b/drivers/net/Config.in index eb70644fd944..9cbfa39d7cf0 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -10,7 +10,7 @@ tristate 'PPP (point-to-point) support' CONFIG_PPP if [ ! "$CONFIG_PPP" = "n" ]; then comment 'CCP compressors for PPP are only built as modules.' fi -bool 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC +tristate 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC tristate 'PLIP (parallel port) support' CONFIG_PLIP tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA diff --git a/drivers/net/Makefile b/drivers/net/Makefile index bf226b783c18..bc8da3e89591 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -352,10 +352,10 @@ endif # If anything built-in uses slhc, then build it into the kernel also. # If not, but a module uses it, build as a module. ifdef CONFIG_SLHC_BUILTIN -L_OBJS += slhc.o +LX_OBJS += slhc.o else ifdef CONFIG_SLHC_MODULE - M_OBJS += slhc.o + MX_OBJS += slhc.o endif endif diff --git a/drivers/net/README.tunnel b/drivers/net/README.tunnel index 9736b484f8e8..455022738aeb 100644 --- a/drivers/net/README.tunnel +++ b/drivers/net/README.tunnel @@ -113,9 +113,9 @@ address on network B, and machine B is simply acting as a proxy for machine A. Machine A needs it's tunnel address to be on network B so that when packets from machine B are unwrapped, the Linux routing system knows that the address is a local one. Due to a -feature of Linux, any packets recieved locally, bound for another +feature of Linux, any packets received locally, bound for another local address, are simply routed through the loopback interface. -This means that the tunnel device should never recieve packets. Even +This means that the tunnel device should never receive packets. Even on machine B, it is the ethernet interface that is receiving wrapped packets, and once they are unwrapped they go back out the ethernet interface. This could cause Linux to generate ICMP redirect messages diff --git a/drivers/net/ne.c b/drivers/net/ne.c index ae22a6a4843d..4da4efb7cee5 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -22,6 +22,7 @@ sanity checks and bad clone support optional. Paul Gortmaker : new reset code, reset card after probe at boot. Paul Gortmaker : multiple card support for module users. + Paul Gortmaker : Support for PCI ne2k clones, similar to lance.c */ @@ -32,10 +33,12 @@ static const char *version = #include - +#include #include #include #include +#include +#include #include #include @@ -90,6 +93,9 @@ bad_clone_list[] = { #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ +/* Non-zero only if the current card is a PCI with BIOS-set IRQ. */ +static unsigned char pci_irq_line = 0; + int ne_probe(struct device *dev); static int ne_probe1(struct device *dev, int ioaddr); @@ -131,16 +137,56 @@ struct netdev_entry netcard_drv = {"ne", ne_probe1, NE_IO_EXTENT, netcard_portlist}; #else +/* Note that this probe only picks up one card at a time, even for multiple + PCI ne2k cards. Use "ether=0,0,eth1" if you have a second PCI ne2k card. + This keeps things consistent regardless of the bus type of the card. */ + int ne_probe(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; + /* First check any supplied i/o locations. User knows best. */ if (base_addr > 0x1ff) /* Check a single specified location. */ return ne_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ return ENXIO; + /* Then look for any installed PCI clones */ +#if defined(CONFIG_PCI) + if (pcibios_present()) { + int pci_index; + for (pci_index = 0; pci_index < 8; pci_index++) { + unsigned char pci_bus, pci_device_fn; + unsigned int pci_ioaddr; + + /* Currently only Realtek are making PCI ne2k clones. */ + if (pcibios_find_device (PCI_VENDOR_ID_REALTEK, + PCI_DEVICE_ID_REALTEK_8029, pci_index, + &pci_bus, &pci_device_fn) != 0) + break; /* OK, now try to probe for std. ISA card */ + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq_line); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &pci_ioaddr); + /* Strip the I/O address out of the returned value */ + pci_ioaddr &= PCI_BASE_ADDRESS_IO_MASK; + /* Avoid already found cards from previous ne_probe() calls */ + if (check_region(pci_ioaddr, NE_IO_EXTENT)) + continue; + printk("ne.c: PCI BIOS reports ne2000 clone at i/o %#x, irq %d.\n", + pci_ioaddr, pci_irq_line); + if (ne_probe1(dev, pci_ioaddr) != 0) { /* Shouldn't happen. */ + printk(KERN_ERR "ne.c: Probe of PCI card at %#x failed.\n", pci_ioaddr); + break; /* Hrmm, try to probe for ISA card... */ + } + pci_irq_line = 0; + return 0; + } + } +#endif /* defined(CONFIG_PCI) */ + + /* Last resort. The semi-risky ISA auto-probe. */ for (i = 0; netcard_portlist[i]; i++) { int ioaddr = netcard_portlist[i]; if (check_region(ioaddr, NE_IO_EXTENT)) @@ -291,6 +337,10 @@ static int ne_probe1(struct device *dev, int ioaddr) dev = init_etherdev(0, 0); } + if (pci_irq_line) { + dev->irq = pci_irq_line; + } + if (dev->irq < 2) { autoirq_setup(0); outb_p(0x50, ioaddr + EN0_IMR); /* Enable one interrupt. */ diff --git a/drivers/net/seeq8005.h b/drivers/net/seeq8005.h index abd06abd7f36..7122340c4479 100644 --- a/drivers/net/seeq8005.h +++ b/drivers/net/seeq8005.h @@ -118,7 +118,7 @@ #define SEEQCFG2_SLOTSEL (0x0040) /* 0= standard IEEE802.3, 1= smaller,faster, non-standard */ #define SEEQCFG2_NO_PREAM (0x0080) /* 1= user supplies Xmit preamble bytes */ #define SEEQCFG2_ADDR_LEN (0x0100) /* 1= 2byte addresses */ -#define SEEQCFG2_REC_CRC (0x0200) /* 0= recieved packets will have CRC stripped from them */ +#define SEEQCFG2_REC_CRC (0x0200) /* 0= received packets will have CRC stripped from them */ #define SEEQCFG2_XMIT_NO_CRC (0x0400) /* dont xmit CRC with each packet (user supplies it) */ #define SEEQCFG2_LOOPBACK (0x0800) #define SEEQCFG2_CTRLO (0x1000) @@ -133,7 +133,7 @@ struct seeq_pkt_hdr { unused:1, data_follows:1, /* if not set, process this as a header and pointer only */ chain_cont:1, /* if set, more headers in chain only cmd bit valid in recv header */ - xmit_recv:1; /* if set, a xmit packet, else a recieve packet.*/ + xmit_recv:1; /* if set, a xmit packet, else a receive packet.*/ unsigned char status; }; diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c index d046fd870e49..aad76ed91c37 100644 --- a/drivers/net/slhc.c +++ b/drivers/net/slhc.c @@ -90,6 +90,8 @@ static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); static unsigned short pull16(unsigned char **cpp); +static void export_slhc_syms(void); +static has_exported = 0; /* Initialize compression data structure * slots must be in range 0 to 255 (zero meaning no compression) @@ -101,6 +103,9 @@ slhc_init(int rslots, int tslots) register struct cstate *ts; struct slcompress *comp; + if (!has_exported) + export_slhc_syms(); + comp = (struct slcompress *)kmalloc(sizeof(struct slcompress), GFP_KERNEL); if (! comp) @@ -727,11 +732,31 @@ void slhc_o_status(struct slcompress *comp) } } +static struct symbol_table slhc_syms = { +/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */ +#include + /* VJ header compression */ + X(slhc_init), + X(slhc_free), + X(slhc_remember), + X(slhc_compress), + X(slhc_uncompress), + X(slhc_toss), +#include +}; + +static void export_slhc_syms(void) +{ + register_symtab(&slhc_syms); + has_exported = 1; +} + #ifdef MODULE int init_module(void) { printk("CSLIP: code copyright 1989 Regents of the University of California\n"); + export_slhc_syms(); return 0; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index fbf16a23017d..16ebfd198c8a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -85,6 +85,7 @@ struct pci_dev_info dev_info[] = { DEVICE( MATROX, MATROX_MGA_IMP, "MGA Impression"), DEVICE( CT, CT_65545, "65545"), DEVICE( FD, FD_36C70, "TMC-18C30"), + DEVICE( SI, SI_6201, "6201"), DEVICE( SI, SI_6202, "6202"), DEVICE( SI, SI_503, "85C503"), DEVICE( SI, SI_501, "85C501"), diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index fca4734d7c41..9d2eb2e70d92 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -14,11 +14,12 @@ bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS mainmenu_option next_comment comment 'SCSI low-level drivers' +dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI dep_tristate 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X $CONFIG_SCSI dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI -dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC +dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG.SCSI dep_tristate 'EATA-DMA (DPT, NEC, ATT, Olivetti) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI @@ -37,3 +38,4 @@ dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI +endmenu diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 2358418e49f1..6423151e7ca1 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -33,6 +33,7 @@ endif ifeq ($(CONFIG_SCSI),y) L_OBJS += hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o +LX_OBJS += scsi_syms.o else ifeq ($(CONFIG_SCSI),m) MX_OBJS += scsi_syms.o @@ -72,6 +73,14 @@ else endif endif +ifeq ($(CONFIG_SCSI_ADVANSYS),y) +L_OBJS += advansys.o +else + ifeq ($(CONFIG_SCSI_ADVANSYS),m) + M_OBJS += advansys.o + endif +endif + ifeq ($(CONFIG_SCSI_QLOGIC),y) L_OBJS += qlogic.o else diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c new file mode 100644 index 000000000000..34dd617c5200 --- /dev/null +++ b/drivers/scsi/advansys.c @@ -0,0 +1,9061 @@ +/* $Id: advansys.c,v 1.11 1996/01/16 22:39:19 bobf Exp bobf $ */ +/* + * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters + * + * Copyright (c) 1995-1996 Advanced System Products, Inc. + * All Rights Reserved. + * + * This driver may be modified and freely distributed provided that + * the above copyright message and this comment are included in the + * distribution. The latest version of this driver is available at + * the AdvanSys FTP and BBS sites listed below. + * + * Please send questions, comments, bug reports to: + * bobf@advansys.com (Bob Frey) + */ + +/* The driver has been tested with Linux 1.2.1 and 1.3.57 kernels. */ +#define ASC_VERSION "1.2" /* AdvanSys Driver Version */ + +/* + + Documentation for the AdvanSys Driver + + A. Adapters Supported by this Driver + B. Linux 1.2.X - Directions for Adding the AdvanSys Driver + C. Linux 1.3.X - Directions for Adding the AdvanSys Driver + D. Source Comments + E. Driver Compile Time Options and Debugging + F. Driver LILO Option + G. Release History + H. Known Problems or Issues + I. Credits + J. AdvanSys Contact Information + + + A. Adapters Supported by this Driver + + AdvanSys (Advanced System Products, Inc.) manufactures the following + Bus-Mastering SCSI-2 Host Adapters for the ISA, EISA, VL, and PCI + buses. This Linux driver supports all of these adapters. + + The CDB counts below indicate the number of SCSI CDB (Command + Descriptor Block) requests that can be stored in the RISC chip + cache and board LRAM. The driver detect routine will display the + number of CDBs available for each adapter detected. This value + can be lowered in the BIOS by changing the 'Host Queue Size' + adapter setting. + + Connectivity Products: + ABP920 - Bus-Master PCI 16 CDB + ABP930 - Bus-Master PCI 16 CDB + ABP5140 - Bus-Master PnP ISA 16 CDB + + Single Channel Products: + ABP542 - Bus-Master ISA 240 CDB + ABP5150 - Bus-Master ISA 240 CDB * + ABP742 - Bus-Master EISA 240 CDB + ABP842 - Bus-Master VL 240 CDB + ABP940 - Bus-Master PCI 240 CDB + + Dual Channel Products: + ABP950 - Dual Channel Bus-Master PCI 240 CDB Per Channel + ABP852 - Dual Channel Bus-Master VL 240 CDB Per Channel + ABP752 - Dual Channel Bus-Master EISA 240 CDB Per Channel + + * This board is shipped by HP with the 4020i CD-R drive. It has + no BIOS so it cannot control a boot device, but it can control + any secondary devices. + + B. Linux 1.2.X - Directions for Adding the AdvanSys Driver + + There are two source files: advansys.h and advansys.c. Copy + both of these files to the directory /usr/src/linux/drivers/scsi. + + 1. Add the following line to /usr/src/linux/arch/i386/config.in + after "comment 'SCSI low-level drivers'": + + bool 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS y + + 2. Add the following lines to /usr/src/linux/drivers/scsi/hosts.c + after "#include "hosts.h"": + + #ifdef CONFIG_SCSI_ADVANSYS + #include "advansys.h" + #endif + + and after "static Scsi_Host_Template builtin_scsi_hosts[] =": + + #ifdef CONFIG_SCSI_ADVANSYS + ADVANSYS, + #endif + + 3. Add the following lines to /usr/src/linux/drivers/scsi/Makefile: + + ifdef CONFIG_SCSI_ADVANSYS + SCSI_SRCS := $(SCSI_SRCS) advansys.c + SCSI_OBJS := $(SCSI_OBJS) advansys.o + else + SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) advansys.o + endif + + 4. (Optional) If you would like to enable the LILO command line + and /etc/lilo.conf 'advansys' option, make the following changes. + This option can be used to disable I/O port scanning or to limit + I/O port scanning to specific addresses. Refer to the 'Driver + LILO Option' section below. Add the following lines to + /usr/src/linux/init/main.c in the prototype section: + + extern void advansys_setup(char *str, int *ints); + + and add the following lines to the bootsetups[] array. + + #ifdef CONFIG_SCSI_ADVANSYS + { "advansys=", advansys_setup }, + #endif + + 5. If you have the HP 4020i CD-R driver and Linux 1.2.X you should + add a fix to the CD-ROM target driver. This fix will allow + you to mount CDs with the iso9660 file system. Linux 1.3.X + already has this fix. In the file /usr/src/linux/drivers/scsi/sr.c + and function get_sectorsize() after the line: + + if(scsi_CDs[i].sector_size == 0) scsi_CDs[i].sector_size = 2048; + + add the following line: + + if(scsi_CDs[i].sector_size == 2340) scsi_CDs[i].sector_size = 2048; + + 6. In the directory /usr/src/linux run 'make config' to configure + the AdvanSys driver, then run 'make vmlinux' or 'make zlilo' to + make the kernel. If the AdvanSys driver is not configured, then + a loadable module can be built by running 'make modules' and + 'make modules_install'. Use 'insmod' and 'rmmod' to install + and remove advansys.o. + + C. Linux 1.3.X - Directions for Adding the AdvanSys Driver + + There are two source files: advansys.h and advansys.c. Copy + both of these files to the directory /usr/src/linux/drivers/scsi. + + 1. Add the following line to /usr/src/linux/drivers/scsi/Config.in + after "comment 'SCSI low-level drivers'": + + dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI + + 2. Add the following lines to /usr/src/linux/drivers/scsi/hosts.c + after "#include "hosts.h"": + + #ifdef CONFIG_SCSI_ADVANSYS + #include "advansys.h" + #endif + + and after "static Scsi_Host_Template builtin_scsi_hosts[] =": + + #ifdef CONFIG_SCSI_ADVANSYS + ADVANSYS, + #endif + + 3. Add the following lines to /usr/src/linux/drivers/scsi/Makefile: + + ifeq ($(CONFIG_SCSI_ADVANSYS),y) + L_OBJS += advansys.o + else + ifeq ($(CONFIG_SCSI_ADVANSYS),m) + M_OBJS += advansys.o + endif + endif + + 4. Add the following line to /usr/src/linux/include/linux/proc_fs.h + in the enum scsi_directory_inos array: + + PROC_SCSI_ADVANSYS, + + 5. (Optional) If you would like to enable the LILO command line + and /etc/lilo.conf 'advansys' option, make the following changes. + This option can be used to disable I/O port scanning or to limit + I/O port scanning to specific addresses. Refer to the 'Driver + LILO Option' section below. Add the following lines to + /usr/src/linux/init/main.c in the prototype section: + + extern void advansys_setup(char *str, int *ints); + + and add the following lines to the bootsetups[] array. + + #ifdef CONFIG_SCSI_ADVANSYS + { "advansys=", advansys_setup }, + #endif + + 6. In the directory /usr/src/linux run 'make config' to configure + the AdvanSys driver, then run 'make vmlinux' or 'make zlilo' to + make the kernel. If the AdvanSys driver is not configured, then + a loadable module can be built by running 'make modules' and + 'make modules_install'. Use 'insmod' and 'rmmod' to install + and remove advansys.o. + + D. Source Comments + + 1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'. + + 2. This driver should be maintained in multiple files. But to make + it easier to include with Linux and to follow Linux conventions, + the whole driver is maintained in the source files advansys.h and + advansys.c. In this file logical sections of the driver begin with + a comment that contains '---'. The following are the logical sections + of the driver below. + + --- Linux Version + --- Linux Include Files + --- Driver Options + --- Asc Library Constants and Macros + --- Debugging Header + --- Driver Constants + --- Driver Macros + --- Driver Structures + --- Driver Data + --- Driver Function Prototypes + --- Linux 'Scsi_Host_Template' and advansys_setup() Functions + --- Loadable Driver Support + --- Miscellaneous Driver Functions + --- Functions Required by the Asc Library + --- Tracing and Debugging Functions + --- Asc Library Functions + + 3. The string 'XXX' is used to flag code that needs to be re-written + or that contains a problem that needs to be addressed. + + 4. I have stripped comments from and reformatted the source for the + Asc Library which is included in this file. I haven't done this + to obfuscate the code. Actually I have done this to deobfuscate + the code. The Asc Library source can be found under the following + headings. + + --- Asc Library Constants and Macros + --- Asc Library Functions + + E. Driver Compile Time Options and Debugging + + In this source file the following constants can be defined. They are + defined in the source below. Both of these options are enabled by + default. + + 1. ADVANSYS_DEBUG - enable for debugging and assertions + + The amount of debugging output can be controlled with the global + variable 'asc_dbglvl'. The higher the number the more output. By + default the debug level is 0. + + If the driver is loaded at boot time and the LILO Driver Option + is included in the system, the debug level can be changed by + specifying a 5th (ASC_NUM_BOARD_SUPPORTED + 1) I/O Port. The + first three hex digits of the pseudo I/O Port must be set to + 'deb' and the fourth hex digit specifies the debug level: 0 - F. + The following command line will look for an adapter at 0x330 + and set the debug level to 2. + + linux advansys=0x330,0x0,0x0,0x0,0xdeb2 + + If the driver is built as a loadable module this variable can be + defined when the driver is loaded. The following insmod command + will set the debug level to one. + + insmod advansys.o asc_dbglvl=1 + + + Debugging Message Levels: + 0: Errors Only + 1: High-Level Tracing + 2-N: Verbose Tracing + + I don't know the approved way for turning on printk()s to the + console. Here's a program I use to do this. Debug output is + logged in /var/adm/messages. + + main() + { + syscall(103, 7, 0, 0); + } + + I found that increasing LOG_BUF_LEN to 40960 in kernel/printk.c + prevents most level 1 debug messages from being lost. + + 2. ADVANSYS_STATS - enable statistics and tracing + + For Linux 1.2.X if ADVANSYS_STATS_1_2_PRINT is defined every + 10,000 I/O operations the driver will print statistics to the + console. This value can be changed by modifying the constant + used in advansys_queuecommand(). ADVANSYS_STATS_1_2_PRINT is + off by default. + + For Linux 1.3.X statistics can be accessed by reading the + /proc/scsi/advansys/[0-9] files. + + Note: these statistics are currently maintained on a global driver + basis and not per board. + + F. Driver LILO Option + + If init/main.c is modified as described in the 'Directions for Adding + the AdvanSys Driver to Linux' section (B.4.) above, the driver will + recognize the 'advansys' LILO command line and /etc/lilo.conf option. + This option can be used to either disable I/O port scanning or to limit + scanning to 1 - 4 I/O ports. Regardless of the option setting EISA and + PCI boards will still be searched for and detected. This option only + affects searching for ISA and VL boards. + + Examples: + 1. Eliminate I/O port scanning: + boot: linux advansys= + or + boot: linux advansys=0x0 + 2. Limit I/O port scanning to one I/O port: + boot: linux advansys=0x110 + 3. Limit I/O port scanning to four I/O ports: + boot: linux advansys=0x110,0x210,0x230,0x330 + + For a loadable module the same effect can be achieved by setting + the 'asc_iopflag' variable and 'asc_ioport' array when loading + the driver, e.g. + + insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330 + + If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_BOARD_SUPPORTED + 1) + I/O Port may be added to specify the driver debug level. Refer to + the 'Driver Compile Time Options and Debugging' section above for + more information. + + G. Release History + + 12/23/95 BETA-1.0: + First Release + + 12/28/95 BETA-1.1: + 1. Prevent advansys_detect() from being called twice. + 2. Add LILO 0xdeb[0-f] option to set 'asc_dbglvl'. + + 1/12/96 1.2: + 1. Prevent re-entrancy in the interrupt handler which + resulted in the driver hanging Linux. + 2. Fix problem that prevented ABP-940 cards from being + recognized on some PCI motherboards. + 3. Add support for the ABP-5140 PnP ISA card. + 4. Fix check condition return status. + 5. Add conditionally compiled code for Linux 1.3.X. + + H. Known Problems or Issues + + 1. The setting for 'cmd_per_lun' needs to be changed. It is currently + less then what the AdvanSys boards can queue. Because the target and + mid-level Linux drivers base memory allocation on 'cmd_per_lun' (as + well as 'sg_tablesize') memory use gets out of hand with a large + 'cmd_per_lun'. 'cmd_per_lun' should be per device instead of per + adapter. When the driver is compiled as a loadable module both + 'cmd_per_lun' and 'sg_tablesize' are tuned down to try to prevent + memory allocation errors. + + 2. For the first scsi command sent to a device the driver increases + the timeout value. This gives the driver more time to perform + its own initialization for the board and each device. The timeout + value is only changed on the first scsi command for each device + and never thereafter. + + I. Credits + + Nathan Hartwell (mage@cdc3.cdc.net) provided the directions and + and basis for the Linux 1.3.X changes which were included in the + 1.2 release. + + J. AdvanSys Contact Information + + Mail: Advanced System Products, Inc. + 1150 Ringwood Court + San Jose, CA 95131 USA + Operator: 1-408-383-9400 + FAX: 1-408-383-9612 + Tech Support: 1-800-525-7440 + BBS: 1-408-383-9540 (9600,N,8,1) + Interactive FAX: 1-408-383-9753 + Customer Direct Sales: 1-800-883-1099 + Tech Support E-Mail: support@advansys.com + Linux Support E-Mail: bobf@advansys.com + FTP Site: ftp.advansys.com (login: anonymous) + Web Site: http://www.advansys.com + +*/ + + +/* + * --- Linux Version + */ + +/* + * The driver can be used in Linux 1.2.X or 1.3.X. + */ +#if !defined(LINUX_1_2) && !defined(LINUX_1_3) +#ifndef LINUX_VERSION_CODE +#include +#endif /* LINUX_VERSION_CODE */ +#if LINUX_VERSION_CODE > 65536 + 3 * 256 +#define LINUX_1_3 +#else /* LINUX_VERSION_CODE */ +#define LINUX_1_2 +#endif /* LINUX_VERSION_CODE */ +#endif /* !defined(LINUX_1_2) && !defined(LINUX_1_3) */ + + +/* + * --- Linux Include Files + */ + +#ifdef MODULE +#ifdef LINUX_1_3 +#include +#endif /* LINUX_1_3 */ +#include +#endif /* MODULE */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef LINUX_1_3 +#include +#endif /* LINUX_1_3 */ +#include +#include +#include +#ifdef LINUX_1_2 +#include "../block/blk.h" +#else /* LINUX_1_3 */ +#include +#include +#endif /* LINUX_1_3 */ +#include "scsi.h" +#include "hosts.h" +#include "sd.h" +#include "advansys.h" + + +/* + * --- Driver Options + */ +#define ADVANSYS_DEBUG /* Enable for debugging and assertions. */ +#define ADVANSYS_STATS /* Enable for statistics and tracing. */ +#ifdef LINUX_1_2 +#undef ADVANSYS_STATS_1_2_PRINT /* Enable to print statistics to console. */ +#endif /* LINUX_1_2 */ + + +/* + * --- Asc Library Constants and Macros + */ + +#define ASC_LIB_VERSION_MAJOR 1 +#define ASC_LIB_VERSION_MINOR 16 +#define ASC_LIB_SERIAL_NUMBER 53 + +typedef unsigned char uchar; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; + +typedef int BOOL; + +#ifndef NULL +#define NULL (0) +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#define REG register + +#define rchar REG char +#define rshort REG short +#define rint REG int +#define rlong REG long + +#define ruchar REG uchar +#define rushort REG ushort +#define ruint REG uint +#define rulong REG ulong + +#define NULLPTR ( void *)0 +#define FNULLPTR ( void dosfar *)0UL +#define EOF (-1) +#define EOS '\0' +#define ERR (-1) +#define UB_ERR (uchar)(0xFF) +#define UW_ERR (uint)(0xFFFF) +#define UL_ERR (ulong)(0xFFFFFFFFUL) + +#define iseven_word( val ) ( ( ( ( uint )val) & ( uint )0x0001 ) == 0 ) +#define isodd_word( val ) ( ( ( ( uint )val) & ( uint )0x0001 ) != 0 ) +#define toeven_word( val ) ( ( ( uint )val ) & ( uint )0xFFFE ) + +#define biton( val, bits ) ((( uint )( val >> bits ) & (uint)0x0001 ) != 0 ) +#define bitoff( val, bits ) ((( uint )( val >> bits ) & (uint)0x0001 ) == 0 ) +#define lbiton( val, bits ) ((( ulong )( val >> bits ) & (ulong)0x00000001UL ) != 0 ) +#define lbitoff( val, bits ) ((( ulong )( val >> bits ) & (ulong)0x00000001UL ) == 0 ) + +#define absh( val ) ( ( val ) < 0 ? -( val ) : ( val ) ) + +#define swapbyte( ch ) ( ( ( (ch) << 4 ) | ( (ch) >> 4 ) ) ) + +#ifndef GBYTE +#define GBYTE (0x40000000UL) +#endif + +#ifndef MBYTE +#define MBYTE (0x100000UL) +#endif + +#ifndef KBYTE +#define KBYTE (0x400) +#endif + +#define HI_BYTE(x) ( *( ( BYTE *)(&x)+1 ) ) +#define LO_BYTE(x) ( *( ( BYTE *)&x ) ) + +#define HI_WORD(x) ( *( ( WORD *)(&x)+1 ) ) +#define LO_WORD(x) ( *( ( WORD *)&x ) ) + +#ifndef MAKEWORD +#define MAKEWORD(lo, hi) ((WORD) (((WORD) lo) | ((WORD) hi << 8))) +#endif + +#ifndef MAKELONG +#define MAKELONG(lo, hi) ((DWORD) (((DWORD) lo) | ((DWORD) hi << 16))) +#endif + +#define SwapWords(dWord) ((DWORD) ((dWord >> 16) | (dWord << 16))) +#define SwapBytes(word) ((WORD) ((word >> 8) | (word << 8))) + +#define BigToLittle(dWord) \ + ((DWORD) (SwapWords(MAKELONG(SwapBytes(LO_WORD(dWord)), SwapBytes(HI_WORD(dWord)))))) +#define LittleToBig(dWord) BigToLittle(dWord) + +#define Lptr +#define dosfar +#define far +#define PortAddr unsigned short +#define Ptr2Func ulong + +#define inp(port) inb(port) +#define inpw(port) inw(port) +#define outp(port, byte) outb((byte), (port)) +#define outpw(port, word) outw((word), (port)) + +#define ASC_MAX_SG_QUEUE 5 +#define ASC_MAX_SG_LIST (1 + ((ASC_SG_LIST_PER_Q) * (ASC_MAX_SG_QUEUE))) + +#define CC_INIT_INQ_DISPLAY FALSE + +#define CC_CLEAR_LRAM_SRB_PTR FALSE +#define CC_VERIFY_LRAM_COPY FALSE + +#define CC_DEBUG_SG_LIST FALSE +#define CC_FAST_STRING_IO FALSE + +#define CC_WRITE_IO_COUNT FALSE +#define CC_CLEAR_DMA_REMAIN FALSE + +#define CC_DISABLE_PCI_PARITY_INT TRUE + +#define CC_LINK_BUSY_Q FALSE + +#define CC_TARGET_MODE FALSE + +#define CC_SCAM FALSE + +#define CC_LITTLE_ENDIAN_HOST TRUE + +#ifndef CC_TEST_LRAM_ENDIAN + +#if CC_LITTLE_ENDIAN_HOST +#define CC_TEST_LRAM_ENDIAN FALSE +#else +#define CC_TEST_LRAM_ENDIAN TRUE +#endif + +#endif + +#define CC_STRUCT_ALIGNED TRUE + +#define CC_MEMORY_MAPPED_IO FALSE + +#ifndef CC_TARGET_MODE +#define CC_TARGET_MODE FALSE +#endif + +#ifndef CC_STRUCT_ALIGNED +#define CC_STRUCT_ALIGNED FALSE +#endif + +#ifndef CC_LITTLE_ENDIAN_HOST +#define CC_LITTLE_ENDIAN_HOST TRUE +#endif + +#if !CC_LITTLE_ENDIAN_HOST + +#ifndef CC_TEST_LRAM_ENDIAN +#define CC_TEST_LRAM_ENDIAN TRUE +#endif + +#endif + +#ifndef CC_MEMORY_MAPPED_IO +#define CC_MEMORY_MAPPED_IO FALSE +#endif + +#ifndef CC_WRITE_IO_COUNT +#define CC_WRITE_IO_COUNT FALSE +#endif + +#ifndef CC_CLEAR_DMA_REMAIN +#define CC_CLEAR_DMA_REMAIN FALSE +#endif + +#define ASC_CS_TYPE unsigned short + +#ifndef asc_ptr_type +#define asc_ptr_type +#endif + +#ifndef CC_SCAM +#define CC_SCAM FALSE +#endif + +#ifndef ASC_GET_PTR2FUNC +#define ASC_GET_PTR2FUNC( fun ) ( Ptr2Func )( fun ) +#endif + +#define FLIP_BYTE_NIBBLE( x ) ( ((x<<4)& 0xFF) | (x>>4) ) + +#define ASC_IS_ISA (0x0001) +#define ASC_IS_ISAPNP (0x0081) +#define ASC_IS_EISA (0x0002) +#define ASC_IS_PCI (0x0004) +#define ASC_IS_PCMCIA (0x0008) +#define ASC_IS_PNP (0x0010) +#define ASC_IS_MCA (0x0020) +#define ASC_IS_VL (0x0040) + +#define ASC_ISA_PNP_PORT_ADDR (0x279) +#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800) + +#define ASC_IS_WIDESCSI_16 (0x0100) +#define ASC_IS_WIDESCSI_32 (0x0200) + +#define ASC_IS_BIG_ENDIAN (0x8000) + +#define ASC_CHIP_MIN_VER_VL (0x01) +#define ASC_CHIP_MAX_VER_VL (0x07) + +#define ASC_CHIP_MIN_VER_PCI (0x09) +#define ASC_CHIP_MAX_VER_PCI (0x0F) +#define ASC_CHIP_VER_PCI_BIT (0x08) + +#define ASC_CHIP_MIN_VER_ISA (0x11) +#define ASC_CHIP_MIN_VER_ISA_PNP (0x21) +#define ASC_CHIP_MAX_VER_ISA (0x27) +#define ASC_CHIP_VER_ISA_BIT (0x30) +#define ASC_CHIP_VER_ISAPNP_BIT (0x20) + +#define ASC_CHIP_VER_ASYN_BUG (0x21) + +#define ASC_CHIP_MIN_VER_EISA (0x41) +#define ASC_CHIP_MAX_VER_EISA (0x47) +#define ASC_CHIP_VER_EISA_BIT (0x40) + +#define ASC_MAX_VL_DMA_ADDR (0x07FFFFFFL) +#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL) + +#define ASC_MAX_PCI_DMA_ADDR (0xFFFFFFFFL) +#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL) + +#define ASC_MAX_ISA_DMA_ADDR (0x00FFFFFFL) +#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL) + +#define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL) +#define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL) + +#if !CC_STRUCT_ALIGNED + +#define DvcGetQinfo( iop_base, s_addr, outbuf, words) \ + AscMemWordCopyFromLram( iop_base, s_addr, outbuf, words) + +#define DvcPutScsiQ( iop_base, s_addr, outbuf, words) \ + AscMemWordCopyToLram( iop_base, s_addr, outbuf, words) + +#endif + +#define ASC_SCSI_ID_BITS 3 +#define ASC_SCSI_TIX_TYPE uchar +#define ASC_ALL_DEVICE_BIT_SET 0xFF + +#ifdef ASC_WIDESCSI_16 + +#undef ASC_SCSI_ID_BITS +#define ASC_SCSI_ID_BITS 4 +#define ASC_ALL_DEVICE_BIT_SET 0xFFFF + +#endif + +#ifdef ASC_WIDESCSI_32 + +#undef ASC_SCSI_ID_BITS +#define ASC_SCSI_ID_BITS 5 +#define ASC_ALL_DEVICE_BIT_SET 0xFFFFFFFFL + +#endif + +#if ASC_SCSI_ID_BITS == 3 + +#define ASC_SCSI_BIT_ID_TYPE uchar +#define ASC_MAX_TID 7 +#define ASC_MAX_LUN 7 +#define ASC_SCSI_WIDTH_BIT_SET 0xFF + +#elif ASC_SCSI_ID_BITS == 4 + +#define ASC_SCSI_BIT_ID_TYPE ushort +#define ASC_MAX_TID 15 +#define ASC_MAX_LUN 7 +#define ASC_SCSI_WIDTH_BIT_SET 0xFFFF + +#elif ASC_SCSI_ID_BITS == 5 + +#define ASC_SCSI_BIT_ID_TYPE ulong +#define ASC_MAX_TID 31 +#define ASC_MAX_LUN 7 +#define ASC_SCSI_WIDTH_BIT_SET 0xFFFFFFFF + +#else + +#error ASC_SCSI_ID_BITS definition is wrong + +#endif + +#define ASC_MAX_SENSE_LEN 32 +#define ASC_MIN_SENSE_LEN 14 + +#define ASC_MAX_CDB_LEN 12 + +#define SCSICMD_TestUnitReady 0x00 +#define SCSICMD_Rewind 0x01 +#define SCSICMD_Rezero 0x01 +#define SCSICMD_RequestSense 0x03 +#define SCSICMD_Format 0x04 +#define SCSICMD_FormatUnit 0x04 +#define SCSICMD_Read6 0x08 +#define SCSICMD_Write6 0x0A +#define SCSICMD_Seek6 0x0B +#define SCSICMD_Inquiry 0x12 +#define SCSICMD_Verify6 0x13 +#define SCSICMD_ModeSelect6 0x15 +#define SCSICMD_ModeSense6 0x1A + +#define SCSICMD_StartStopUnit 0x1B +#define SCSICMD_LoadUnloadTape 0x1B +#define SCSICMD_ReadCapacity 0x25 +#define SCSICMD_Read10 0x28 +#define SCSICMD_Write10 0x2A +#define SCSICMD_Seek10 0x2B +#define SCSICMD_Erase10 0x2C +#define SCSICMD_WriteAndVerify10 0x2E +#define SCSICMD_Verify10 0x2F + +#define SCSICMD_ModeSelect10 0x55 +#define SCSICMD_ModeSense10 0x5A + +#define SCSI_TYPE_DASD 0x00 +#define SCSI_TYPE_SASD 0x01 +#define SCSI_TYPE_PRN 0x02 +#define SCSI_TYPE_PROC 0x03 + +#define SCSI_TYPE_WORM 0x04 +#define SCSI_TYPE_CDROM 0x05 +#define SCSI_TYPE_SCANNER 0x06 +#define SCSI_TYPE_OPTMEM 0x07 +#define SCSI_TYPE_MED_CHG 0x08 +#define SCSI_TYPE_COMM 0x09 +#define SCSI_TYPE_UNKNOWN 0x1F +#define SCSI_TYPE_NO_DVC 0xFF + +#define ASC_SCSIDIR_NOCHK 0x00 + +#define ASC_SCSIDIR_T2H 0x08 + +#define ASC_SCSIDIR_H2T 0x10 + +#define ASC_SCSIDIR_NODATA 0x18 + +#define SCSI_SENKEY_NO_SENSE 0x00 +#define SCSI_SENKEY_UNDEFINED 0x01 +#define SCSI_SENKEY_NOT_READY 0x02 +#define SCSI_SENKEY_MEDIUM_ERR 0x03 +#define SCSI_SENKEY_HW_ERR 0x04 +#define SCSI_SENKEY_ILLEGAL 0x05 +#define SCSI_SENKEY_ATTENSION 0x06 +#define SCSI_SENKEY_PROTECTED 0x07 +#define SCSI_SENKEY_BLANK 0x08 +#define SCSI_SENKEY_V_UNIQUE 0x09 +#define SCSI_SENKEY_CPY_ABORT 0x0A +#define SCSI_SENKEY_ABORT 0x0B +#define SCSI_SENKEY_EQUAL 0x0C +#define SCSI_SENKEY_VOL_OVERFLOW 0x0D +#define SCSI_SENKEY_MISCOMP 0x0E +#define SCSI_SENKEY_RESERVED 0x0F + +#define ASC_SRB_HOST( x ) ( ( uchar )( ( uchar )( x ) >> 4 ) ) +#define ASC_SRB_TID( x ) ( ( uchar )( ( uchar )( x ) & ( uchar )0x0F ) ) + +#define ASC_SRB_LUN( x ) ( ( uchar )( ( uint )( x ) >> 13 ) ) + +#define PUT_CDB1( x ) ( ( uchar )( ( uint )( x ) >> 8 ) ) + +#define SS_GOOD 0x00 +#define SS_CHK_CONDITION 0x02 +#define SS_CONDITION_MET 0x04 +#define SS_TARGET_BUSY 0x08 +#define SS_INTERMID 0x10 +#define SS_INTERMID_COND_MET 0x14 + +#define SS_RSERV_CONFLICT 0x18 +#define SS_CMD_TERMINATED 0x22 + +#define SS_QUEUE_FULL 0x28 + +#define MS_CMD_DONE 0x00 +#define MS_EXTEND 0x01 +#define MS_SDTR_LEN 0x03 +#define MS_SDTR_CODE 0x01 + +#define M1_SAVE_DATA_PTR 0x02 +#define M1_RESTORE_PTRS 0x03 +#define M1_DISCONNECT 0x04 +#define M1_INIT_DETECTED_ERR 0x05 +#define M1_ABORT 0x06 +#define M1_MSG_REJECT 0x07 +#define M1_NO_OP 0x08 +#define M1_MSG_PARITY_ERR 0x09 +#define M1_LINK_CMD_DONE 0x0A +#define M1_LINK_CMD_DONE_WFLAG 0x0B +#define M1_BUS_DVC_RESET 0x0C +#define M1_ABORT_TAG 0x0D +#define M1_CLR_QUEUE 0x0E +#define M1_INIT_RECOVERY 0x0F +#define M1_RELEASE_RECOVERY 0x10 +#define M1_KILL_IO_PROC 0x11 + +#define M2_QTAG_MSG_SIMPLE 0x20 +#define M2_QTAG_MSG_HEAD 0x21 +#define M2_QTAG_MSG_ORDERED 0x22 +#define M2_IGNORE_WIDE_RESIDUE 0x23 + +typedef struct { + uchar peri_dvc_type:5; + uchar peri_qualifier:3; +} ASC_SCSI_INQ0; + +typedef struct { + uchar dvc_type_modifier:7; + uchar rmb:1; +} ASC_SCSI_INQ1; + +typedef struct { + uchar ansi_apr_ver:3; + uchar ecma_ver:3; + uchar iso_ver:2; +} ASC_SCSI_INQ2; + +typedef struct { + uchar rsp_data_fmt:4; + + uchar res:2; + uchar TemIOP:1; + uchar aenc:1; +} ASC_SCSI_INQ3; + +typedef struct { + uchar StfRe:1; + uchar CmdQue:1; + uchar Reserved:1; + uchar Linked:1; + uchar Sync:1; + uchar WBus16:1; + uchar WBus32:1; + uchar RelAdr:1; +} ASC_SCSI_INQ7; + +typedef struct { + ASC_SCSI_INQ0 byte0; + ASC_SCSI_INQ1 byte1; + ASC_SCSI_INQ2 byte2; + ASC_SCSI_INQ3 byte3; + uchar add_len; + uchar res1; + uchar res2; + ASC_SCSI_INQ7 byte7; + uchar vendor_id[8]; + uchar product_id[16]; + uchar product_rev_level[4]; +} ASC_SCSI_INQUIRY; + +typedef struct asc_req_sense { + uchar err_code:7; + uchar info_valid:1; + uchar segment_no; + uchar sense_key:4; + uchar reserved_bit:1; + uchar sense_ILI:1; + uchar sense_EOM:1; + uchar file_mark:1; + uchar info1[4]; + uchar add_sense_len; + uchar cmd_sp_info[4]; + uchar asc; + uchar ascq; + + uchar fruc; + uchar sks_byte0:7; + uchar sks_valid:1; + uchar sks_bytes[2]; + uchar notused[2]; + uchar ex_sense_code; + uchar info2[4]; +} ASC_REQ_SENSE; + +#define ASC_SG_LIST_PER_Q 7 + +#define QS_FREE 0x00 +#define QS_READY 0x01 +#define QS_DISC1 0x02 +#define QS_DISC2 0x04 +#define QS_BUSY 0x08 + +#define QS_ABORTED 0x40 +#define QS_DONE 0x80 + +#define QC_NO_CALLBACK 0x01 + +#define QC_SG_SWAP_QUEUE 0x02 +#define QC_SG_HEAD 0x04 +#define QC_DATA_IN 0x08 +#define QC_DATA_OUT 0x10 + +#define QC_URGENT 0x20 +#define QC_MSG_OUT 0x40 +#define QC_REQ_SENSE 0x80 + +#define QCSG_SG_XFER_LIST 0x02 +#define QCSG_SG_XFER_MORE 0x04 +#define QCSG_SG_XFER_END 0x08 + +#define QD_IN_PROGRESS 0x00 +#define QD_NO_ERROR 0x01 +#define QD_ABORTED_BY_HOST 0x02 +#define QD_WITH_ERROR 0x04 +#define QD_INVALID_REQUEST 0x80 +#define QD_INVALID_HOST_NUM 0x81 +#define QD_INVALID_DEVICE 0x82 +#define QD_ERR_INTERNAL 0xFF + +#define QHSTA_NO_ERROR 0x00 +#define QHSTA_M_SEL_TIMEOUT 0x11 +#define QHSTA_M_DATA_OVER_RUN 0x12 +#define QHSTA_M_DATA_UNDER_RUN 0x12 +#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13 +#define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14 + +#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21 +#define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22 +#define QHSTA_D_HOST_ABORT_FAILED 0x23 +#define QHSTA_D_EXE_SCSI_Q_FAILED 0x24 +#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25 + +#define QHSTA_D_ASPI_NO_BUF_POOL 0x26 + +#define QHSTA_M_WTM_TIMEOUT 0x41 +#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42 +#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43 +#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44 +#define QHSTA_M_TARGET_STATUS_BUSY 0x45 +#define QHSTA_M_BAD_TAG_CODE 0x46 + +#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47 + +#define QHSTA_D_LRAM_CMP_ERROR 0x81 +#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1 + +#define ASC_FLAG_SCSIQ_REQ 0x01 +#define ASC_FLAG_BIOS_SCSIQ_REQ 0x02 +#define ASC_FLAG_BIOS_ASYNC_IO 0x04 +#define ASC_FLAG_SRB_LINEAR_ADDR 0x08 + +#define ASC_FLAG_WIN16 0x10 +#define ASC_FLAG_WIN32 0x20 + +#define ASC_FLAG_DOS_VM_CALLBACK 0x80 + +#define ASC_TAG_FLAG_ADD_ONE_BYTE 0x10 +#define ASC_TAG_FLAG_ISAPNP_ADD_BYTES 0x40 + +#define ASC_SCSIQ_CPY_BEG 4 +#define ASC_SCSIQ_SGHD_CPY_BEG 2 + +#define ASC_SCSIQ_B_FWD 0 +#define ASC_SCSIQ_B_BWD 1 + +#define ASC_SCSIQ_B_STATUS 2 +#define ASC_SCSIQ_B_QNO 3 + +#define ASC_SCSIQ_B_CNTL 4 +#define ASC_SCSIQ_B_SG_QUEUE_CNT 5 + +#define ASC_SCSIQ_D_DATA_ADDR 8 +#define ASC_SCSIQ_D_DATA_CNT 12 +#define ASC_SCSIQ_B_SENSE_LEN 20 +#define ASC_SCSIQ_DONE_INFO_BEG 22 +#define ASC_SCSIQ_D_SRBPTR 22 +#define ASC_SCSIQ_B_TARGET_IX 26 +#define ASC_SCSIQ_B_CDB_LEN 28 +#define ASC_SCSIQ_B_TAG_CODE 29 +#define ASC_SCSIQ_W_VM_ID 30 +#define ASC_SCSIQ_DONE_STATUS 32 +#define ASC_SCSIQ_HOST_STATUS 33 +#define ASC_SCSIQ_SCSI_STATUS 34 +#define ASC_SCSIQ_CDB_BEG 36 +#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56 +#define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60 +#define ASC_SCSIQ_B_SG_WK_QP 49 +#define ASC_SCSIQ_B_SG_WK_IX 50 +#define ASC_SCSIQ_W_REQ_COUNT 52 +#define ASC_SCSIQ_B_LIST_CNT 6 +#define ASC_SCSIQ_B_CUR_LIST_CNT 7 + +#define ASC_SGQ_B_SG_CNTL 4 +#define ASC_SGQ_B_SG_HEAD_QP 5 +#define ASC_SGQ_B_SG_LIST_CNT 6 +#define ASC_SGQ_B_SG_CUR_LIST_CNT 7 +#define ASC_SGQ_LIST_BEG 8 + +#define ASC_DEF_SCSI1_QNG 2 +#define ASC_MAX_SCSI1_QNG 2 +#define ASC_DEF_SCSI2_QNG 16 +#define ASC_MAX_SCSI2_QNG 32 + +#define ASC_TAG_CODE_MASK 0x23 + +#define ASC_STOP_REQ_RISC_STOP 0x01 + +#define ASC_STOP_ACK_RISC_STOP 0x03 + +#define ASC_STOP_CLEAN_UP_BUSY_Q 0x10 +#define ASC_STOP_CLEAN_UP_DISC_Q 0x20 +#define ASC_STOP_HOST_REQ_RISC_HALT 0x40 +#define ASC_STOP_SEND_INT_TO_HOST 0x80 + +#define ASC_TIDLUN_TO_IX( tid, lun ) ( ASC_SCSI_TIX_TYPE )( (tid) + ((lun)<> ASC_SCSI_ID_BITS ) & ASC_MAX_LUN ) + +#define ASC_QNO_TO_QADDR( q_no ) ( (ASC_QADR_BEG)+( ( int )(q_no) << 6 ) ) + +typedef struct asc_scisq_1 { + uchar status; + uchar q_no; + uchar cntl; + uchar sg_queue_cnt; + + uchar target_id; + uchar target_lun; + + ulong data_addr; + ulong data_cnt; + ulong sense_addr; + uchar sense_len; + uchar user_def; +} ASC_SCSIQ_1; + +typedef struct asc_scisq_2 { + ulong srb_ptr; + uchar target_ix; + + uchar flag; + uchar cdb_len; + uchar tag_code; + + ushort vm_id; +} ASC_SCSIQ_2; + +typedef struct asc_scsiq_3 { + uchar done_stat; + uchar host_stat; + uchar scsi_stat; + uchar scsi_msg; +} ASC_SCSIQ_3; + +typedef struct asc_scsiq_4 { + uchar cdb[ASC_MAX_CDB_LEN]; + uchar y_first_sg_list_qp; + uchar y_working_sg_qp; + uchar y_working_sg_ix; + uchar y_cntl; + ushort x_req_count; + ushort x_reconnect_rtn; + ulong x_saved_data_addr; + ulong x_saved_data_cnt; +} ASC_SCSIQ_4; + +typedef struct asc_q_done_info { + ASC_SCSIQ_2 d2; + ASC_SCSIQ_3 d3; + uchar q_status; + uchar q_no; + uchar cntl; + uchar sense_len; + uchar user_def; + uchar res; + ulong remain_bytes; +} ASC_QDONE_INFO; + +typedef struct asc_sg_list { + ulong addr; + ulong bytes; +} ASC_SG_LIST; + +typedef struct asc_sg_head { + uchar entry_cnt; + + uchar queue_cnt; + + uchar entry_to_copy; + uchar res; + ASC_SG_LIST sg_list[ASC_MAX_SG_LIST]; +} ASC_SG_HEAD; + +#define ASC_MIN_SG_LIST 2 + +typedef struct asc_min_sg_head { + uchar entry_cnt; + + uchar queue_cnt; + + uchar entry_to_copy; + uchar res; + ASC_SG_LIST sg_list[ASC_MIN_SG_LIST]; +} ASC_MIN_SG_HEAD; + +#define QCX_SORT (0x0001) +#define QCX_COALEASE (0x0002) + +#if CC_LINK_BUSY_Q +typedef struct asc_ext_scsi_q { + ulong lba; + ushort lba_len; + struct asc_scsi_q dosfar *next; + struct asc_scsi_q dosfar *join; + ushort cntl; + ushort buffer_id; + uchar q_required; + uchar res; +} ASC_EXT_SCSI_Q; + +#endif + +typedef struct asc_scsi_q { + ASC_SCSIQ_1 q1; + ASC_SCSIQ_2 q2; + uchar dosfar *cdbptr; + + ASC_SG_HEAD dosfar *sg_head; + +#if CC_LINK_BUSY_Q + ASC_EXT_SCSI_Q ext; +#endif + +} ASC_SCSI_Q; + +typedef struct asc_scsi_req_q { + ASC_SCSIQ_1 r1; + ASC_SCSIQ_2 r2; + uchar dosfar *cdbptr; + ASC_SG_HEAD dosfar *sg_head; + +#if CC_LINK_BUSY_Q + ASC_EXT_SCSI_Q ext; +#endif + + uchar dosfar *sense_ptr; + + ASC_SCSIQ_3 r3; + uchar cdb[ASC_MAX_CDB_LEN]; + uchar sense[ASC_MIN_SENSE_LEN]; +} ASC_SCSI_REQ_Q; + +typedef struct asc_risc_q { + uchar fwd; + uchar bwd; + ASC_SCSIQ_1 i1; + ASC_SCSIQ_2 i2; + ASC_SCSIQ_3 i3; + ASC_SCSIQ_4 i4; +} ASC_RISC_Q; + +typedef struct asc_sg_list_q { + + uchar seq_no; + uchar q_no; + uchar cntl; + uchar sg_head_qp; + uchar sg_list_cnt; + uchar sg_cur_list_cnt; + +} ASC_SG_LIST_Q; + +typedef struct asc_risc_sg_list_q { + uchar fwd; + uchar bwd; + ASC_SG_LIST_Q sg; + ASC_SG_LIST sg_list[7]; +} ASC_RISC_SG_LIST_Q; + +#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL +#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP 1024 + +#define ASCQ_ERR_NO_ERROR 0 +#define ASCQ_ERR_IO_NOT_FOUND 1 +#define ASCQ_ERR_LOCAL_MEM 2 +#define ASCQ_ERR_CHKSUM 3 +#define ASCQ_ERR_START_CHIP 4 +#define ASCQ_ERR_INT_TARGET_ID 5 +#define ASCQ_ERR_INT_LOCAL_MEM 6 +#define ASCQ_ERR_HALT_RISC 7 +#define ASCQ_ERR_GET_ASPI_ENTRY 8 +#define ASCQ_ERR_CLOSE_ASPI 9 +#define ASCQ_ERR_HOST_INQUIRY 0x0A +#define ASCQ_ERR_SAVED_SRB_BAD 0x0B +#define ASCQ_ERR_QCNTL_SG_LIST 0x0C +#define ASCQ_ERR_Q_STATUS 0x0D +#define ASCQ_ERR_WR_SCSIQ 0x0E +#define ASCQ_ERR_PC_ADDR 0x0F +#define ASCQ_ERR_SYN_OFFSET 0x10 +#define ASCQ_ERR_SYN_XFER_TIME 0x11 +#define ASCQ_ERR_LOCK_DMA 0x12 +#define ASCQ_ERR_UNLOCK_DMA 0x13 +#define ASCQ_ERR_VDS_CHK_INSTALL 0x14 +#define ASCQ_ERR_MICRO_CODE_HALT 0x15 +#define ASCQ_ERR_SET_LRAM_ADDR 0x16 +#define ASCQ_ERR_CUR_QNG 0x17 +#define ASCQ_ERR_SG_Q_LINKS 0x18 +#define ASCQ_ERR_SCSIQ_PTR 0x19 +#define ASCQ_ERR_ISR_RE_ENTRY 0x1A +#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B +#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C +#define ASCQ_ERR_SG_LIST_ODD_ADDRESS 0x1D +#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E +#define ASCQ_ERR_SCSIQ_NULL_PTR 0x1F +#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR 0x20 +#define ASCQ_ERR_GET_NUM_OF_FREE_Q 0x21 +#define ASCQ_ERR_SEND_SCSI_Q 0x22 +#define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23 +#define ASCQ_ERR_RESET_SDTR 0x24 + +#define ASC_WARN_NO_ERROR 0x0000 +#define ASC_WARN_IO_PORT_ROTATE 0x0001 +#define ASC_WARN_EEPROM_CHKSUM 0x0002 +#define ASC_WARN_IRQ_MODIFIED 0x0004 +#define ASC_WARN_AUTO_CONFIG 0x0008 +#define ASC_WARN_CMD_QNG_CONFLICT 0x0010 + +#define ASC_WARN_EEPROM_RECOVER 0x0020 +#define ASC_WARN_CFG_MSW_RECOVER 0x0040 + +#define ASC_IERR_WRITE_EEPROM 0x0001 +#define ASC_IERR_MCODE_CHKSUM 0x0002 +#define ASC_IERR_SET_PC_ADDR 0x0004 +#define ASC_IERR_START_STOP_CHIP 0x0008 + +#define ASC_IERR_IRQ_NO 0x0010 + +#define ASC_IERR_SET_IRQ_NO 0x0020 +#define ASC_IERR_CHIP_VERSION 0x0040 +#define ASC_IERR_SET_SCSI_ID 0x0080 +#define ASC_IERR_GET_PHY_ADDR 0x0100 +#define ASC_IERR_BAD_SIGNATURE 0x0200 +#define ASC_IERR_NO_BUS_TYPE 0x0400 +#define ASC_IERR_SCAM 0x0800 +#define ASC_IERR_SET_SDTR 0x1000 +#define ASC_IERR_RW_LRAM 0x8000 + +#define ASC_DEF_IRQ_NO 10 +#define ASC_MAX_IRQ_NO 15 +#define ASC_MIN_IRQ_NO 10 + +#define ASC_MIN_REMAIN_Q (0x02) +#define ASC_DEF_MAX_TOTAL_QNG (0x40) + +#define ASC_MIN_TAG_Q_PER_DVC (0x04) +#define ASC_DEF_TAG_Q_PER_DVC (0x04) + +#define ASC_MIN_FREE_Q ASC_MIN_REMAIN_Q + +#define ASC_MIN_TOTAL_QNG (( ASC_MAX_SG_QUEUE )+( ASC_MIN_FREE_Q )) + +#define ASC_MAX_TOTAL_QNG 240 +#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20 + +#define ASC_MAX_INRAM_TAG_QNG 16 + +typedef struct asc_dvc_cfg { + ASC_SCSI_BIT_ID_TYPE can_tagged_qng; + + ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled; + ASC_SCSI_BIT_ID_TYPE disc_enable; + uchar res; + uchar chip_scsi_id:4; + + uchar isa_dma_speed:4; + + uchar isa_dma_channel; + uchar chip_version; + ushort pci_device_id; + ushort lib_serial_no; + ushort lib_version; + ushort mcode_date; + ushort mcode_version; + uchar sdtr_data[ASC_MAX_TID + 1]; + uchar max_tag_qng[ASC_MAX_TID + 1]; + uchar dosfar *overrun_buf; + +} ASC_DVC_CFG; + +#define ASC_DEF_DVC_CNTL 0xFFFF +#define ASC_DEF_CHIP_SCSI_ID 7 +#define ASC_DEF_ISA_DMA_SPEED 4 + +#define ASC_INIT_STATE_NULL 0x0000 +#define ASC_INIT_STATE_BEG_GET_CFG 0x0001 +#define ASC_INIT_STATE_END_GET_CFG 0x0002 +#define ASC_INIT_STATE_BEG_SET_CFG 0x0004 +#define ASC_INIT_STATE_END_SET_CFG 0x0008 +#define ASC_INIT_STATE_BEG_LOAD_MC 0x0010 +#define ASC_INIT_STATE_END_LOAD_MC 0x0020 +#define ASC_INIT_STATE_BEG_INQUIRY 0x0040 +#define ASC_INIT_STATE_END_INQUIRY 0x0080 +#define ASC_INIT_RESET_SCSI_DONE 0x0100 + +#define ASC_PCI_DEVICE_ID_REV_A 0x1100 +#define ASC_PCI_DEVICE_ID_REV_B 0x1200 + +#define ASC_BUG_FIX_ADD_ONE_BYTE 0x0001 + +#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41 + +#define ASC_MIN_TAGGED_CMD 7 + +typedef struct asc_dvc_var { + PortAddr iop_base; + ushort err_code; + ushort dvc_cntl; + ushort bug_fix_cntl; + ushort bus_type; + Ptr2Func isr_callback; + Ptr2Func exe_callback; + + ASC_SCSI_BIT_ID_TYPE init_sdtr; + + ASC_SCSI_BIT_ID_TYPE sdtr_done; + + ASC_SCSI_BIT_ID_TYPE use_tagged_qng; + + ASC_SCSI_BIT_ID_TYPE unit_not_ready; + + ASC_SCSI_BIT_ID_TYPE queue_full_or_busy; + + ASC_SCSI_BIT_ID_TYPE start_motor; + uchar scsi_reset_wait; + uchar chip_no; + + char is_in_int; + uchar max_total_qng; + + uchar cur_total_qng; + + uchar in_critical_cnt; + + uchar irq_no; + uchar last_q_shortage; + + ushort init_state; + uchar cur_dvc_qng[ASC_MAX_TID + 1]; + uchar max_dvc_qng[ASC_MAX_TID + 1]; + + ASC_SCSI_Q dosfar *scsiq_busy_head[ASC_MAX_TID + 1]; + ASC_SCSI_Q dosfar *scsiq_busy_tail[ASC_MAX_TID + 1]; + + ulong int_count; + ulong req_count; + ulong busy_count; + + ASC_DVC_CFG dosfar *cfg; + Ptr2Func saved_ptr2func; + ulong reserved2; + ulong reserved3; + ulong max_dma_count; + ASC_SCSI_BIT_ID_TYPE no_scam; + ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer; +} ASC_DVC_VAR; + +typedef int (dosfar * ASC_ISR_CALLBACK) (ASC_DVC_VAR asc_ptr_type *, ASC_QDONE_INFO dosfar *); +typedef int (dosfar * ASC_EXE_CALLBACK) (ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *); + +typedef struct asc_dvc_inq_info { + uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1]; +} ASC_DVC_INQ_INFO; + +typedef struct asc_cap_info { + ulong lba; + ulong blk_size; +} ASC_CAP_INFO; + +typedef struct asc_cap_info_array { + ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1]; +} ASC_CAP_INFO_ARRAY; + +#define ASC_IOADR_TABLE_MAX_IX 11 +#define ASC_IOADR_GAP 0x10 +#define ASC_SEARCH_IOP_GAP 0x10 +#define ASC_MIN_IOP_ADDR ( PortAddr )0x0100 +#define ASC_MAX_IOP_ADDR ( PortAddr )0x3F0 + +#define ASC_IOADR_1 ( PortAddr )0x0110 +#define ASC_IOADR_2 ( PortAddr )0x0130 +#define ASC_IOADR_3 ( PortAddr )0x0150 +#define ASC_IOADR_4 ( PortAddr )0x0190 +#define ASC_IOADR_5 ( PortAddr )0x0210 +#define ASC_IOADR_6 ( PortAddr )0x0230 +#define ASC_IOADR_7 ( PortAddr )0x0250 +#define ASC_IOADR_8 ( PortAddr )0x0330 +#define ASC_IOADR_DEF ASC_IOADR_8 + +#define ASC_SYN_XFER_NO 8 +#define ASC_MAX_SDTR_PERIOD_INDEX 7 +#define ASC_SYN_MAX_OFFSET 0x0F +#define ASC_DEF_SDTR_OFFSET 0x0F +#define ASC_DEF_SDTR_INDEX 0x00 + +#define SYN_XFER_NS_0 25 +#define SYN_XFER_NS_1 30 +#define SYN_XFER_NS_2 35 +#define SYN_XFER_NS_3 40 +#define SYN_XFER_NS_4 50 +#define SYN_XFER_NS_5 60 +#define SYN_XFER_NS_6 70 +#define SYN_XFER_NS_7 85 + +#define ASC_SDTR_PERIOD_IX_MIN 7 + +#define SYN_XMSG_WLEN 3 + +typedef struct sdtr_xmsg { + uchar msg_type; + uchar msg_len; + uchar msg_req; + uchar xfer_period; + uchar req_ack_offset; + uchar res; +} SDTR_XMSG; + +#define ASC_MCNTL_NO_SEL_TIMEOUT ( ushort )0x0001 +#define ASC_MCNTL_NULL_TARGET ( ushort )0x0002 + +#define ASC_CNTL_INITIATOR ( ushort )0x0001 +#define ASC_CNTL_BIOS_GT_1GB ( ushort )0x0002 +#define ASC_CNTL_BIOS_GT_2_DISK ( ushort )0x0004 +#define ASC_CNTL_BIOS_REMOVABLE ( ushort )0x0008 +#define ASC_CNTL_NO_SCAM ( ushort )0x0010 +#define ASC_CNTL_NO_PCI_FIX_ASYN_XFER ( ushort )0x0020 + +#define ASC_CNTL_INT_MULTI_Q ( ushort )0x0080 + +#define ASC_CNTL_NO_LUN_SUPPORT ( ushort )0x0040 + +#define ASC_CNTL_NO_VERIFY_COPY ( ushort )0x0100 +#define ASC_CNTL_RESET_SCSI ( ushort )0x0200 +#define ASC_CNTL_INIT_INQUIRY ( ushort )0x0400 +#define ASC_CNTL_INIT_VERBOSE ( ushort )0x0800 + +#define ASC_CNTL_SCSI_PARITY ( ushort )0x1000 +#define ASC_CNTL_BURST_MODE ( ushort )0x2000 + +#define ASC_CNTL_USE_8_IOP_BASE ( ushort )0x4000 + +#define ASC_EEP_DVC_CFG_BEG_VL 2 +#define ASC_EEP_MAX_DVC_ADDR_VL 15 + +#define ASC_EEP_DVC_CFG_BEG 32 +#define ASC_EEP_MAX_DVC_ADDR 45 + +#define ASC_EEP_DEFINED_WORDS 10 +#define ASC_EEP_MAX_ADDR 63 +#define ASC_EEP_RES_WORDS 0 +#define ASC_EEP_MAX_RETRY 20 +#define ASC_MAX_INIT_BUSY_RETRY 8 + +#define ASC_EEP_ISA_PNP_WSIZE 16 + +typedef struct asceep_config { + ushort cfg_lsw; + ushort cfg_msw; + + uchar init_sdtr; + uchar disc_enable; + + uchar use_cmd_qng; + + uchar start_motor; + uchar max_total_qng; + uchar max_tag_qng; + uchar bios_scan; + + uchar power_up_wait; + + uchar no_scam; + uchar chip_scsi_id:4; + + uchar isa_dma_speed:4; + + uchar sdtr_data[ASC_MAX_TID + 1]; + + uchar adapter_info[6]; + + ushort cntl; + + ushort chksum; +} ASCEEP_CONFIG; + +#define ASC_EEP_CMD_READ 0x80 +#define ASC_EEP_CMD_WRITE 0x40 +#define ASC_EEP_CMD_WRITE_ABLE 0x30 +#define ASC_EEP_CMD_WRITE_DISABLE 0x00 + +#define ASC_OVERRUN_BSIZE 0x00000048UL + +#define ASCV_MSGOUT_BEG 0x0000 +#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3) +#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4) + +#define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8) +#define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3) +#define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4) + +#define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8) +#define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8) +#define ASCV_MAX_DVC_QNG_BEG ( ushort )0x0020 + +#define ASCV_ASCDVC_ERR_CODE_W ( ushort )0x0030 +#define ASCV_MCODE_CHKSUM_W ( ushort )0x0032 +#define ASCV_MCODE_SIZE_W ( ushort )0x0034 +#define ASCV_STOP_CODE_B ( ushort )0x0036 +#define ASCV_DVC_ERR_CODE_B ( ushort )0x0037 + +#define ASCV_OVERRUN_PADDR_D ( ushort )0x0038 +#define ASCV_OVERRUN_BSIZE_D ( ushort )0x003C + +#define ASCV_HALTCODE_W ( ushort )0x0040 +#define ASCV_CHKSUM_W ( ushort )0x0042 +#define ASCV_MC_DATE_W ( ushort )0x0044 +#define ASCV_MC_VER_W ( ushort )0x0046 +#define ASCV_NEXTRDY_B ( ushort )0x0048 +#define ASCV_DONENEXT_B ( ushort )0x0049 +#define ASCV_USE_TAGGED_QNG_B ( ushort )0x004A +#define ASCV_SCSIBUSY_B ( ushort )0x004B +#define ASCV_CDBCNT_B ( ushort )0x004C +#define ASCV_CURCDB_B ( ushort )0x004D +#define ASCV_RCLUN_B ( ushort )0x004E +#define ASCV_BUSY_QHEAD_B ( ushort )0x004F +#define ASCV_DISC1_QHEAD_B ( ushort )0x0050 + +#define ASCV_DISC_ENABLE_B ( ushort )0x0052 +#define ASCV_CAN_TAGGED_QNG_B ( ushort )0x0053 +#define ASCV_HOSTSCSI_ID_B ( ushort )0x0055 +#define ASCV_MCODE_CNTL_B ( ushort )0x0056 +#define ASCV_NULL_TARGET_B ( ushort )0x0057 + +#define ASCV_FREE_Q_HEAD_W ( ushort )0x0058 +#define ASCV_DONE_Q_TAIL_W ( ushort )0x005A +#define ASCV_FREE_Q_HEAD_B ( ushort )(ASCV_FREE_Q_HEAD_W+1) +#define ASCV_DONE_Q_TAIL_B ( ushort )(ASCV_DONE_Q_TAIL_W+1) + +#define ASCV_HOST_FLAG_B ( ushort )0x005D + +#define ASCV_TOTAL_READY_Q_B ( ushort )0x0064 +#define ASCV_VER_SERIAL_B ( ushort )0x0065 +#define ASCV_HALTCODE_SAVED_W ( ushort )0x0066 +#define ASCV_WTM_FLAG_B ( ushort )0x0068 +#define ASCV_RISC_FLAG_B ( ushort )0x006A +#define ASCV_REQ_SG_LIST_QP ( ushort )0x006B + +#define ASC_HOST_FLAG_IN_ISR 0x01 +#define ASC_HOST_FLAG_ACK_INT 0x02 + +#define ASC_RISC_FLAG_GEN_INT 0x01 +#define ASC_RISC_FLAG_REQ_SG_LIST 0x02 + +#define IOP_CTRL (0x0F) +#define IOP_STATUS (0x0E) +#define IOP_INT_ACK IOP_STATUS + +#define IOP_REG_IFC (0x0D) + +#define IOP_SYN_OFFSET (0x0B) +#define IOP_REG_PC (0x0C) +#define IOP_RAM_ADDR (0x0A) +#define IOP_RAM_DATA (0x08) +#define IOP_EEP_DATA (0x06) +#define IOP_EEP_CMD (0x07) + +#define IOP_VERSION (0x03) +#define IOP_CONFIG_HIGH (0x04) +#define IOP_CONFIG_LOW (0x02) +#define IOP_ASPI_ID_LOW (0x01) +#define IOP_ASPI_ID_HIGH (0x00) + +#define IOP_REG_DC1 (0x0E) +#define IOP_REG_DC0 (0x0C) +#define IOP_REG_SB (0x0B) +#define IOP_REG_DA1 (0x0A) +#define IOP_REG_DA0 (0x08) +#define IOP_REG_SC (0x09) +#define IOP_DMA_SPEED (0x07) +#define IOP_REG_FLAG (0x07) +#define IOP_FIFO_H (0x06) +#define IOP_FIFO_L (0x04) +#define IOP_REG_ID (0x05) +#define IOP_REG_QP (0x03) +#define IOP_REG_IH (0x02) +#define IOP_REG_IX (0x01) +#define IOP_REG_AX (0x00) + +#define IFC_REG_LOCK (0x00) +#define IFC_REG_UNLOCK (0x09) + +#define IFC_WR_EN_FILTER (0x10) +#define IFC_RD_NO_EEPROM (0x10) +#define IFC_SLEW_RATE (0x20) +#define IFC_ACT_NEG (0x40) +#define IFC_INP_FILTER (0x80) + +#define IFC_INIT_DEFAULT ( IFC_ACT_NEG | IFC_REG_UNLOCK ) + +#define SC_SEL (0x80) +#define SC_BSY (0x40) +#define SC_ACK (0x20) +#define SC_REQ (0x10) +#define SC_ATN (0x08) +#define SC_IO (0x04) +#define SC_CD (0x02) +#define SC_MSG (0x01) + +#define AscGetVarFreeQHead( port ) AscReadLramWord( port, ASCV_FREE_Q_HEAD_W ) +#define AscGetVarDoneQTail( port ) AscReadLramWord( port, ASCV_DONE_Q_TAIL_W ) +#define AscPutVarFreeQHead( port, val ) AscWriteLramWord( port, ASCV_FREE_Q_HEAD_W, val ) +#define AscPutVarDoneQTail( port, val ) AscWriteLramWord( port, ASCV_DONE_Q_TAIL_W, val ) + +#define AscGetRiscVarFreeQHead( port ) AscReadLramByte( port, ASCV_NEXTRDY_B ) +#define AscGetRiscVarDoneQTail( port ) AscReadLramByte( port, ASCV_DONENEXT_B ) +#define AscPutRiscVarFreeQHead( port, val ) AscWriteLramByte( port, ASCV_NEXTRDY_B, val ) +#define AscPutRiscVarDoneQTail( port, val ) AscWriteLramByte( port, ASCV_DONENEXT_B, val ) + +#define AscGetChipIFC( port ) inp( (port)+IOP_REG_IFC ) +#define AscPutChipIFC( port, data ) outp( (port)+IOP_REG_IFC, data ) + +#define AscGetChipLramAddr( port ) ( ushort )inpw( ( PortAddr )((port)+IOP_RAM_ADDR) ) +#define AscSetChipLramAddr( port, addr ) outpw( ( PortAddr )( (port)+IOP_RAM_ADDR ), addr ) +#define AscPutChipLramData( port, data ) outpw( (port)+IOP_RAM_DATA, data ) +#define AscGetChipLramData( port ) inpw( (port)+IOP_RAM_DATA ) + +#define AscWriteChipSyn( port, data ) outp( (port)+IOP_SYN_OFFSET, data ) +#define AscReadChipSyn( port ) inp( (port)+IOP_SYN_OFFSET ) + +#define AscWriteChipIH( port, data ) outpw( (port)+IOP_REG_IH, data ) +#define AscReadChipIH( port ) inpw( (port)+IOP_REG_IH ) + +#define AscWriteChipScsiID( port, data ) outp( (port)+IOP_REG_ID, data ) +#define AscReadChipScsiID( port ) inp( (port)+IOP_REG_ID ) + +#define AscGetChipDmaSpeed( port ) ( uchar )inp( (port)+IOP_DMA_SPEED ) +#define AscSetChipDmaSpeed( port, data ) outp( (port)+IOP_DMA_SPEED, data ) +#define AscGetChipQP( port ) ( uchar )inp( (port)+IOP_REG_QP ) +#define AscSetPCAddr( port, data ) outpw( (port)+IOP_REG_PC, data ) +#define AscGetPCAddr( port ) inpw( (port)+IOP_REG_PC ) +#define AscGetChipVerNo( port ) ( uchar )inp( (port)+IOP_VERSION ) + +#define AscGetChipEEPCmd( port ) ( uchar )inp( (port)+IOP_EEP_CMD ) +#define AscSetChipEEPCmd( port, data ) outp( (port)+IOP_EEP_CMD, data ) +#define AscGetChipEEPData( port ) inpw( (port)+IOP_EEP_DATA ) +#define AscSetChipEEPData( port, data ) outpw( (port)+IOP_EEP_DATA, data ) + +#define AscGetChipControl( port ) ( uchar )inp( (port)+IOP_CTRL ) +#define AscSetChipControl( port, cc_val ) outp( (port)+IOP_CTRL, cc_val ) + +#define AscGetChipStatus( port ) ( ASC_CS_TYPE )inpw( (port)+IOP_STATUS ) +#define AscSetChipStatus( port, cs_val ) outpw( (port)+IOP_STATUS, cs_val ) + +#define AscGetChipCfgLsw( port ) ( ushort )inpw( (port)+IOP_CONFIG_LOW ) +#define AscGetChipCfgMsw( port ) ( ushort )inpw( (port)+IOP_CONFIG_HIGH ) +#define AscSetChipCfgLsw( port, data ) outpw( (port)+IOP_CONFIG_LOW, data ) +#define AscSetChipCfgMsw( port, data ) outpw( (port)+IOP_CONFIG_HIGH, data ) + +#define AscIsIntPending( port ) ( AscGetChipStatus( port ) & CSW_INT_PENDING ) +#define AscGetChipScsiID( port ) ( ( AscGetChipCfgLsw( port ) >> 8 ) & ASC_MAX_TID ) + +#define ASC_HALT_EXTMSG_IN ( ushort )0x8000 +#define ASC_HALT_CHK_CONDITION ( ushort )0x8100 +#define ASC_HALT_SS_QUEUE_FULL ( ushort )0x8200 +#define ASC_HALT_SDTR_REJECTED ( ushort )0x4000 + +#define ASC_MAX_QNO 0xF8 +#define ASC_DATA_SEC_BEG ( ushort )0x0080 +#define ASC_DATA_SEC_END ( ushort )0x0080 +#define ASC_CODE_SEC_BEG ( ushort )0x0080 +#define ASC_CODE_SEC_END ( ushort )0x0080 +#define ASC_QADR_BEG (0x4000) +#define ASC_QADR_USED ( ushort )( ASC_MAX_QNO * 64 ) +#define ASC_QADR_END ( ushort )0x7FFF +#define ASC_QLAST_ADR ( ushort )0x7FC0 +#define ASC_QBLK_SIZE 0x40 +#define ASC_BIOS_DATA_QBEG 0xF8 + +#define ASC_MIN_ACTIVE_QNO 0x01 + +#define ASC_QLINK_END 0xFF +#define ASC_EEPROM_WORDS 0x10 +#define ASC_MAX_MGS_LEN 0x10 + +#define ASC_BIOS_ADDR_DEF 0xDC00 +#define ASC_BIOS_SIZE 0x3800 +#define ASC_BIOS_RAM_OFF 0x3800 +#define ASC_BIOS_RAM_SIZE 0x800 +#define ASC_BIOS_MIN_ADDR 0xC000 +#define ASC_BIOS_MAX_ADDR 0xEC00 +#define ASC_BIOS_BANK_SIZE 0x0400 + +#define ASC_MCODE_START_ADDR 0x0080 + +#define ASC_CFG0_HOST_INT_ON 0x0020 +#define ASC_CFG0_BIOS_ON 0x0040 +#define ASC_CFG0_VERA_BURST_ON 0x0080 +#define ASC_CFG0_SCSI_PARITY_ON 0x0800 + +#define ASC_CFG1_SCSI_TARGET_ON 0x0080 +#define ASC_CFG1_LRAM_8BITS_ON 0x0800 + +#define ASC_CFG_MSW_CLR_MASK 0xF0C0 + +#define CSW_TEST1 ( ASC_CS_TYPE )0x8000 +#define CSW_AUTO_CONFIG ( ASC_CS_TYPE )0x4000 +#define CSW_RESERVED1 ( ASC_CS_TYPE )0x2000 +#define CSW_IRQ_WRITTEN ( ASC_CS_TYPE )0x1000 +#define CSW_33MHZ_SELECTED ( ASC_CS_TYPE )0x0800 +#define CSW_TEST2 ( ASC_CS_TYPE )0x0400 +#define CSW_TEST3 ( ASC_CS_TYPE )0x0200 +#define CSW_RESERVED2 ( ASC_CS_TYPE )0x0100 +#define CSW_DMA_DONE ( ASC_CS_TYPE )0x0080 +#define CSW_FIFO_RDY ( ASC_CS_TYPE )0x0040 + +#define CSW_EEP_READ_DONE ( ASC_CS_TYPE )0x0020 + +#define CSW_HALTED ( ASC_CS_TYPE )0x0010 +#define CSW_SCSI_RESET_ACTIVE ( ASC_CS_TYPE )0x0008 + +#define CSW_PARITY_ERR ( ASC_CS_TYPE )0x0004 +#define CSW_SCSI_RESET_LATCH ( ASC_CS_TYPE )0x0002 + +#define CSW_INT_PENDING ( ASC_CS_TYPE )0x0001 + +#define CIW_INT_ACK ( ASC_CS_TYPE )0x0100 +#define CIW_TEST1 ( ASC_CS_TYPE )0x0200 +#define CIW_TEST2 ( ASC_CS_TYPE )0x0400 +#define CIW_SEL_33MHZ ( ASC_CS_TYPE )0x0800 + +#define CIW_IRQ_ACT ( ASC_CS_TYPE )0x1000 + +#define CC_CHIP_RESET ( uchar )0x80 +#define CC_SCSI_RESET ( uchar )0x40 +#define CC_HALT ( uchar )0x20 +#define CC_SINGLE_STEP ( uchar )0x10 +#define CC_DMA_ABLE ( uchar )0x08 +#define CC_TEST ( uchar )0x04 +#define CC_BANK_ONE ( uchar )0x02 +#define CC_DIAG ( uchar )0x01 + +#define ASC_1000_ID0W 0x04C1 +#define ASC_1000_ID0W_FIX 0x00C1 +#define ASC_1000_ID1B 0x25 + +#define ASC_EISA_BIG_IOP_GAP (0x1C30-0x0C50) +#define ASC_EISA_SMALL_IOP_GAP (0x0020) +#define ASC_EISA_MIN_IOP_ADDR (0x0C30) +#define ASC_EISA_MAX_IOP_ADDR (0xFC50) +#define ASC_EISA_REV_IOP_MASK (0x0C83) +#define ASC_EISA_PID_IOP_MASK (0x0C80) +#define ASC_EISA_CFG_IOP_MASK (0x0C86) + +#define ASC_GET_EISA_SLOT( iop ) ( PortAddr )( (iop) & 0xF000 ) + +#define ASC_EISA_ID_740 0x01745004UL +#define ASC_EISA_ID_750 0x01755004UL + +#define INS_HALTINT ( ushort )0x6281 +#define INS_HALT ( ushort )0x6280 +#define INS_SINT ( ushort )0x6200 +#define INS_RFLAG_WTM ( ushort )0x7380 + +#define ASC_MC_SAVE_CODE_WSIZE 0x500 +#define ASC_MC_SAVE_DATA_WSIZE 0x40 + +typedef struct asc_mc_saved { + ushort data[ASC_MC_SAVE_DATA_WSIZE]; + ushort code[ASC_MC_SAVE_CODE_WSIZE]; +} ASC_MC_SAVED; + +int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg); +int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg); +void AscWaitEEPRead(void); +void AscWaitEEPWrite(void); +ushort AscReadEEPWord(PortAddr, uchar); +ushort AscWriteEEPWord(PortAddr, uchar, ushort); +ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG dosfar *, ushort); +int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG dosfar *, ushort); +int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG dosfar *, ushort); +ushort AscEEPSum(PortAddr, uchar, uchar); + +int AscStartChip(PortAddr); +int AscStopChip(PortAddr); +void AscSetChipIH(PortAddr, ushort); +int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar); + +int AscIsChipHalted(PortAddr); + +void AscSetChipCfgDword(PortAddr, ulong); +ulong AscGetChipCfgDword(PortAddr); + +void AscAckInterrupt(PortAddr); +void AscDisableInterrupt(PortAddr); +void AscEnableInterrupt(PortAddr); +void AscSetBank(PortAddr, uchar); +uchar AscGetBank(PortAddr); +int AscResetChipAndScsiBus(PortAddr); +ushort AscGetIsaDmaChannel(PortAddr); +ushort AscSetIsaDmaChannel(PortAddr, ushort); +uchar AscSetIsaDmaSpeed(PortAddr, uchar); +uchar AscGetIsaDmaSpeed(PortAddr); + +uchar AscReadLramByte(PortAddr, ushort); +ushort AscReadLramWord(PortAddr, ushort); +ulong AscReadLramDWord(PortAddr, ushort); +void AscWriteLramWord(PortAddr, ushort, ushort); +void AscWriteLramDWord(PortAddr, ushort, ulong); +void AscWriteLramByte(PortAddr, ushort, uchar); +int AscVerWriteLramDWord(PortAddr, ushort, ulong); +int AscVerWriteLramWord(PortAddr, ushort, ushort); +int AscVerWriteLramByte(PortAddr, ushort, uchar); + +ulong AscMemSumLramWord(PortAddr, ushort, int); +void AscMemWordSetLram(PortAddr, ushort, ushort, int); +void AscMemWordCopyToLram(PortAddr, ushort, ushort dosfar *, int); +void AscMemDWordCopyToLram(PortAddr, ushort, ulong dosfar *, int); +void AscMemWordCopyFromLram(PortAddr, ushort, ushort dosfar *, int); +int AscMemWordCmpToLram(PortAddr, ushort, ushort dosfar *, int); + +ushort AscInitAscDvcVar(ASC_DVC_VAR asc_ptr_type *); +ulong AscLoadMicroCode(PortAddr, ushort, + ushort dosfar *, ushort); +ushort AscInitFromEEP(ASC_DVC_VAR asc_ptr_type *); +ushort AscInitFromAscDvcVar(ASC_DVC_VAR asc_ptr_type *); +ushort AscInitMicroCodeVar(ASC_DVC_VAR asc_ptr_type * asc_dvc); + +void dosfar AscInitPollIsrCallBack(ASC_DVC_VAR asc_ptr_type *, + ASC_QDONE_INFO dosfar *); +int AscTestExternalLram(ASC_DVC_VAR asc_ptr_type *); +ushort AscTestLramEndian(PortAddr); + +uchar AscMsgOutSDTR(PortAddr, uchar, uchar); + +uchar AscCalSDTRData(uchar, uchar); +void AscSetChipSDTR(PortAddr, uchar, uchar); +int AscInitChipAllSynReg(ASC_DVC_VAR asc_ptr_type *, uchar); +uchar AscGetSynPeriodIndex(uchar); +uchar AscSynIndexToPeriod(uchar); +uchar AscAllocFreeQueue(PortAddr, uchar); +uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar); +int AscRiscHaltedAbortSRB(ASC_DVC_VAR asc_ptr_type *, ulong); +int AscRiscHaltedAbortTIX(ASC_DVC_VAR asc_ptr_type *, uchar); +int AscRiscHaltedAbortALL(ASC_DVC_VAR asc_ptr_type *); +int AscHostReqRiscHalt(PortAddr); +int AscStopQueueExe(PortAddr); +int AscStartQueueExe(PortAddr); +int AscCleanUpDiscQueue(PortAddr); +int AscCleanUpBusyQueue(PortAddr); +int _AscAbortTidBusyQueue(ASC_DVC_VAR asc_ptr_type *, + ASC_QDONE_INFO dosfar *, uchar); +int _AscAbortSrbBusyQueue(ASC_DVC_VAR asc_ptr_type *, + ASC_QDONE_INFO dosfar *, ulong); +int AscWaitTixISRDone(ASC_DVC_VAR asc_ptr_type *, uchar); +int AscWaitISRDone(ASC_DVC_VAR asc_ptr_type *); +ulong AscGetOnePhyAddr(ASC_DVC_VAR asc_ptr_type *, uchar dosfar *, ulong); + +int AscSendScsiQueue(ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_Q dosfar * scsiq, + uchar n_q_required); +int AscPutReadyQueue(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *, uchar); +int AscPutReadySgListQueue(ASC_DVC_VAR asc_ptr_type *, + ASC_SCSI_Q dosfar *, uchar); +int AscAbortScsiIO(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *); +void AscExeScsiIO(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *); +int AscSetChipSynRegAtID(PortAddr, uchar, uchar); +int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar); +ushort AscInitLram(ASC_DVC_VAR asc_ptr_type *); +int AscReInitLram(ASC_DVC_VAR asc_ptr_type *); +ushort AscInitQLinkVar(ASC_DVC_VAR asc_ptr_type *); +int AscSetLibErrorCode(ASC_DVC_VAR asc_ptr_type *, ushort); +int _AscWaitQDone(PortAddr, ASC_SCSI_Q dosfar *); + +int AscEnterCritical(void); +void AscLeaveCritical(int); + +int AscIsrChipHalted(ASC_DVC_VAR asc_ptr_type *); +uchar _AscCopyLramScsiDoneQ(PortAddr, ushort, + ASC_QDONE_INFO dosfar *, ulong); +int AscIsrQDone(ASC_DVC_VAR asc_ptr_type *); +ushort AscIsrExeBusyQueue(ASC_DVC_VAR asc_ptr_type *, uchar); +int AscScsiSetupCmdQ(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *, + uchar dosfar *, ulong); + +int AscScsiInquiry(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *, + uchar dosfar *, int); +int AscScsiTestUnitReady(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *); +int AscScsiStartStopUnit(ASC_DVC_VAR asc_ptr_type *, + ASC_SCSI_REQ_Q dosfar *, uchar); +int AscScsiReadCapacity(ASC_DVC_VAR asc_ptr_type *, + ASC_SCSI_REQ_Q dosfar *, + uchar dosfar *); + +ulong dosfar *swapfarbuf4(uchar dosfar *); +int PollQueueDone(ASC_DVC_VAR asc_ptr_type *, + ASC_SCSI_REQ_Q dosfar *, + int); +int PollScsiReadCapacity(ASC_DVC_VAR asc_ptr_type *, + ASC_SCSI_REQ_Q dosfar *, + ASC_CAP_INFO dosfar *); +int PollScsiInquiry(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *, + uchar dosfar *, int); +int PollScsiTestUnitReady(ASC_DVC_VAR asc_ptr_type *, + ASC_SCSI_REQ_Q dosfar *); +int PollScsiStartUnit(ASC_DVC_VAR asc_ptr_type *, + ASC_SCSI_REQ_Q dosfar *); +int InitTestUnitReady(ASC_DVC_VAR asc_ptr_type *, + ASC_SCSI_REQ_Q dosfar *); +void AscDispInquiry(uchar, uchar, ASC_SCSI_INQUIRY dosfar *); +int AscPollQDone(ASC_DVC_VAR asc_ptr_type *, + ASC_SCSI_REQ_Q dosfar *, int); + +int AscSetBIOSBank(PortAddr, int, ushort); +int AscSetVlBIOSBank(PortAddr, int); +int AscSetEisaBIOSBank(PortAddr, int); +int AscSetIsaBIOSBank(PortAddr, int); + +int AscIsBiosEnabled(PortAddr, ushort); +void AscResetScsiBus(PortAddr); +void AscClrResetScsiBus(PortAddr); + +void AscSingleStepChip(PortAddr); +uchar AscSetChipScsiID(PortAddr, uchar); +ushort AscGetChipBiosAddress(PortAddr, ushort); +ushort AscSetChipBiosAddress(PortAddr, ushort, ushort); +uchar AscGetChipVersion(PortAddr, ushort); +ushort AscGetChipBusType(PortAddr); + +PortAddr AscSearchIOPortAddr11(PortAddr); +PortAddr AscSearchIOPortAddr100(PortAddr); +int AscFindSignature(PortAddr); +void AscToggleIRQAct(PortAddr); +int AscResetChip(PortAddr); +void AscClrResetChip(PortAddr); + +short itos(ushort, uchar dosfar *, short, short); +int insnchar(uchar dosfar *, short, short, ruchar, short); +void itoh(ushort, ruchar dosfar *); +void btoh(uchar, ruchar dosfar *); +void ltoh(ulong, ruchar dosfar *); +uchar dosfar *todstr(ushort, uchar dosfar *); +uchar dosfar *tohstr(ushort, uchar dosfar *); +uchar dosfar *tobhstr(uchar, uchar dosfar *); +uchar dosfar *tolhstr(ulong, uchar dosfar *); + +void AscSetISAPNPWaitForKey(void); +uchar AscGetChipIRQ(PortAddr, ushort); +uchar AscSetChipIRQ(PortAddr, uchar, ushort); +uchar AscGetChipScsiCtrl(PortAddr); + +ushort AscGetEisaChipCfg(PortAddr); +ushort AscGetEisaChipGpReg(PortAddr); +ushort AscSetEisaChipCfg(PortAddr, ushort); +ushort AscSetEisaChipGpReg(PortAddr, ushort); + +ulong AscGetEisaProductID(PortAddr); +PortAddr AscSearchIOPortAddrEISA(PortAddr); + +int AscPollQTailSync(PortAddr); +int AscPollQHeadSync(PortAddr); +int AscWaitQTailSync(PortAddr); + +int _AscRestoreMicroCode(PortAddr, ASC_MC_SAVED dosfar *); + +int AscSCAM(ASC_DVC_VAR asc_ptr_type *); + +ushort SwapByteOfWord(ushort word_val); +ulong SwapWordOfDWord(ulong dword_val); +ulong AdjEndianDword(ulong dword_val); + +int AscAdjEndianScsiQ(ASC_SCSI_Q dosfar *); +int AscAdjEndianQDoneInfo(ASC_QDONE_INFO dosfar *); + +extern int DvcEnterCritical(void); +extern void DvcLeaveCritical(int); + +extern void DvcInPortWords(PortAddr, ushort dosfar *, int); +extern void DvcOutPortWords(PortAddr, ushort dosfar *, int); +extern void DvcOutPortDWords(PortAddr, ulong dosfar *, int); + +extern void DvcSleepMilliSecond(ulong); +extern void DvcDisplayString(uchar dosfar *); +extern ulong DvcGetPhyAddr(uchar dosfar * buf_addr, ulong buf_len); +extern ulong DvcGetSGList(ASC_DVC_VAR asc_ptr_type *, uchar dosfar *, ulong, + ASC_SG_HEAD dosfar *); + +extern void DvcSCAMDelayMS(ulong); +extern int DvcDisableCPUInterrupt(void); +extern void DvcRestoreCPUInterrupt(int); + +void DvcPutScsiQ(PortAddr, ushort, ushort dosfar *, int); +void DvcGetQinfo(PortAddr, ushort, ushort dosfar *, int); + +PortAddr AscSearchIOPortAddr(PortAddr, ushort); +ushort AscInitGetConfig(ASC_DVC_VAR asc_ptr_type *); +ushort AscInitSetConfig(ASC_DVC_VAR asc_ptr_type *); +ushort AscInitAsc1000Driver(ASC_DVC_VAR asc_ptr_type *); +int AscInitScsiTarget(ASC_DVC_VAR asc_ptr_type *, + ASC_DVC_INQ_INFO dosfar *, + uchar dosfar *, + ASC_CAP_INFO_ARRAY dosfar *, + ushort); +int AscInitPollBegin(ASC_DVC_VAR asc_ptr_type *); +int AscInitPollEnd(ASC_DVC_VAR asc_ptr_type *); +int AscInitPollTarget(ASC_DVC_VAR asc_ptr_type *, + ASC_SCSI_REQ_Q dosfar *, + ASC_SCSI_INQUIRY dosfar *, + ASC_CAP_INFO dosfar *); +int AscExeScsiQueue(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *); + +int AscISR(ASC_DVC_VAR asc_ptr_type *); +void AscISR_AckInterrupt(ASC_DVC_VAR asc_ptr_type *); +int AscISR_CheckQDone(ASC_DVC_VAR asc_ptr_type *, + ASC_QDONE_INFO dosfar *, + uchar dosfar *); + +int AscStartUnit(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_TIX_TYPE); +int AscStopUnit( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_TIX_TYPE target_ix +); + +uint AscGetNumOfFreeQueue(ASC_DVC_VAR asc_ptr_type *, uchar, uchar); +int AscSgListToQueue(int); +int AscQueueToSgList(int); +int AscSetDvcErrorCode(ASC_DVC_VAR asc_ptr_type *, uchar); + +int AscAbortSRB(ASC_DVC_VAR asc_ptr_type *, ulong); +int AscResetDevice(ASC_DVC_VAR asc_ptr_type *, uchar); +int AscResetSB(ASC_DVC_VAR asc_ptr_type *); + +void AscEnableIsaDma(uchar); +void AscDisableIsaDma(uchar); + +ulong AscGetMaxDmaAddress(ushort); +ulong AscGetMaxDmaCount(ushort); + +int AscSaveMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SAVED dosfar *); +int AscRestoreOldMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SAVED dosfar *); +int AscRestoreNewMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SAVED dosfar *); + +/* + * --- Debugging Header + */ + +#ifdef ADVANSYS_DEBUG +#define STATIC +#else /* ADVANSYS_DEBUG */ +#define STATIC static +#endif /* ADVANSYS_DEBUG */ + + +/* + * --- Driver Constants and Macros + */ + +#define ASC_NUM_BOARD_SUPPORTED 4 +#define ASC_NUM_BUS 4 + +/* Reference Scsi_Host hostdata */ +#define ASC_BOARD(host) ((struct asc_board *) &(host)->hostdata) + +#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */ + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif /* min */ + +/* Asc Library return codes */ +#define ASC_TRUE 1 +#define ASC_FALSE 0 +#define ASC_NOERROR 1 +#define ASC_BUSY 0 +#define ASC_ERROR (-1) + +/* Scsi_Cmnd function return codes */ +#define STATUS_BYTE(byte) (byte) +#define MSG_BYTE(byte) ((byte) << 8) +#define HOST_BYTE(byte) ((byte) << 16) +#define DRIVER_BYTE(byte) ((byte) << 24) + +/* asc_enqueue() flags */ +#define ASC_FRONT 1 +#define ASC_BACK 2 + +/* PCI configuration declarations */ + +#define ASC_PCI_REV_A_INIT 0x01 +#define ASC_PCI_REV_A_DONE 0x02 +#define ASC_PCI_REV_B_INIT 0x04 +#define ASC_PCI_REV_B_DONE 0x08 + +#define PCI_BASE_CLASS_PREDEFINED 0x00 +#define PCI_BASE_CLASS_MASS_STORAGE 0x01 +#define PCI_BASE_CLASS_NETWORK 0x02 +#define PCI_BASE_CLASS_DISPLAY 0x03 +#define PCI_BASE_CLASS_MULTIMEDIA 0x04 +#define PCI_BASE_CLASS_MEMORY_CONTROLLER 0x05 +#define PCI_BASE_CLASS_BRIDGE_DEVICE 0x06 + +/* MASS STORAGE */ +#define PCI_SUB_CLASS_SCSI_CONTROLLER 0x00 +#define PCI_SUB_CLASS_IDE_CONTROLLER 0x01 +#define PCI_SUB_CLASS_FLOPPY_DISK_CONTROLLER 0x02 +#define PCI_SUB_CLASS_IPI_BUS_CONTROLLER 0x03 +#define PCI_SUB_CLASS_OTHER_MASS_CONTROLLER 0x80 + +/* NETWORK CONTROLLER */ +#define PCI_SUB_CLASS_ETHERNET_CONTROLLER 0x00 +#define PCI_SUB_CLASS_TOKEN_RING_CONTROLLER 0x01 +#define PCI_SUB_CLASS_FDDI_CONTROLLER 0x02 +#define PCI_SUB_CLASS_OTHER_NETWORK_CONTROLLER 0x80 + +/* DISPLAY CONTROLLER */ +#define PCI_SUB_CLASS_VGA_CONTROLLER 0x00 +#define PCI_SUB_CLASS_XGA_CONTROLLER 0x01 +#define PCI_SUB_CLASS_OTHER_DISPLAY_CONTROLLER 0x80 + +/* MULTIMEDIA CONTROLLER */ +#define PCI_SUB_CLASS_VIDEO_DEVICE 0x00 +#define PCI_SUB_CLASS_AUDIO_DEVICE 0x01 +#define PCI_SUB_CLASS_OTHER_MULTIMEDIA_DEVICE 0x80 + +/* MEMORY CONTROLLER */ +#define PCI_SUB_CLASS_RAM_CONTROLLER 0x00 +#define PCI_SUB_CLASS_FLASH_CONTROLLER 0x01 +#define PCI_SUB_CLASS_OTHER_MEMORY_CONTROLLER 0x80 + +/* BRIDGE CONTROLLER */ +#define PCI_SUB_CLASS_HOST_BRIDGE_CONTROLLER 0x00 +#define PCI_SUB_CLASS_ISA_BRIDGE_CONTROLLER 0x01 +#define PCI_SUB_CLASS_EISA_BRIDGE_CONTROLLER 0x02 +#define PCI_SUB_CLASS_MC_BRIDGE_CONTROLLER 0x03 +#define PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER 0x04 +#define PCI_SUB_CLASS_PCMCIA_BRIDGE_CONTROLLER 0x05 +#define PCI_SUB_CLASS_OTHER_BRIDGE_CONTROLLER 0x80 + +#define PCI_MAX_SLOT 0x1F +#define PCI_MAX_BUS 0xFF +#define ASC_PCI_VENDORID 0x10CD +#define PCI_IOADDRESS_MASK 0xFFFE + +/* PCI IO Port Addresses to generate special cycle */ + +#define PCI_CONFIG_ADDRESS_MECH1 0x0CF8 +#define PCI_CONFIG_DATA_MECH1 0x0CFC + +#define PCI_CONFIG_FORWARD_REGISTER 0x0CFA /* 0=type 0; 1=type 1; */ + +#define PCI_CONFIG_BUS_NUMBER_MASK 0x00FF0000 +#define PCI_CONFIG_DEVICE_FUNCTION_MASK 0x0000FF00 +#define PCI_CONFIG_REGISTER_NUMBER_MASK 0x000000F8 + +#define PCI_DEVICE_FOUND 0x0000 +#define PCI_DEVICE_NOT_FOUND 0xffff + +#define SUBCLASS_OFFSET 0x0A +#define CLASSCODE_OFFSET 0x0B +#define VENDORID_OFFSET 0x00 +#define DEVICEID_OFFSET 0x02 + +/* + * --- Driver Macros + */ + +#ifndef ADVANSYS_STATS +#define ASC_STATS(counter) +#define ASC_STATS_ADD(counter, count) +#else /* ADVANSYS_STATS */ +#define ASC_STATS(counter) asc_stats.counter++ +#define ASC_STATS_ADD(counter, count) asc_stats.counter += (count) +#endif /* ADVANSYS_STATS */ + +#ifndef ADVANSYS_DEBUG + +#define ASC_DBG(lvl, s) +#define ASC_DBG1(lvl, s, a1) +#define ASC_DBG2(lvl, s, a1, a2) +#define ASC_DBG3(lvl, s, a1, a2, a3) +#define ASC_DBG4(lvl, s, a1, a2, a3, a4) +#define ASC_DBG_PRT_SCSI_HOST(lvl, s) +#define ASC_DBG_PRT_DVC_VAR(lvl, v) +#define ASC_DBG_PRT_DVC_CFG(lvl, c) +#define ASC_DBG_PRT_SCSI_Q(lvl, scsiqp) +#define ASC_DBG_PRT_QDONE_INFO(lvl, qdone) +#define ASC_DBG_PRT_HEX(lvl, name, start, length) +#define ASC_DBG_PRT_CDB(lvl, cdb, len) +#define ASC_DBG_PRT_SENSE(lvl, sense, len) +#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) +#define ASC_ASSERT(a) + +#else /* ADVANSYS_DEBUG */ + +/* + * Debugging Message Levels: + * 0: Errors Only + * 1: High-Level Tracing + * 2-N: Verbose Tracing + */ + +#define ASC_DBG(lvl, s) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + printk(s); \ + } \ + } + +#define ASC_DBG1(lvl, s, a1) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + printk((s), (a1)); \ + } \ + } + +#define ASC_DBG2(lvl, s, a1, a2) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + printk((s), (a1), (a2)); \ + } \ + } + +#define ASC_DBG3(lvl, s, a1, a2, a3) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + printk((s), (a1), (a2), (a3)); \ + } \ + } + +#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + printk((s), (a1), (a2), (a3), (a4)); \ + } \ + } + +#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + asc_prt_scsi_host(s); \ + } \ + } + +#define ASC_DBG_PRT_DVC_VAR(lvl, v) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + asc_prt_dvc_var(v); \ + } \ + } + +#define ASC_DBG_PRT_DVC_CFG(lvl, c) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + asc_prt_dvc_cfg(c); \ + } \ + } + +#define ASC_DBG_PRT_SCSI_Q(lvl, scsiqp) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + asc_prt_scsi_q(scsiqp); \ + } \ + } + +#define ASC_DBG_PRT_QDONE_INFO(lvl, qdone) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + asc_prt_qdone_info(qdone); \ + } \ + } + +#define ASC_DBG_PRT_HEX(lvl, name, start, length) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + asc_prt_hex((name), (start), (length)); \ + } \ + } + +#define ASC_DBG_PRT_CDB(lvl, cdb, len) \ + ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len)); + +#define ASC_DBG_PRT_SENSE(lvl, sense, len) \ + ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len)); + +#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \ + ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len)); + +#define ASC_ASSERT(a) \ + { \ + if (!(a)) { \ + printk("ASC_ASSERT() Failure: file %s, line %d\n", \ + __FILE__, __LINE__); \ + } \ + } +#endif /* ADVANSYS_DEBUG */ + + +/* + * --- Driver Structures + */ + +/* + * Structure allocated for each board. + * + * This structure is allocated by scsi_register() at the end + * of the 'Scsi_Host' structure starting at the 'hostdata' + * field. It is guaranteed to be allocated from DMA-able memory. + */ +struct asc_board { + /* Asc Library */ + ASC_DVC_VAR board; /* Board configuration */ + ASC_DVC_CFG cfg; /* Device configuration */ + uchar overrun_buf[ASC_OVERRUN_BSIZE]; + /* Queued Commands */ + ASC_SCSI_BIT_ID_TYPE pending_tidmask; /* Pending command mask */ + Scsi_Cmnd *pending[ASC_MAX_TID]; + /* Target Initialization */ + ASC_SCSI_BIT_ID_TYPE init_tidmask; /* Target initialized mask */ + ASC_SCSI_REQ_Q scsireqq; + ASC_CAP_INFO cap_info; + ASC_SCSI_INQUIRY inquiry; +}; + +/* + * PCI configuration structures + */ +typedef struct _PCI_DATA_ +{ + uchar type; + uchar bus; + uchar slot; + uchar func; + uchar offset; +} PCI_DATA; + +typedef struct _PCI_DEVICE_ +{ + ushort vendorID; + ushort deviceID; + ushort slotNumber; + ushort slotFound; + uchar busNumber; + uchar maxBusNumber; + uchar devFunc; + ushort startSlot; + ushort endSlot; + uchar bridge; + uchar type; +} PCI_DEVICE; + +typedef struct _PCI_CONFIG_SPACE_ +{ + ushort vendorID; + ushort deviceID; + ushort command; + ushort status; + uchar revision; + uchar classCode[3]; + uchar cacheSize; + uchar latencyTimer; + uchar headerType; + uchar bist; + ulong baseAddress[6]; + ushort reserved[4]; + ulong optionRomAddr; + ushort reserved2[4]; + uchar irqLine; + uchar irqPin; + uchar minGnt; + uchar maxLatency; +} PCI_CONFIG_SPACE; + +#ifdef ADVANSYS_STATS +struct asc_stats { + ulong command; /* # calls to advansys_command() */ + ulong queuecommand; /* # calls to advansys_queuecommand() */ + ulong abort; /* # calls to advansys_abort() */ + ulong reset; /* # calls to advansys_reset() */ + ulong biosparam; /* # calls to advansys_biosparam() */ + ulong interrupt; /* # calls to advansys_interrupt() */ + ulong callback; /* # calls asc_isr_callback() */ + ulong cont_cnt; /* # non-scatter-gather I/O requests received */ + ulong cont_xfer; /* contiguous transfer total (512 byte units) */ + ulong sg_cnt; /* # scatter-gather I/O requests received */ + ulong sg_elem; /* scatter-gather element total */ + ulong sg_xfer; /* scatter-gather tranfer total (512 byte units) */ + ulong error; /* # AscExeScsiQueue() ASC_ERROR returns. */ + /* + * Number of times interrupts disabled in advansys_queuecommand() and + * asc_isr_callback(), respectively. For the former indicates how many + * times commands were pending when a new command was received. + */ + ulong cmd_disable; + ulong intr_disable; + /* + * Number of times asc_enqueue() called. Indicates how many ASC_BUSY + * returns have occurred. + */ + ulong enqueue; + ulong dequeue; /* # calls to asc_dequeue(). */ + /* + * Number of times asc_rmqueue() called and the specified command + * was found and removed. + */ + ulong rmqueue; +} asc_stats; +#endif /* ADVANSYS_STATS */ + + +/* + * --- Driver Data + */ + +#ifdef LINUX_1_3 +struct proc_dir_entry proc_scsi_advansys = +{ + PROC_SCSI_ADVANSYS, /* unsigned short low_ino */ + 8, /* unsigned short namelen */ + "advansys", /* const char *name */ + S_IFDIR | S_IRUGO | S_IXUGO, /* mode_t mode */ + 2 /* nlink_t nlink */ +}; +#endif /* LINUX_1_3 */ + +STATIC int asc_board_count; /* Number of boards detected in system. */ +STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED]; +STATIC Scsi_Cmnd *asc_scsi_done; /* Commands needing done function call. */ + +STATIC ushort asc_bus[ASC_NUM_BUS] = { + ASC_IS_ISA, + ASC_IS_VL, + ASC_IS_EISA, + ASC_IS_PCI, +}; + +/* + * Used with the LILO 'advansys' option to eliminate or + * limit I/O port probing at boot time, cf. advansys_setup(). + */ +int asc_iopflag = ASC_FALSE; +int asc_ioport[ASC_NUM_BOARD_SUPPORTED] = { 0, 0, 0, 0 }; + +#ifdef ADVANSYS_DEBUG +char * +asc_bus_name[ASC_NUM_BUS] = { + "ASC_IS_ISA", + "ASC_IS_VL", + "ASC_IS_EISA", + "ASC_IS_PCI", +}; + +int asc_dbglvl = 0; +#endif /* ADVANSYS_DEBUG */ + + +/* + * --- Driver Function Prototypes + * + * advansys.h contains function prototypes for functions global to Linux. + */ + +#ifdef LINUX_1_3 +STATIC int asc_proc_copy(off_t, off_t, char *, int , char *, int); +#endif /* LINUX_1_3 */ +STATIC void advansys_interrupt(int, struct pt_regs *); +STATIC void advansys_command_done(Scsi_Cmnd *); +STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *); +STATIC void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *); +STATIC void asc_execute_pending(struct Scsi_Host *); +STATIC int asc_init_dev(ASC_DVC_VAR *, Scsi_Cmnd *); +STATIC int asc_srch_pci_dev(PCI_DEVICE *); +STATIC uchar asc_scan_method(PCI_DEVICE *); +STATIC int asc_pci_find_dev(PCI_DEVICE *); +STATIC void asc_get_pci_cfg(PCI_DEVICE *, PCI_CONFIG_SPACE *); +STATIC ushort asc_get_cfg_word(PCI_DATA *); +STATIC uchar asc_get_cfg_byte(PCI_DATA *); +STATIC void asc_enqueue(struct Scsi_Host *, Scsi_Cmnd *, int, int); +STATIC Scsi_Cmnd *asc_dequeue(struct Scsi_Host *, int); +STATIC int asc_rmqueue(struct Scsi_Host *, Scsi_Cmnd *, int); + +/* XXX - Asc Library Routines not supposed to be used directly */ +ushort AscGetChipBiosAddress(PortAddr, ushort); +int AscFindSignature(PortAddr); + +#ifdef ADVANSYS_STATS +STATIC int asc_prt_stats(char *, int); +STATIC int asc_prt_stats_line(char *, int, char *fmt, ...); +#endif /* ADVANSYS_STATS */ +#ifdef ADVANSYS_DEBUG +STATIC void asc_prt_scsi_host(struct Scsi_Host *); +STATIC void asc_prt_dvc_cfg(ASC_DVC_CFG *); +STATIC void asc_prt_dvc_var(ASC_DVC_VAR *); +STATIC void asc_prt_scsi_q(ASC_SCSI_Q *); +STATIC void asc_prt_qdone_info(ASC_QDONE_INFO *); +STATIC void asc_prt_hex(char *f, uchar *, int); +STATIC int interrupts_enabled(void); +#endif /* ADVANSYS_DEBUG */ + + +/* + * --- Linux 'Scsi_Host_Template' and advansys_setup() Functions + */ + +#ifdef LINUX_1_3 +/* + * advansys_proc_info() - /proc/scsi/advansys/[0-ASC_NUM_BOARD_SUPPORTED] + * + * *buffer: I/O buffer + * **start: if inout == FALSE pointer into buffer where user read should start + * offset: current offset into /proc/scsi/advansys file + * length: length of buffer + * hostno: Scsi_Host host_no + * inout: TRUE - user is writing; FALSE - user is reading + * + * Return the number of bytes read from or written to + * /proc/scsi/advansys file. + */ +int +advansys_proc_info(char *buffer, char **start, off_t offset, int length, + int hostno, int inout) +{ + struct Scsi_Host *shp; + int i; + char *cp; + int cplen; + int cnt; + int totcnt; + int leftlen; + char *curbuf; + off_t advoffset; + Scsi_Device *scd; + char prtbuf[480]; /* 6 lines */ + + ASC_DBG(1, "advansys_proc_info: begin\n"); + + /* + * User write not supported. + */ + if (inout == TRUE) { + return(-ENOSYS); + } + + /* + * User read of /proc/scsi/advansys file. + */ + + /* Find the specified board. */ + for (i = 0; i < asc_board_count; i++) { + if (asc_host[i]->host_no == hostno) { + break; + } + } + if (i == asc_board_count) { + return(-ENOENT); + } + shp = asc_host[i]; + + /* Always copy read data to the beginning of the buffer. */ + *start = buffer; + + curbuf = buffer; + advoffset = 0; + totcnt = 0; + leftlen = length; + + /* Get board information. */ + cp = (char *) advansys_info(shp); + strcat(cp, "\n"); + cplen = strlen(cp); + + /* Copy board information. */ + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; + + /* + * Get and copy information for each device attached to the board. + */ + cp = &prtbuf[0]; + sprintf(cp, "\nDevices attached to SCSI Host %d:\n", shp->host_no); + cplen = strlen(cp); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; + + cp = &prtbuf[0]; + for (scd = scsi_devices; scd; scd = scd->next) { + if (scd->host == shp) { + proc_print_scsidevice(scd, cp, &cplen, 0); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; + } + } + +#ifdef ADVANSYS_STATS + /* + * prtbuf[] has about 6 lines worth of space. If the statistics ever + * get longer than 6 lines, prtbuf[] should be increased in size. If + * prtbuf[] is too small it will not be overwritten. Instead the user + * just won't get all of the available statistics. + */ + cp = &prtbuf[0]; + cplen = asc_prt_stats(cp, sizeof(prtbuf)); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; +#endif /* ADVANSYS_STATS */ + + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); + + return totcnt; +} +#endif /* LINUX_1_3 */ + + +/* + * advansys_detect() + * + * Detect function for AdvanSys adapters. + * + * Argument is a pointer to the host driver's scsi_hosts entry. + * + * Return number of adapters found. + * + * Note: Because this function is called during system initialization + * it must not call SCSI mid-level functions including scsi_malloc() + * and scsi_free(). + */ +int +advansys_detect(Scsi_Host_Template *tpnt) +{ + static int detect_called = ASC_FALSE; + int iop; + int bus; + struct Scsi_Host *shp; + ASC_DVC_VAR *boardp; + int ioport = 0; + PCI_DEVICE pciDevice; + PCI_CONFIG_SPACE pciConfig; + int ret; + extern PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX]; + + + if (detect_called == ASC_FALSE) { + detect_called = ASC_TRUE; + } else { + printk("AdvanSys SCSI: advansys_detect() mulitple calls ignored\n"); + return 0; + } + + ASC_DBG(1, "advansys_detect: begin\n"); + +#ifdef LINUX_1_3 + tpnt->proc_dir = &proc_scsi_advansys; +#endif /* LINUX_1_3 */ + +#ifdef ADVANSYS_STATS + memset(&asc_stats, 0, sizeof(asc_stats)); +#endif /* ADVANSYS_STATS */ + + asc_board_count = 0; + + /* + * If I/O port probing has been modified, then verify and + * clean-up the 'asc_ioport' list. + */ + if (asc_iopflag == ASC_TRUE) { + for (ioport = 0; ioport < ASC_NUM_BOARD_SUPPORTED; ioport++) { + ASC_DBG2(1, "asdvansys_detect: asc_ioport[%d] %x\n", + ioport, asc_ioport[ioport]); + if (asc_ioport[ioport] != 0) { + for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX; iop++) { + if (_asc_def_iop_base[iop] == asc_ioport[ioport]) { + break; + } + } + if (iop == ASC_IOADR_TABLE_MAX_IX) { + printk("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n", + asc_ioport[ioport]); + asc_ioport[ioport] = 0; + } + } + } + ioport = 0; + } + + memset(&pciDevice, 0, sizeof(PCI_DEVICE)); + memset(&pciConfig, 0, sizeof(PCI_CONFIG_SPACE)); + pciDevice.maxBusNumber = PCI_MAX_BUS; + pciDevice.endSlot = PCI_MAX_SLOT; + + for (bus = 0; bus < ASC_NUM_BUS; bus++) { + + ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n", + bus, asc_bus_name[bus]); + iop = 0; + + while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) { + + ASC_DBG1(2, "advansys_detect: asc_board_count %d\n", + asc_board_count); + + switch (asc_bus[bus]) { + case ASC_IS_ISA: + case ASC_IS_VL: + if (asc_iopflag == ASC_FALSE) { + iop = AscSearchIOPortAddr(iop, asc_bus[bus]); + } else { + /* + * ISA and VL I/O port scanning has either been + * eliminated or limited to selected ports on + * the LILO command line, /etc/lilo.conf, or + * by setting variables when the module was loaded. + */ + ASC_DBG(1, "advansys_detect: I/O port scanning modified\n"); + ioport_try_again: + iop = 0; + for (; ioport < ASC_NUM_BOARD_SUPPORTED; ioport++) { + if ((iop = asc_ioport[ioport]) != 0) { + break; + } + } + if (iop) { + ASC_DBG1(1, "advansys_detect: probing I/O port %x...\n", + iop); + if (check_region(iop, ASC_IOADR_GAP) != 0) { + printk("AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop); + /* Don't try this I/O port twice. */ + asc_ioport[ioport] = 0; + goto ioport_try_again; + } else if (AscFindSignature(iop) == ASC_FALSE) { + printk("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop); + /* Don't try this I/O port twice. */ + asc_ioport[ioport] = 0; + goto ioport_try_again; + } else { + /* + * If this isn't an ISA board, then it must be + * a VL board. If currently looking an ISA + * board is being looked for then try for + * another ISA board in 'asc_ioport'. + */ + if (asc_bus[bus] == ASC_IS_ISA && + (AscGetChipVersion(iop, ASC_IS_ISA) & + ASC_CHIP_VER_ISA_BIT) == 0) { + /* + * Don't clear 'asc_ioport[ioport]'. Try + * this board again for VL. Increment + * 'ioport' past this board. + */ + ioport++; + goto ioport_try_again; + } + } + /* + * This board appears good, don't try the I/O port + * again by clearing its value. Increment 'ioport' + * for the next iteration. + */ + asc_ioport[ioport++] = 0; + } + } + break; + + case ASC_IS_EISA: + iop = AscSearchIOPortAddr(iop, asc_bus[bus]); + break; + + case ASC_IS_PCI: + if (asc_srch_pci_dev(&pciDevice) != PCI_DEVICE_FOUND) { + iop = 0; + } else { + ASC_DBG2(2, + "advansys_detect: slotFound %d, busNumber %d\n", + pciDevice.slotFound, pciDevice.busNumber); + asc_get_pci_cfg(&pciDevice, &pciConfig); + iop = pciConfig.baseAddress[0] & PCI_IOADDRESS_MASK; + ASC_DBG2(2, "advansys_detect: iop %x, irqLine %d\n", + iop, pciConfig.irqLine); + } + break; + + default: + ASC_DBG(0, "advansys_detect: unknown bus type\n"); + break; + } + ASC_DBG1(1, "advansys_detect: iop %x\n", iop); + + /* + * Adapter not found, try next bus type. + */ + if (iop == 0) { + break; + } + + /* + * Adapter found. + * + * Register the adapter, get its configuration, and + * initialize it. + */ + ASC_DBG(2, "advansys_detect: scsi_register()\n"); + shp = scsi_register(tpnt, sizeof(struct asc_board)); + + /* Save a pointer to the Scsi_host of each found board. */ + asc_host[asc_board_count++] = shp; + + /* Initialize private per board data */ + memset(ASC_BOARD(shp), 0, sizeof(struct asc_board)); + boardp = &ASC_BOARD(shp)->board; + boardp->cfg = &ASC_BOARD(shp)->cfg; + boardp->cfg->overrun_buf = &ASC_BOARD(shp)->overrun_buf[0]; + boardp->iop_base = iop; + + /* + * Set the board bus type and PCI IRQ for AscInitGetConfig(). + */ + boardp->bus_type = asc_bus[bus]; + switch (boardp->bus_type) { + case ASC_IS_ISA: + shp->unchecked_isa_dma = TRUE; + break; + case ASC_IS_EISA: + shp->unchecked_isa_dma = FALSE; + break; + case ASC_IS_VL: + shp->unchecked_isa_dma = FALSE; + break; + case ASC_IS_PCI: + shp->irq = boardp->irq_no = pciConfig.irqLine; + boardp->cfg->pci_device_id = pciConfig.deviceID; + shp->unchecked_isa_dma = FALSE; + break; + default: + ASC_DBG(0, "advansys_detect: unknown adapter type"); + shp->unchecked_isa_dma = TRUE; + break; + } + + /* + * Get the board configuration. AscInitGetConfig() may change + * the board's bus_type value. The asc_bus[bus] value should no + * longer be used. + */ + ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n"); + switch(ret = AscInitGetConfig(boardp)) { + case 0: /* No error */ + break; + case ASC_WARN_IO_PORT_ROTATE: + ASC_DBG(0, "AscInitGetConfig: I/O port address modified\n"); + break; + case ASC_WARN_EEPROM_CHKSUM: + ASC_DBG(0, "AscInitGetConfig: EEPROM checksum error\n"); + break; + case ASC_WARN_IRQ_MODIFIED: + ASC_DBG(0, "AscInitGetConfig: IRQ modified\n"); + break; + case ASC_WARN_CMD_QNG_CONFLICT: + ASC_DBG(0, + "AscInitGetConfig: Tag queuing enabled w/o disconnects\n"); + break; + default: + ASC_DBG1(0, "AscInitGetConfig: Unknown warning: %x\n", ret); + break; + } + if (boardp->err_code != 0) { + ASC_DBG2(0, + "AscInitGetConfig: error: init_state %x, err_code %x\n", + boardp->init_state, boardp->err_code); + scsi_unregister(shp); + asc_board_count--; + continue; + } + + /* + * Modify board configuration. + */ + boardp->isr_callback = (Ptr2Func) asc_isr_callback; + boardp->exe_callback = (Ptr2Func) NULL; + + ASC_DBG(2, "advansys_detect: AscInitSetConfig()\n"); + switch (ret = AscInitSetConfig(boardp)) { + case 0: /* No error. */ + break; + case ASC_WARN_IO_PORT_ROTATE: + ASC_DBG(0, "AscInitSetConfig: I/O port address modified\n"); + break; + case ASC_WARN_EEPROM_CHKSUM: + ASC_DBG(0, "AscInitSetConfig: EEPROM checksum error\n"); + break; + case ASC_WARN_IRQ_MODIFIED: + ASC_DBG(0, "AscInitSetConfig: IRQ modified\n"); + break; + case ASC_WARN_CMD_QNG_CONFLICT: + ASC_DBG(0, "AscInitSetConfig: Tag queuing w/o disconnects\n"); + break; + default: + ASC_DBG1(0, "AscInitSetConfig: Unknown warning: %x\n", ret); + break; + } + if (boardp->err_code != 0) { + ASC_DBG2(0, + "AscInitSetConfig: error: init_state %x, err_code %x\n", + boardp->init_state, boardp->err_code); + scsi_unregister(shp); + asc_board_count--; + continue; + } + + /* + * Finish initializing the 'Scsi_Host' structure. + */ + + /* AscInitSetConfig() will set the IRQ for non-PCI boards. */ + if (boardp->bus_type != ASC_IS_PCI) { + shp->irq = boardp->irq_no; + } + + shp->io_port = boardp->iop_base; + shp->n_io_port = ASC_IOADR_GAP; + shp->this_id = boardp->cfg->chip_scsi_id; + + /* Maximum number of queues this adapter can handle. */ + shp->can_queue = boardp->max_total_qng; + + /* + * XXX - Command queuing limits are maintained per target + * by AdvanSys adapters. Set 'cmd_per_lun' to the minimum + * value of the all the target settings for the adapter. + * + * For now set 'cmd_per_lun' to 'max_total_qng'. This + * value should be adjusted every time a new device is + * found in asc_init_dev(). + * + * XXX - memory allocation is done by the mid-level scsi + * driver based on 'cmd_per_lun'. If 'sg_tablesize' is too large + * allocation failures can occur in scsi_register_host(). + * A 'Scsi_Cmnd' structure is pre-allocated for each command + * also DMA memory is reserved. Set it artificially low for now. + * + * shp->cmd_per_lun = boardp->max_total_qng; + */ +#ifdef MODULE + shp->cmd_per_lun = 1; +#else /* MODULE */ + shp->cmd_per_lun = 4; +#endif /* MODULE */ + ASC_DBG1(1, "advansys_detect: cmd_per_lun: %d\n", shp->cmd_per_lun); + + /* Maximum number of scatter-gather elements adapter can handle. */ + /* + * XXX - memory allocation is done by the mid-level scsi + * driver based on sg_tablesize. If 'sg_tablesize' is too large + * allocation failures can occur in scsi_register_host(). + */ +#ifdef MODULE + shp->sg_tablesize = 8; +#else /* MODULE */ + shp->sg_tablesize = ASC_MAX_SG_LIST; +#endif /* MODULE */ + ASC_DBG1(1, "advansys_detect: sg_tablesize: %d\n", + shp->sg_tablesize); + + /* BIOS start address. */ + shp->base = (char *) ((ulong) AscGetChipBiosAddress( + boardp->iop_base, + boardp->bus_type)); + + /* + * Register Board Resources - I/O Port, DMA, IRQ + */ + + /* Register I/O port range */ + ASC_DBG(2, "advansys_detect: request_region()\n"); + request_region(shp->io_port, shp->n_io_port, "advansys"); + + /* Register DMA channel for ISA bus. */ + if ((boardp->bus_type & ASC_IS_ISA) == 0) { + shp->dma_channel = NO_ISA_DMA; + } else { + shp->dma_channel = boardp->cfg->isa_dma_channel; + if ((ret = request_dma(shp->dma_channel, "advansys")) != 0) { + ASC_DBG2(0, "advansys_detect: request_dma() %d failed %d\n", + shp->dma_channel, ret); + release_region(shp->io_port, shp->n_io_port); + scsi_unregister(shp); + asc_board_count--; + continue; + } + AscEnableIsaDma(shp->dma_channel); + } + + /* Register IRQ Number. */ + ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq); + if ((ret = request_irq(shp->irq, advansys_interrupt, + SA_INTERRUPT, "advansys")) != 0) { + ASC_DBG1(0, "advansys_detect: request_irq() failed %d\n", ret); + release_region(shp->io_port, shp->n_io_port); + if (shp->dma_channel != NO_ISA_DMA) { + free_dma(shp->dma_channel); + } + scsi_unregister(shp); + asc_board_count--; + continue; + } + + /* + * Initialize board RISC chip and enable interrupts. + */ + ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n"); + if (AscInitAsc1000Driver(boardp)) { + ASC_DBG2(0, + "AscInitAsc1000Driver: error: init_state %x, err_code %x\n", + boardp->init_state, boardp->err_code); + release_region(shp->io_port, shp->n_io_port); + if (shp->dma_channel != NO_ISA_DMA) { + free_dma(shp->dma_channel); + } + free_irq(shp->irq); + scsi_unregister(shp); + asc_board_count--; + continue; + } + ASC_DBG_PRT_SCSI_HOST(2, shp); + } + } + + ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count); + return asc_board_count; +} + +/* + * advansys_release() + * + * Release resources allocated for a single AdvanSys adapter. + */ +int +advansys_release(struct Scsi_Host *shp) +{ + ASC_DBG(1, "advansys_release: begin\n"); + free_irq(shp->irq); + if (shp->dma_channel != NO_ISA_DMA) { + ASC_DBG(1, "advansys_release: free_dma()\n"); + free_dma(shp->dma_channel); + } + release_region(shp->io_port, shp->n_io_port); + scsi_unregister(shp); + ASC_DBG(1, "advansys_release: end\n"); + return 0; +} + +/* + * advansys_info() + * + * Return suitable for printing on the console with the argument + * adapter's configuration information. + */ +const char * +advansys_info(struct Scsi_Host *shp) +{ + static char info[128]; + ASC_DVC_VAR *boardp; + char *busname; + + boardp = &ASC_BOARD(shp)->board; + ASC_DBG(1, "advansys_info: begin\n"); + if (boardp->bus_type & ASC_IS_ISA) { + sprintf(info, + "AdvanSys SCSI %s: ISA (%u CDB): BIOS %X, IO %X-%X, IRQ %u, DMA %u", + ASC_VERSION, ASC_BOARD(shp)->board.max_total_qng, + (unsigned) shp->base, shp->io_port, + shp->io_port + (shp->n_io_port - 1), shp->irq, shp->dma_channel); + } else { + switch (boardp->bus_type) { + case ASC_IS_EISA: + busname = "EISA"; + break; + case ASC_IS_VL: + busname = "VL"; + break; + case ASC_IS_PCI: + busname = "PCI"; + break; + default: + busname = "?"; + ASC_DBG1(0, "advansys_info: unknown bus type %d\n", + boardp->bus_type); + break; + } + /* No DMA channel for non-ISA busses. */ + sprintf(info, + "AdvanSys SCSI %s: %s (%u CDB): BIOS %X, IO %X-%X, IRQ %u", + ASC_VERSION, busname, ASC_BOARD(shp)->board.max_total_qng, + (unsigned) shp->base, shp->io_port, + shp->io_port + (shp->n_io_port - 1), shp->irq); + } + ASC_DBG(1, "advansys_info: end\n"); + return info; +} + +/* + * advansys_command() + * + * Polled-I/O. Apparently host driver shouldn't return until + * command is finished. + * + * XXX - Can host driver block here instead of spinning on command status? + */ +int +advansys_command(Scsi_Cmnd *scp) +{ + ASC_DBG1(1, "advansys_command: scp %x\n", (unsigned) scp); + ASC_STATS(command); + scp->SCp.Status = 0; /* Set to a known state */ + advansys_queuecommand(scp, advansys_command_done); + while (scp->SCp.Status == 0) { + continue; + } + ASC_DBG1(1, "advansys_command: result %x\n", scp->result); + return scp->result; +} + +/* + * advansys_queuecommand() + * + * This function always returns 0. Command return status is saved + * in the 'scp' result field. + */ +int +advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *)) +{ + struct Scsi_Host *shp; + int flags = 0; + int interrupts_disabled; + + ASC_STATS(queuecommand); + shp = scp->host; + +#ifdef LINUX_1_2 + /* + * For LINUX_1_3, if statistics are enabled they can be accessed + * by reading /proc/scsi/advansys/[0-9]. + */ +#ifdef ADVANSYS_STATS_1_2_PRINT + /* Display statistics every 10000 commands. */ + if ((asc_stats.queuecommand % 10000) == 0) { + printk("\n"); + (void) asc_prt_stats(NULL, 0); + printk("\n"); + } +#endif /* ADVANSYS_STATS_1_2_PRINT */ +#endif /* LINUX_1_2 */ + + /* + * If there are any pending commands for this board before trying + * to execute them, disable interrupts to preserve request ordering. + * + * The typical case will be no pending commands and interrupts + * not disabled. + */ + if (ASC_BOARD(shp)->pending_tidmask == 0) { + interrupts_disabled = ASC_FALSE; + } else { + ASC_STATS(cmd_disable); + /* Disable interrupts */ + interrupts_disabled = ASC_TRUE; + save_flags(flags); + cli(); + ASC_DBG1(1, "advansys_queuecommand: asc_execute_pending() %x\n", + ASC_BOARD(shp)->pending_tidmask); + asc_execute_pending(shp); + } + + /* + * Save the function pointer to Linux mid-level 'done' function and + * execute the command. + */ + scp->scsi_done = done; + if (asc_execute_scsi_cmnd(scp) == ASC_BUSY) { + if (interrupts_disabled == ASC_FALSE) { + save_flags(flags); + cli(); + interrupts_disabled = ASC_TRUE; + } + asc_enqueue(shp, scp, scp->target, ASC_BACK); + } + + if (interrupts_disabled == ASC_TRUE) { + restore_flags(flags); + } + + return 0; +} + +/* + * advansys_abort() + * + * Abort the specified command and reset the device + * associated with the command 'scp'. + */ +int +advansys_abort(Scsi_Cmnd *scp) +{ + ASC_DVC_VAR *boardp; + int flags; + int ret; + + ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp); + save_flags(flags); + cli(); + ASC_STATS(abort); + if (scp->host == NULL) { + scp->result = HOST_BYTE(DID_ERROR); + ret = SCSI_ABORT_ERROR; + } else if (asc_rmqueue(scp->host, scp, scp->target) == ASC_TRUE) { + scp->result = HOST_BYTE(DID_ABORT); + ret = SCSI_ABORT_SUCCESS; + (void) AscResetDevice(&ASC_BOARD(scp->host)->board, scp->target); + } else { + /* Must enable interrupts for AscAbortSRB() */ + sti(); + boardp = &ASC_BOARD(scp->host)->board; + scp->result = HOST_BYTE(DID_ABORT); + switch (AscAbortSRB(boardp, (ulong) scp)) { + case ASC_TRUE: + /* asc_isr_callback() will be called */ + ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n"); + ret = SCSI_ABORT_PENDING; + break; + case ASC_FALSE: + /* Request has apparently already completed. */ + ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n"); + ret = SCSI_ABORT_NOT_RUNNING; + break; + case ASC_ERROR: + default: + ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n"); + ret = SCSI_ABORT_ERROR; + break; + } + (void) AscResetDevice(boardp, scp->target); + } + restore_flags(flags); + ASC_DBG1(1, "advansys_abort: ret %d\n", ret); + return ret; +} + +/* + * advansys_reset() + * + * Reset all devices and the SCSI bus for the board + * associated with 'scp'. + */ +int +advansys_reset(Scsi_Cmnd *scp) +{ + ASC_DVC_VAR *boardp; + int flags; + Scsi_Cmnd *tscp; + int i; + int ret; + + ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp); + save_flags(flags); + cli(); + ASC_STATS(reset); + if (scp->host == NULL) { + scp->result = HOST_BYTE(DID_ERROR); + ret = SCSI_RESET_ERROR; + } else { + /* Remove any pending commands, set DID_RESET, and done them. */ + for (i = 0; i < ASC_MAX_TID; i++) { + while ((tscp = asc_dequeue(scp->host, i)) != NULL) { + tscp->result = HOST_BYTE(DID_RESET); + tscp->scsi_done(tscp); + } + } + /* Must enable interrupts for AscResetSB() */ + sti(); + boardp = &ASC_BOARD(scp->host)->board; + scp->result = HOST_BYTE(DID_RESET); + switch (AscResetSB(boardp)) { + case ASC_TRUE: + ASC_DBG(1, "advansys_abort: AscResetSB() TRUE\n"); + ret = SCSI_RESET_SUCCESS; + break; + case ASC_ERROR: + default: + ASC_DBG(1, "advansys_abort: AscResetSB() ERROR\n"); + ret = SCSI_RESET_ERROR; + break; + } + } + restore_flags(flags); + ASC_DBG1(1, "advansys_reset: ret %d", ret); + return ret; +} + +/* + * advansys_biosparam() + * + * Translate disk drive geometry if the "BIOS greater than 1 GB" + * support is enabled for a drive. + * + * ip (information pointer) is an int array with the following definition: + * ip[0]: heads + * ip[1]: sectors + * ip[2]: cylinders + */ +int +#ifdef LINUX_1_2 +advansys_biosparam(Disk *dp, int dep, int ip[]) +#else /* LINUX_1_3 */ +advansys_biosparam(Disk *dp, kdev_t dep, int ip[]) +#endif /* LINUX_1_3 */ +{ + ASC_DBG(1, "advansys_biosparam: begin\n"); + ASC_STATS(biosparam); + if ((ASC_BOARD(dp->device->host)->board.dvc_cntl & ASC_CNTL_BIOS_GT_1GB) && + dp->capacity > 0x200000) { + ip[0] = 255; + ip[1] = 64; + } else { + ip[0] = 64; + ip[1] = 32; + } + ip[2] = dp->capacity / (ip[0] * ip[1]); + ASC_DBG(1, "advansys_biosparam: end\n"); + return 0; +} + +/* + * advansys_setup() + * + * This function is called from init/main.c at boot time. + * It it passed LILO parameters that can be set from the + * LILO command line or in /etc/lilo.conf. + * + * It is used by the AdvanSys driver to either disable I/O + * port scanning or to limit scanning to 1 - 4 I/O ports. + * Regardless of the option setting EISA and PCI boards + * will still be searched for and detected. This option + * only affects searching for ISA and VL boards. + * + * If ADVANSYS_DEBUG is defined the driver debug level may + * be set using the 5th (ASC_NUM_BOARD_SUPPORTED + 1) I/O Port. + * + * Examples: + * 1. Eliminate I/O port scanning: + * boot: linux advansys= + * or + * boot: linux advansys=0x0 + * 2. Limit I/O port scanning to one I/O port: + * boot: linux advansys=0x110 + * 3. Limit I/O port scanning to four I/O ports: + * boot: linux advansys=0x110,0x210,0x230,0x330 + * 4. If ADVANSYS_DEBUG, limit I/O port scanning to four I/O ports and + * set the driver debug level to 2. + * boot: linux advansys=0x110,0x210,0x230,0x330,0xdeb2 + * + * ints[0] - number of arguments + * ints[1] - first argument + * ints[2] - second argument + * ... + */ +void +advansys_setup(char *str, int *ints) +{ + int i; + + if (asc_iopflag == ASC_TRUE) { + printk("AdvanSys SCSI: 'advansys' LILO option may appear only once\n"); + return; + } + + asc_iopflag = ASC_TRUE; + + if (ints[0] > ASC_NUM_BOARD_SUPPORTED) { +#ifdef ADVANSYS_DEBUG + if ((ints[0] == ASC_NUM_BOARD_SUPPORTED + 1) && + (ints[ASC_NUM_BOARD_SUPPORTED + 1] >> 4 == 0xdeb)) { + asc_dbglvl = ints[ASC_NUM_BOARD_SUPPORTED + 1] & 0xf; + } else { +#endif /* ADVANSYS_DEBUG */ + printk("AdvanSys SCSI: only %d I/O ports accepted\n", + ASC_NUM_BOARD_SUPPORTED); +#ifdef ADVANSYS_DEBUG + } +#endif /* ADVANSYS_DEBUG */ + } + +#ifdef ADVANSYS_DEBUG + ASC_DBG1(1, "advansys_setup: ints[0] %d\n", ints[0]); + for (i = 1; i < ints[0]; i++) { + ASC_DBG2(1, " ints[%d] %x", i, ints[i]); + } + ASC_DBG(1, "\n"); +#endif /* ADVANSYS_DEBUG */ + + for (i = 1; i <= ints[0] && i <= ASC_NUM_BOARD_SUPPORTED; i++) { + asc_ioport[i-1] = ints[i]; + ASC_DBG2(1, "advansys_setup: asc_ioport[%d] %x\n", + i - 1, asc_ioport[i-1]); + } +} + + +/* + * --- Loadable Driver Support + */ + +#ifdef MODULE +Scsi_Host_Template driver_template = ADVANSYS; +# include "scsi_module.c" +#endif /* MODULE */ + + +/* + * --- Miscellaneous Driver Functions + */ + +#ifdef LINUX_1_3 +/* + * asc_proc_copy() + * + * Copy proc information to a read buffer considering the current read + * offset in the file and the remaining space in the read buffer. + */ +STATIC int +asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen, + char *cp, int cplen) +{ + int cnt = 0; + + ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n", + (unsigned) offset, (unsigned) advoffset, cplen); + if (offset <= advoffset) { + /* Read offset below current offset, copy everything. */ + cnt = min(cplen, leftlen); + ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n", + (unsigned) curbuf, (unsigned) cp, cnt); + memcpy(curbuf, cp, cnt); + } else if (offset < advoffset + cplen) { + /* Read offset within current range, partial copy. */ + cnt = (advoffset + cplen) - offset; + cp = (cp + cplen) - cnt; + cnt = min(cnt, leftlen); + ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n", + (unsigned) curbuf, (unsigned) cp, cnt); + memcpy(curbuf, cp, cnt); + } + return cnt; +} +#endif /* LINUX_1_3 */ + +/* + * First-level interrupt handler. + */ +STATIC void +advansys_interrupt(int irq, struct pt_regs *regs) +{ + int i; + int flags; + Scsi_Cmnd *scp; + Scsi_Cmnd *tscp; + + /* Disable interrupts, if the aren't already disabled. */ + save_flags(flags); + cli(); + + ASC_DBG(1, "advansys_interrupt: begin\n"); + ASC_STATS(interrupt); + /* + * Check for interrupts on all boards. + * AscISR() will call asc_isr_callback(). + */ + for (i = 0; i < asc_board_count; i++) { + while (AscIsIntPending(asc_host[i]->io_port)) { + ASC_DBG(1, "advansys_interrupt: before AscISR()\n"); + AscISR(&ASC_BOARD(asc_host[i])->board); + } + } + ASC_DBG(1, "advansys_interrupt: end\n"); + + /* + * While interrupts are still disabled save the list of requests that + * need their done function called. After re-enabling interrupts call + * the done function which may re-enable interrupts anyway. + */ + if ((scp = asc_scsi_done) != NULL) { + asc_scsi_done = NULL; + } + + /* Re-enable interrupts, if they were enabled on entry. */ + restore_flags(flags); + + while (scp) { + tscp = (Scsi_Cmnd *) scp->host_scribble; + scp->scsi_done(scp); + scp = tscp; + } + + return; +} + +/* + * Function used only with polled I/O requests that are initiated by + * advansys_command(). + */ +STATIC void +advansys_command_done(Scsi_Cmnd *scp) +{ + ASC_DBG1(1, "advansys_command_done: scp %x\n", (unsigned) scp); + scp->SCp.Status = 1; +} + +/* + * Execute a single 'Scsi_Cmnd'. + * + * The function 'done' is called when the request has been completed. + * + * Scsi_Cmnd: + * + * host - board controlling device + * device - device to send command + * target - target of device + * lun - lun of device + * cmd_len - length of SCSI CDB + * cmnd - buffer for SCSI 8, 10, or 12 byte CDB + * use_sg - if non-zero indicates scatter-gather request with use_sg elements + * + * if (use_sg == 0) + * request_buffer - buffer address for request + * request_bufflen - length of request buffer + * else + * request_buffer - pointer to scatterlist structure + * + * sense_buffer - sense command buffer + * + * result (4 bytes of an int): + * Byte Meaning + * 0 SCSI Status Byte Code + * 1 SCSI One Byte Message Code + * 2 Host Error Code + * 3 Mid-Level Error Code + * + * host driver fields: + * SCp - Scsi_Pointer used for command processing status + * scsi_done - used to save caller's done function + * host_scribble - used for pointer to another Scsi_Cmnd + * + * If this function returns ASC_NOERROR or ASC_ERROR the done + * function has been called. If ASC_BUSY is returned the request + * must be enqueued by the caller and re-tried later. + */ +STATIC int +asc_execute_scsi_cmnd(Scsi_Cmnd *scp) +{ + ASC_DVC_VAR *boardp; + ASC_SCSI_Q scsiq; + ASC_SG_HEAD sghead; + int ret; + + ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %x, done %x\n", + (unsigned) scp, (unsigned) scp->scsi_done); + + boardp = &ASC_BOARD(scp->host)->board; + + /* + * If this is the first command, then initialize the device. If + * no device is found set 'DID_BAD_TARGET' and return. + */ + if ((ASC_BOARD(scp->host)->init_tidmask & + ASC_TIX_TO_TARGET_ID(scp->target)) == 0) { + if (asc_init_dev(boardp, scp) == ASC_FALSE) { + scp->result = HOST_BYTE(DID_BAD_TARGET); + scp->scsi_done(scp); + return ASC_ERROR; + } + ASC_BOARD(scp->host)->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target); + } + + memset(&scsiq, 0, sizeof(ASC_SCSI_Q)); + + /* + * Point the ASC_SCSI_Q to the 'Scsi_Cmnd'. + */ + scsiq.q2.srb_ptr = (ulong) scp; + + /* + * Build the ASC_SCSI_Q request. + */ + scsiq.cdbptr = &scp->cmnd[0]; + scsiq.q2.cdb_len = scp->cmd_len; + scsiq.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target); + scsiq.q1.target_lun = scp->lun; + scsiq.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun); + scsiq.q1.sense_addr = (ulong) &scp->sense_buffer[0]; + scsiq.q1.sense_len = sizeof(scp->sense_buffer); + scsiq.q2.tag_code = M2_QTAG_MSG_SIMPLE; + + /* + * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather + * buffer command. + */ + if (scp->use_sg == 0) { + /* + * CDB request of single contiguous buffer. + */ + ASC_STATS(cont_cnt); + /* request_buffer is already a real address. */ + scsiq.q1.data_addr = (ulong) scp->request_buffer; + scsiq.q1.data_cnt = scp->request_bufflen; + ASC_STATS_ADD(cont_xfer, (scp->request_bufflen + 511) >> 9); + scsiq.q1.sg_queue_cnt = 0; + scsiq.sg_head = NULL; + } else { + /* + * CDB scatter-gather request list. + */ + int sgcnt; + struct scatterlist *slp; + + if (scp->use_sg > ASC_MAX_SG_LIST) { + ASC_DBG2(0, "asc_execute_scsi_cmnd: use_sg %d > %d\n", + scp->use_sg, ASC_MAX_SG_LIST); + scp->result = HOST_BYTE(DID_ERROR); + scp->scsi_done(scp); + return ASC_ERROR; + } + + ASC_STATS(sg_cnt); + + /* + * Allocate a ASC_SG_HEAD structure and set the ASC_SCSI_Q + * to point to it. + */ + memset(&sghead, 0, sizeof(ASC_SG_HEAD)); + + scsiq.q1.cntl |= QC_SG_HEAD; + scsiq.sg_head = &sghead; + scsiq.q1.data_cnt = 0; + scsiq.q1.data_addr = 0; + sghead.entry_cnt = scsiq.q1.sg_queue_cnt = scp->use_sg; + ASC_STATS_ADD(sg_elem, sghead.entry_cnt); + + /* + * Convert scatter-gather list into ASC_SG_HEAD list. + */ + slp = (struct scatterlist *) scp->request_buffer; + for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) { + sghead.sg_list[sgcnt].addr = (ulong) slp->address; + sghead.sg_list[sgcnt].bytes = slp->length; + ASC_STATS_ADD(sg_xfer, (slp->length + 511) >> 9); + } + } + + ASC_DBG_PRT_SCSI_Q(2, &scsiq); + ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); + + switch (ret = AscExeScsiQueue(boardp, &scsiq)) { + case ASC_NOERROR: + ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue() ASC_NOERROR\n"); + break; + case ASC_BUSY: + /* Caller must enqueue request and retry later. */ + break; + case ASC_ERROR: + ASC_DBG1(0, + "asc_execute_scsi_cmnd: AscExeScsiQueue() ASC_ERROR err_code %x\n", + boardp->err_code); + ASC_STATS(error); + scp->result = HOST_BYTE(DID_ERROR); + scp->scsi_done(scp); + break; + } + + ASC_DBG(1, "asc_execute_scsi_cmnd: end\n"); + return ret; +} + +/* + * asc_isr_callback() - Second Level Interrupt Handler called by AscISR(). + */ +void +asc_isr_callback(ASC_DVC_VAR *boardp, ASC_QDONE_INFO *qdonep) +{ + Scsi_Cmnd *scp; + struct Scsi_Host *shp; + int flags; + Scsi_Cmnd **scpp; + + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_DBG2(1, "asc_isr_callback: boardp %x, qdonep %x\n", + (unsigned) boardp, (unsigned) qdonep); + ASC_STATS(callback); + ASC_DBG_PRT_QDONE_INFO(2, qdonep); + + /* + * Get the Scsi_Cmnd structure and Scsi_Host structure for the + * command that has been completed. + */ + scp = (Scsi_Cmnd *) qdonep->d2.srb_ptr; + ASC_DBG1(1, "asc_isr_callback: scp %x\n", (unsigned) scp); + ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); + + shp = scp->host; + ASC_ASSERT(shp); + ASC_DBG1(1, "asc_isr_callback: shp %x\n", (unsigned) shp); + + /* + * 'qdonep' contains the command's ending status. + */ + switch (qdonep->d3.done_stat) { + case QD_NO_ERROR: + ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n"); + switch (qdonep->d3.host_stat) { + case QHSTA_NO_ERROR: + scp->result = 0; + break; + default: + /* QHSTA error occurred */ + scp->result = HOST_BYTE(DID_ERROR); + break; + } + break; + + case QD_WITH_ERROR: + ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n"); + switch (qdonep->d3.host_stat) { + case QHSTA_NO_ERROR: + if (qdonep->d3.scsi_stat == SS_CHK_CONDITION) { + ASC_DBG(2, "asc_isr_callback: SS_CHK_CONDITION\n"); + ASC_DBG_PRT_SENSE(2, scp->sense_buffer, + sizeof(scp->sense_buffer)); + /* + * Note: The status_byte() macro used by target drivers + * defined in scsi.h shifts the status byte returned by + * host drivers right by 1 bit. This is why target drivers + * also use left shifted status byte definitions. For instance + * target drivers use CHECK_CONDITION, defined to 0x1, instead + * of the SCSI defined check condition value of 0x2. + */ + scp->result = DRIVER_BYTE(DRIVER_SENSE) | + STATUS_BYTE(qdonep->d3.scsi_stat); + } else { + scp->result = STATUS_BYTE(qdonep->d3.scsi_stat); + } + break; + + default: + /* QHSTA error occurred */ + ASC_DBG1(2, "asc_isr_callback: host_stat %x\n", + qdonep->d3.host_stat); + scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) | + STATUS_BYTE(qdonep->d3.scsi_stat); + break; + } + break; + + case QD_ABORTED_BY_HOST: + ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n"); + scp->result = HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.scsi_msg) | + STATUS_BYTE(qdonep->d3.scsi_stat); + break; + + default: + ASC_DBG1(0, "asc_isr_callback: done_stat %x\n", qdonep->d3.done_stat ); + scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) | + STATUS_BYTE(qdonep->d3.scsi_stat); + break; + } + + /* + * Before calling 'scsi_done' for the current 'Scsi_Cmnd' and possibly + * triggering more commands to be issued, try to start any pending + * commands. + */ + if (ASC_BOARD(shp)->pending_tidmask != 0) { + /* + * If there are any pending commands for this board before trying + * to execute them, disable interrupts to preserve request ordering. + */ + ASC_STATS(intr_disable); + save_flags(flags); + cli(); + ASC_DBG1(1, "asc_isr_callback: asc_execute_pending() %x\n", + ASC_BOARD(shp)->pending_tidmask); + asc_execute_pending(shp); + restore_flags(flags); + } + + /* + * Because interrupts may be enabled by the 'Scsi_Cmnd' done function, + * add the command to the end of the global done list. The done function + * for the command will be called in advansys_interrupt(). + */ + for (scpp = &asc_scsi_done; *scpp; + scpp = (Scsi_Cmnd **) &(*scpp)->host_scribble) { + ; + } + *scpp = scp; + scp->host_scribble = NULL; + return; +} + +/* + * Execute as many pending requests as possible for the + * board specified by 'Scsi_Host'. + */ +STATIC void +asc_execute_pending(struct Scsi_Host *shp) +{ + ASC_SCSI_BIT_ID_TYPE scan_tidmask; + Scsi_Cmnd *scp; + int i; + + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + /* + * Execute pending commands for devices attached to + * the current board in round-robin fashion. + */ + scan_tidmask = ASC_BOARD(shp)->pending_tidmask; + do { + for (i = 0; i < ASC_MAX_TID; i++) { + if (scan_tidmask & ASC_TIX_TO_TARGET_ID(i)) { + if ((scp = asc_dequeue(shp, i)) == NULL) { + scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); + } else if (asc_execute_scsi_cmnd(scp) == ASC_BUSY) { + scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); + /* Put the request back at front of the list. */ + asc_enqueue(shp, scp, i, ASC_FRONT); + } + } + } + } while (scan_tidmask); + return; +} + +/* + * asc_init_dev() + * + * Perform one-time initialization of a device. + */ +STATIC int +asc_init_dev(ASC_DVC_VAR *boardp, Scsi_Cmnd *scp) +{ + ASC_SCSI_REQ_Q *scsireqq; + ASC_CAP_INFO *cap_info; + ASC_SCSI_INQUIRY *inquiry; + int found; + ASC_SCSI_BIT_ID_TYPE save_use_tagged_qng; + ASC_SCSI_BIT_ID_TYPE save_can_tagged_qng; + int ret; +#ifdef ADVANSYS_DEBUG + ASC_SCSI_BIT_ID_TYPE tidmask; /* target id bit mask: 1 - 128 */ +#endif /* ADVANSYS_DEBUG */ + + ASC_DBG1(1, "asc_init_dev: target %d\n", (unsigned) scp->target); + + /* Return true for the board's target id. */ + if (boardp->cfg->chip_scsi_id == scp->target) { + return ASC_TRUE; + } + + /* + * XXX - Host drivers should not modify the timeout field. + * But on the first command only add some extra time to + * allow the driver to complete its initialization for the + * device. + */ + scp->timeout += 2000; /* Add 5 seconds to the request timeout. */ + + /* Set-up AscInitPollTarget() arguments. */ + scsireqq = &ASC_BOARD(scp->host)->scsireqq; + memset(scsireqq, 0, sizeof(ASC_SCSI_REQ_Q)); + cap_info = &ASC_BOARD(scp->host)->cap_info; + memset(cap_info, 0, sizeof(ASC_CAP_INFO)); + inquiry = &ASC_BOARD(scp->host)->inquiry; + memset(inquiry, 0, sizeof(ASC_SCSI_INQUIRY)); + + /* + * XXX - AscInitPollBegin() re-initializes these fields to + * zero. 'Or' in the new values and restore them before calling + * AscInitPollEnd(). Normally all targets are initialized within + * a call to AscInitPollBegin() and AscInitPollEnd(). + */ + save_use_tagged_qng = boardp->use_tagged_qng; + save_can_tagged_qng = boardp->cfg->can_tagged_qng; + + ASC_DBG(2, "asc_init_dev: AscInitPollBegin()\n"); + if (AscInitPollBegin(boardp)) { + ASC_DBG(0, "asc_init_dev: AscInitPollBegin() failed\n"); + return ASC_FALSE; + } + + scsireqq->sense_ptr = &scsireqq->sense[0]; + scsireqq->r1.sense_len = ASC_MIN_SENSE_LEN; + scsireqq->r1.target_id = ASC_TID_TO_TARGET_ID(scp->target); + scsireqq->r1.target_lun = 0; + scsireqq->r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0); + + found = ASC_FALSE; + ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n"); + switch (ret = AscInitPollTarget(boardp, scsireqq, inquiry, cap_info)) { + case ASC_TRUE: + found = ASC_TRUE; +#ifdef ADVANSYS_DEBUG + tidmask = ASC_TIX_TO_TARGET_ID(scp->target); + ASC_DBG2(1, "asc_init_dev: lba %lu, blk_size %lu\n", + cap_info->lba, cap_info->blk_size); + ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n", + inquiry->byte0.peri_dvc_type); + if (boardp->use_tagged_qng & tidmask) { + ASC_DBG1(1, "asc_init_dev: command queuing enabled: %d\n", + boardp->max_dvc_qng[scp->target]); + } else { + ASC_DBG(1, "asc_init_dev: command queuing disabled\n"); + } + if (boardp->init_sdtr & tidmask) { + ASC_DBG(1, "asc_init_dev: synchronous transfers enabled\n"); + } else { + ASC_DBG(1, "asc_init_dev: synchronous transfers disabled\n"); + } + /* Set bit means fix disabled. */ + if (boardp->pci_fix_asyn_xfer & tidmask) { + ASC_DBG(1, "asc_init_dev: synchronous transfer fix disabled\n"); + } else { + ASC_DBG(1, "asc_init_dev: synchronous transfer fix enabled\n"); + } +#endif /* ADVANSYS_DEBUG */ + break; + case ASC_FALSE: + ASC_DBG(1, "asc_init_dev: no device found\n"); + break; + case ASC_ERROR: + ASC_DBG(0, "asc_init_dev: AscInitPollTarget() ASC_ERROR\n"); + break; + default: + ASC_DBG1(0, "asc_init_dev: AscInitPollTarget() unknown ret %d\n", ret); + break; + } + + /* XXX - 'Or' in original tag bits. */ + boardp->use_tagged_qng |= save_use_tagged_qng; + boardp->cfg->can_tagged_qng |= save_can_tagged_qng; + + ASC_DBG(2, "asc_init_dev: AscInitPollEnd()\n"); + AscInitPollEnd(boardp); + +#ifdef ASC_SET_CMD_PER_LUN + /* + * XXX - Refer to the comment in advansys_detect() + * regarding cmd_per_lun. + */ + for (i = 0; i <= ASC_MAX_TID; i++) { + if (boardp->max_dvc_qng[i] < scp->host->cmd_per_lun) { + scp->host->cmd_per_lun = boardp->max_dvc_qng[i]; + } + } +#endif /* ASC_SET_CMD_PER_LUN */ + + return found; +} + +/* + * Search for an AdvanSys PCI device in the PCI configuration space. + */ +STATIC int +asc_srch_pci_dev(PCI_DEVICE *pciDevice) +{ + int ret; + static int scan = 1; + + ASC_DBG(2, "asc_srch_pci_dev: begin\n"); + + if (scan) { + pciDevice->type = asc_scan_method(pciDevice); + scan = 0; + ASC_DBG1(2, "asc_srch_pci_dev: type %d\n", pciDevice->type); + } + ret = asc_pci_find_dev(pciDevice); + ASC_DBG1(2, "asc_srch_pci_dev: asc_pci_find_dev() return %d\n", ret); + if (ret == PCI_DEVICE_FOUND) { + pciDevice->slotNumber = pciDevice->slotFound + 1; + pciDevice->startSlot = pciDevice->slotFound + 1; + } else { + if (pciDevice->bridge > pciDevice->busNumber) { + ASC_DBG2(2, "asc_srch_pci_dev: bridge %x, busNumber %x\n", + pciDevice->bridge, pciDevice->busNumber); + pciDevice->busNumber++; + pciDevice->slotNumber = 0; + pciDevice->startSlot = 0; + pciDevice->endSlot = 0x0f; + ret = asc_srch_pci_dev(pciDevice); + ASC_DBG1(2, "asc_srch_pci_dev recursive call return %d\n", ret); + } + } + ASC_DBG1(2, "asc_srch_pci_dev: return %d\n", ret); + return ret; +} + +/* + * Determine the access method to be used for 'pciDevice'. + */ +STATIC uchar +asc_scan_method(PCI_DEVICE *pciDevice) +{ + ushort data; + PCI_DATA pciData; + uchar type; + uchar slot; + + ASC_DBG(2, "asc_scan_method: begin\n"); + memset(&pciData, 0, sizeof(pciData)); + for (type = 1; type < 3; type++) { + pciData.type = type; + for (slot = 0; slot < PCI_MAX_SLOT; slot++) { + pciData.slot = slot; + data = asc_get_cfg_word(&pciData); + if ((data != 0xFFFF) && (data != 0x0000)) { + ASC_DBG2(4, "asc_scan_method: data %x, type %d\n", data, type); + return (type); + } + } + } + ASC_DBG1(4, "asc_scan_method: type %d\n", type); + return (type); +} + +/* + * Check for an AdvanSys PCI device in 'pciDevice'. + * + * Return PCI_DEVICE_FOUND if found, otherwise return PCI_DEVICE_NOT_FOUND. + */ +STATIC int +asc_pci_find_dev(PCI_DEVICE *pciDevice) +{ + PCI_DATA pciData; + ushort vendorid, deviceid; + uchar classcode, subclass; + uchar lslot; + + ASC_DBG(3, "asc_pci_find_dev: begin\n"); + pciData.type = pciDevice->type; + pciData.bus = pciDevice->busNumber; + pciData.func = pciDevice->devFunc; + lslot = pciDevice->startSlot; + for (; lslot < pciDevice->endSlot; lslot++) { + pciData.slot = lslot; + pciData.offset = VENDORID_OFFSET; + vendorid = asc_get_cfg_word(&pciData); + ASC_DBG1(3, "asc_pci_find_dev: vendorid %x\n", vendorid); + if (vendorid != 0xffff) { + pciData.offset = DEVICEID_OFFSET; + deviceid = asc_get_cfg_word(&pciData); + ASC_DBG1(3, "asc_pci_find_dev: deviceid %x\n", deviceid); + if ((vendorid == ASC_PCI_VENDORID) && + ((deviceid == ASC_PCI_DEVICE_ID_REV_A) || + (deviceid == ASC_PCI_DEVICE_ID_REV_B))) { + pciDevice->slotFound = lslot; + ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n"); + return PCI_DEVICE_FOUND; + } else { + pciData.offset = SUBCLASS_OFFSET; + subclass = asc_get_cfg_byte(&pciData); + pciData.offset = CLASSCODE_OFFSET; + classcode = asc_get_cfg_byte(&pciData); + if ((classcode & PCI_BASE_CLASS_BRIDGE_DEVICE) && + (subclass & PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER)) { + pciDevice->bridge++; + } + ASC_DBG2(3, "asc_pci_find_dev: subclass %x, classcode %x\n", + subclass, classcode); + } + } + } + return PCI_DEVICE_NOT_FOUND; +} + +/* + * Read PCI configuration data into 'pciConfig'. + */ +STATIC void +asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig) +{ + PCI_DATA pciData; + uchar counter; + uchar *localConfig; + + ASC_DBG1(4, "asc_get_pci_cfg: slot found - %d\n ", + pciDevice->slotFound); + + pciData.type = pciDevice->type; + pciData.bus = pciDevice->busNumber; + pciData.slot = pciDevice->slotFound; + pciData.func = pciDevice->devFunc; + localConfig = (uchar *) pciConfig; + + for (counter = 0; counter < sizeof(PCI_CONFIG_SPACE); counter++) { + pciData.offset = counter; + *localConfig = asc_get_cfg_byte(&pciData); + ASC_DBG1(4, "asc_get_pci_cfg: byte %x\n", *localConfig); + localConfig++; + } + ASC_DBG1(4, "asc_get_pci_cfg: counter %d\n", counter); +} + +/* + * Read a word (16 bits) from the PCI configuration space. + * + * The configuration mechanism is checked for the correct access method. + */ +STATIC ushort +asc_get_cfg_word(PCI_DATA *pciData) +{ + ushort tmp; + ulong address; + ulong lbus = pciData->bus; + ulong lslot = pciData->slot; + ulong lfunc = pciData->func; + uchar t2CFA, t2CF8; + ushort t1CF8, t1CFA, t1CFC, t1CFE; + + ASC_DBG4(4, "asc_get_cfg_word: type %d, bus %lu, slot %lu, func %lu\n", + pciData->type, lbus, lslot, lfunc); + + /* + * check type of configuration mechanism + */ + if (pciData->type == 2) { + /* + * save these registers so we can restore them after we are done + */ + t2CFA = inp(0xCFA); /* save PCI bus register */ + t2CF8 = inp(0xCF8); /* save config space enable register */ + + /* + * go out and write the bus and enable registers + */ + /* set for type 1 cycle, if needed */ + outp(0xCFA, pciData->bus); + /* set the function number */ + outp(0xCF8, 0x10 | (pciData->func << 1)) ; + + /* + * read the configuration space type 2 locations + */ + tmp = (ushort) inpw(0xC000 | ((pciData->slot << 8) + pciData->offset)); + } else { + /* + * type 1 configuration mechanism + * + * save the CONFIG_ADDRESS and CONFIG_DATA register values + */ + t1CFC = inpw(0xCFC); + t1CFE = inpw(0xCFE); + t1CF8 = inpw(0xCF8); + t1CFA = inpw(0xCFA); + + /* + * enable <31>, bus = <23:16>, slot = <15:11>, + * func = <10:8>, reg = <7:2> + */ + address = (ulong) ((lbus << 16) | (lslot << 11) | + (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L); + + /* + * write out the address to CONFIG_ADDRESS + */ + outl(address, 0xCF8); + + /* + * read in the word from CONFIG_DATA + */ + tmp = (ushort) ((inl(0xCFC) >> + ((pciData->offset & 2) * 8)) & 0xFFFF); + } + ASC_DBG1(4, "asc_get_cfg_word: config data: %x\n", tmp); + return tmp; +} + +/* + * Reads a byte from the PCI configuration space. + * + * The configuration mechanism is checked for the correct access method. + */ +STATIC uchar +asc_get_cfg_byte(PCI_DATA *pciData) +{ + uchar tmp; + ulong address; + ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func; + uchar t2CFA, t2CF8; + ushort t1CF8, t1CFA, t1CFC, t1CFE; + + ASC_DBG1(4, "asc_get_cfg_byte: type: %d\n", pciData->type); + + /* + * check type of configuration mechanism + */ + if (pciData->type == 2) { + /* + * save these registers so we can restore them after we are done + */ + t2CFA = inp(0xCFA); /* save PCI bus register */ + t2CF8 = inp(0xCF8); /* save config space enable register */ + + /* + * go out and write the bus and enable registers + */ + /* set for type 1 cycle, if needed */ + outp(0xCFA, pciData->bus); + /* set the function number */ + outp(0xCF8, 0x10 | (pciData->func << 1)); + + /* + * read the configuration space type 2 locations + */ + tmp = inp(0xC000 | ((pciData->slot << 8) + pciData->offset)); + + /* + * restore the registers used for our transaction + */ + outp(0xCF8, t2CF8); /* restore the enable register */ + outp(0xCFA, t2CFA); /* restore PCI bus register */ + } else { + /* + * type 1 configuration mechanism + * + * save the CONFIG_ADDRESS and CONFIG_DATA register values + */ + t1CFC = inpw(0xCFC); + t1CFE = inpw(0xCFE); + t1CF8 = inpw(0xCF8); + t1CFA = inpw(0xCFA); + + /* + * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>, + * reg = <7:2> + */ + address = (ulong) ((lbus << 16) | (lslot << 11) | + (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L); + + /* + * write out the address to CONFIG_ADDRESS + */ + outl(address, 0xCF8); + + /* + * read in the word from CONFIG_DATA + */ + tmp = (uchar) ((inl(0xCFC) >> ((pciData->offset & 3) * 8)) & 0xFF); + } + ASC_DBG1(4, "asc_get_cfg_byte: config data: %x\n", tmp); + return tmp; +} + +/* + * Add a 'Scsi_Cmnd' to the end of specified 'Scsi_Host' + * target device pending command list. Set 'pending_tidmask' + * to indicate a command is queued for the device. + * + * 'flag' may be either ASC_FRONT or ASC_BACK. + * + * The 'Scsi_Cmnd' host_scribble field is used as a next pointer. + */ +STATIC void +asc_enqueue(struct Scsi_Host *shp, Scsi_Cmnd *scp, int tid, int flag) +{ + Scsi_Cmnd **scpp; + + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK); + ASC_STATS(enqueue); + if (flag == ASC_FRONT) { + scp->host_scribble = (unsigned char *) ASC_BOARD(shp)->pending[tid]; + ASC_BOARD(shp)->pending[tid] = (Scsi_Cmnd *) scp; + } else { /* ASC_BACK */ + for (scpp = &ASC_BOARD(shp)->pending[tid]; *scpp; + scpp = (Scsi_Cmnd **) &(*scpp)->host_scribble) { + ; + } + *scpp = scp; + scp->host_scribble = NULL; + } + ASC_BOARD(shp)->pending_tidmask |= ASC_TIX_TO_TARGET_ID(tid); +} + +/* + * Return first pending 'Scsi_Cmnd' on the specified 'Scsi_Host' + * for the specified target device. Clear the 'pending_tidmask' + * bit for the device if no more commands are left queued for it. + * + * The 'Scsi_Cmnd' host_scribble field is used as a next pointer. + */ +STATIC Scsi_Cmnd * +asc_dequeue(struct Scsi_Host *shp, int tid) +{ + Scsi_Cmnd *scp; + + ASC_STATS(dequeue); + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + if ((scp = ASC_BOARD(shp)->pending[tid]) != NULL) { + ASC_BOARD(shp)->pending[tid] = (Scsi_Cmnd *) scp->host_scribble; + } + if (ASC_BOARD(shp)->pending[tid] == NULL) { + ASC_BOARD(shp)->pending_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid); + } + return scp; +} + +/* + * Remove the specified 'Scsi_Cmnd' from the specified 'Scsi_Host' + * for the specified target device. Clear the 'pending_tidmask' + * bit for the device if no more commands are left queued for it. + * + * The 'Scsi_Cmnd' host_scribble field is used as a next pointer. + * + * Return ASC_TRUE if the command was found and removed, otherwise + * return ASC_FALSE if the command was not found. + */ +STATIC int +asc_rmqueue(struct Scsi_Host *shp, Scsi_Cmnd *scp, int tid) +{ + Scsi_Cmnd **scpp; + int ret; + + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ret = ASC_FALSE; + for (scpp = &ASC_BOARD(shp)->pending[tid]; + *scpp; scpp = (Scsi_Cmnd **) &(*scpp)->host_scribble) { + if (*scpp == scp) { + *scpp = (Scsi_Cmnd *) scp->host_scribble; + scp->host_scribble = NULL; + ASC_STATS(rmqueue); + ret = ASC_TRUE; + } + } + if (ASC_BOARD(shp)->pending[tid] == NULL) { + ASC_BOARD(shp)->pending_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid); + } + return ret; +} + + +/* + * --- Functions Required by the Asc Library + */ + +/* + * Delay for 'n' milliseconds. Don't use the 'jiffies' + * global variable which is incremented once every 5 ms + * from a timer interrupt, because this function may be + * called when interrupts are disabled. + */ +void +DvcSleepMilliSecond(ulong n) +{ + ulong i; + + ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", n); + for (i = 0; i < n; i++) { + udelay(1000); + } +} + +void +DvcDisplayString(uchar *s) +{ + printk(s); +} + +int +DvcEnterCritical(void) +{ + int flags; + + save_flags(flags); + cli(); + return flags; +} + +void +DvcLeaveCritical(int flags) +{ + restore_flags(flags); +} + +/* + * Convert a virtual address to a virtual address. + * + * Apparently Linux is loaded V=R (virtual equals real). Just return + * the virtual address. + */ +ulong +DvcGetPhyAddr(uchar *buf_addr, ulong buf_len) +{ + ulong phys_addr; + + phys_addr = (ulong) buf_addr; + return phys_addr; +} + +ulong +DvcGetSGList(ASC_DVC_VAR *asc_dvc_sg, uchar *buf_addr, ulong buf_len, + ASC_SG_HEAD *asc_sg_head_ptr) +{ + ulong buf_size; + + buf_size = buf_len; + asc_sg_head_ptr->entry_cnt = 1; + asc_sg_head_ptr->sg_list[0].addr = (ulong) buf_addr; + asc_sg_head_ptr->sg_list[0].bytes = buf_size; + return buf_size; +} + +/* + * void + * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words) + * + * Calling/Exit State: + * none + * + * Description: + * Output an ASC_SCSI_Q structure to the chip + */ +void +DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words) +{ + int i; + + ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", (uchar *) outbuf, 2 * words); + AscSetChipLramAddr(iop_base, s_addr); + for (i = 0; i < words; i++, outbuf++) { + if (i == 2 || i == 10) { + continue; + } + AscPutChipLramData(iop_base, *outbuf); + } +} + +/* + * void + * DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words) + * + * Calling/Exit State: + * none + * + * Description: + * Input an ASC_QDONE_INFO structure from the chip + */ +void +DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words) +{ + int i; + + AscSetChipLramAddr(iop_base, s_addr); + for (i = 0; i < words; i++, inbuf++) { + if (i == 5) { + continue; + } + *inbuf = AscGetChipLramData(iop_base); + } + ASC_DBG_PRT_HEX(2, "DvcGetQinfo", (uchar *) inbuf, 2 * words); +} + +/* + * void DvcOutPortWords(ushort iop_base, ushort &outbuf, int words) + * + * Calling/Exit State: + * none + * + * Description: + * output a buffer to an i/o port address + */ +void +DvcOutPortWords(ushort iop_base, ushort *outbuf, int words) +{ + int i; + + for (i = 0; i < words; i++, outbuf++) + outpw(iop_base, *outbuf); +} + +/* + * void DvcInPortWords(ushort iop_base, ushort &outbuf, int words) + * + * Calling/Exit State: + * none + * + * Description: + * input a buffer from an i/o port address + */ +void +DvcInPortWords(ushort iop_base, ushort *inbuf, int words) +{ + int i; + + for (i = 0; i < words; i++, inbuf++) + *inbuf = inpw(iop_base); +} + + +/* + * void DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords) + * + * Calling/Exit State: + * none + * + * Description: + * output a buffer of 32-bit integers to an i/o port address in + * 16 bit integer units + */ +void +DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords) +{ + int i; + int words; + ushort *pw; + + pw = (ushort *) pdw; + words = dwords << 1; + for(i = 0; i < words; i++, pw++) { + outpw(port, *pw); + } + return; +} + + +/* + * --- Tracing and Debugging Functions + */ + +#ifdef ADVANSYS_STATS + +#define ASC_PRT_STATS_NEXT() \ + if (cp) { \ + totlen += len; \ + leftlen -= len; \ + if (leftlen == 0) { \ + return totlen; \ + } \ + cp += len; \ + } + +/* + * asc_prt_stats() + * + * Note: no single line should be greater than 160 characters, cf. + * asc_prt_stats_line(). + * + * Return the number of characters copied into 'cp'. No more than + * 'cplen' characters will be copied to 'cp'. + */ +STATIC int +asc_prt_stats(char *cp, int cplen) +{ + struct asc_stats *s; + int leftlen; + int totlen; + int len; + + s = &asc_stats; + leftlen = cplen; + totlen = len = 0; + + len = asc_prt_stats_line(cp, leftlen, +"\nAdvanSys SCSI Host Driver Statistics:\n"); + ASC_PRT_STATS_NEXT(); + + len = asc_prt_stats_line(cp, leftlen, +" command %lu, queuecommand %lu, abort %lu, reset %lu, biosparam %lu,\n", + s->command, s->queuecommand, s->abort, s->reset, s->biosparam); + ASC_PRT_STATS_NEXT(); + + len = asc_prt_stats_line(cp, leftlen, +" interrupt %lu, callback %lu, cmd_disable %lu, intr_disable %lu,\n", + s->interrupt, s->callback, s->cmd_disable, s->intr_disable); + ASC_PRT_STATS_NEXT(); + + len = asc_prt_stats_line(cp, leftlen, +" error %lu, enqueue %lu, dequeue %lu, rmqueue %lu,\n", + s->error, s->enqueue, s->dequeue, s->rmqueue); + ASC_PRT_STATS_NEXT(); + + if (s->cont_cnt > 0) { + len = asc_prt_stats_line(cp, leftlen, +" cont_cnt %lu, cont_xfer %lu: avg_xfer=%lu kb\n", + s->cont_cnt, s->cont_xfer, (s->cont_xfer/2)/s->cont_cnt); + ASC_PRT_STATS_NEXT(); + } + + if (s->sg_cnt > 0) { + len = asc_prt_stats_line(cp, leftlen, +" sg_cnt %lu, sg_elem %lu, sg_xfer %lu: avg_elem=%lu, avg_size=%lu kb\n", + s->sg_cnt, s->sg_elem, s->sg_xfer, + s->sg_elem/s->sg_cnt, (s->sg_xfer/2)/s->sg_cnt); + ASC_PRT_STATS_NEXT(); + } + + return totlen; +} + +/* + * asc_prt_stats_line() + * + * If 'cp' is NULL print to the console, otherwise print to a buffer. + * + * Return 0 if printing to the console, otherwise return the number of + * bytes written to the buffer. + * + * Note: If any single line is greater than 160 bytes the stack + * will be corrupted. 's[]' is defined to be 160 bytes. + */ +int +asc_prt_stats_line(char *buf, int buflen, char *fmt, ...) +{ + va_list args; + int ret; + char s[160]; /* 2 lines */ + + va_start(args, fmt); + ret = vsprintf(s, fmt, args); + if (buf == NULL) { + (void) printk(s); + ret = 0; + } else { + ret = min(buflen, ret); + memcpy(buf, s, ret); + } + va_end(args); + return ret; +} +#endif /* ADVANSYS_STATS */ + +#ifdef ADVANSYS_DEBUG +/* + * asc_prt_scsi_host() + */ +STATIC void +asc_prt_scsi_host(struct Scsi_Host *s) +{ + printk("Scsi_Host at addr %x\n", (unsigned) s); + printk( +" next %x, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n", + (unsigned) s->next, s->extra_bytes, s->host_busy, s->host_no, + s->last_reset); + + printk( +" host_wait %x, host_queue %x, hostt %x, block %x,\n", + (unsigned) s->host_wait, (unsigned) s->host_queue, + (unsigned) s->hostt, (unsigned) s->block); + + printk( +" wish_block %d, base %x, io_port %d, n_io_port %d, irq %d, dma_channel %d,\n", + s->wish_block, (unsigned) s->base, s->io_port, s->n_io_port, + s->irq, s->dma_channel); + + printk( +" this_id %d, can_queue %d,\n", s->this_id, s->can_queue); + + printk( +" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d, loaded_as_module %d\n", + s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma, + s->loaded_as_module); + + printk("hostdata (struct asc_board)\n"); + asc_prt_dvc_var(&ASC_BOARD(s)->board); + asc_prt_dvc_cfg(&ASC_BOARD(s)->cfg); + printk(" overrun_buf %x\n", (unsigned) &ASC_BOARD(s)->overrun_buf[0]); +} + +/* + * asc_prt_dvc_var() + */ +STATIC void +asc_prt_dvc_var(ASC_DVC_VAR *h) +{ + printk("ASC_DVC_VAR at addr %x\n", (unsigned) h); + + printk( +" iop_base %x, err_code %x, dvc_cntl %x, bug_fix_cntl %d,\n", + h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl); + + printk( +" bus_type %d, isr_callback %x, exe_callback %x, init_sdtr %x,\n", + h->bus_type, (unsigned) h->isr_callback, (unsigned) h->exe_callback, + (unsigned) h->init_sdtr); + + printk( +" sdtr_done %x, use_tagged_qng %x, unit_not_ready %x, chip_no %x,\n", + (unsigned) h->sdtr_done, (unsigned) h->use_tagged_qng, + (unsigned) h->unit_not_ready, (unsigned) h->chip_no); + + printk( +" queue_full_or_busy %x, start_motor %x, scsi_reset_wait %x, irq_no %x,\n", + (unsigned) h->queue_full_or_busy, (unsigned) h->start_motor, + (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no); + + printk( +" is_in_int %x, max_total_qng %x, cur_total_qng %x, in_critical_cnt %x,\n", + (unsigned) h->is_in_int, (unsigned) h->max_total_qng, + (unsigned) h->cur_total_qng, (unsigned) h->in_critical_cnt); + + printk( +" last_q_shortage %x, init_state %x, no_scam %x, pci_fix_asyn_xfer %x,\n", + (unsigned) h->last_q_shortage, (unsigned) h->init_state, + (unsigned) h->no_scam, (unsigned) h->pci_fix_asyn_xfer); + + printk( +" int_count %ld, req_count %ld, busy_count %ld, cfg %x, saved_ptr2func %x\n", + h->int_count, h->req_count, h->busy_count, (unsigned) h->cfg, + (unsigned) h->saved_ptr2func); +} + +/* + * asc_prt_dvc_cfg() + */ +STATIC void +asc_prt_dvc_cfg(ASC_DVC_CFG *h) +{ + printk("ASC_DVC_CFG at addr %x\n", (unsigned) h); + + printk( +" can_tagged_qng %x, cmd_qng_enabled %x, disc_enable %x, res %x,\n", + h->can_tagged_qng, h->cmd_qng_enabled, h->disc_enable, h->res); + + printk( +" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n", + h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel, + h->chip_version); + + printk( +" pci_device_id %d, lib_serial_no %d, lib_version %d, mcode_date %d,\n", + h->pci_device_id, h->lib_serial_no, h->lib_version, h->mcode_date); + + printk( +" mcode_version %d, overrun_buf %x\n", + h->mcode_version, (unsigned) h->overrun_buf); +} + +/* + * asc_prt_scsi_q() + */ +STATIC void +asc_prt_scsi_q(ASC_SCSI_Q *q) +{ + ASC_SG_HEAD *sgp; + int i; + + printk("ASC_SCSI_Q at addr %x\n", (unsigned) q); + + printk( +" target_ix %u, target_lun %u, srb_ptr %x, tag_code %u,\n", + q->q2.target_ix, q->q1.target_lun, + (unsigned) q->q2.srb_ptr, q->q2.tag_code); + + printk( +" data_addr %x, data_cnt %lu, sense_addr %x, sense_len %u,\n", + (unsigned) q->q1.data_addr, q->q1.data_cnt, + (unsigned) q->q1.sense_addr, q->q1.sense_len); + + printk( +" cdbptr %x, cdb_len %u, sg_head %x, sg_queue_cnt %u\n", + (unsigned) q->cdbptr, q->q2.cdb_len, + (unsigned) q->sg_head, q->q1.sg_queue_cnt); + + if (q->sg_head) { + sgp = q->sg_head; + printk("ASC_SG_HEAD at addr %x\n", (unsigned) sgp); + printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, sgp->queue_cnt); + for (i = 0; i < sgp->entry_cnt; i++) { + printk(" [%u]: addr %x, bytes %lu\n", + i, (unsigned) sgp->sg_list[i].addr, sgp->sg_list[i].bytes); + } + + } +} + +/* + * asc_prt_qdone_info() + */ +STATIC void +asc_prt_qdone_info(ASC_QDONE_INFO *q) +{ + printk("ASC_QDONE_INFO at addr %x\n", (unsigned) q); + printk( +" srb_ptr %x, target_ix %u, cdb_len %u, tag_code %u, done_stat %x\n", + (unsigned) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len, + q->d2.tag_code, q->d3.done_stat); + printk( +" host_stat %x, scsi_stat %x, scsi_msg %x\n", + q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg); +} + +/* + * asc_prt_hex() + * + * Print hexadecimal output in 4 byte groupings 32 bytes + * or 8 double-words per line. + */ +STATIC void +asc_prt_hex(char *f, uchar *s, int l) +{ + int i; + int j; + int k; + int m; + + printk("%s: (%d bytes)\n", f, l); + + for (i = 0; i < l; i += 32) { + + /* Display a maximum of 8 double-words per line. */ + if ((k = (l - i) / 4) >= 8) { + k = 8; + m = 0; + } else { + m = (l - i) % 4 ; + } + + for (j = 0; j < k; j++) { + printk(" %2.2X%2.2X%2.2X%2.2X", + (unsigned) s[i+(j*4)], (unsigned) s[i+(j*4)+1], + (unsigned) s[i+(j*4)+2], (unsigned) s[i+(j*4)+3]); + } + + switch (m) { + case 0: + default: + break; + case 1: + printk(" %2.2X", + (unsigned) s[i+(j*4)+4]); + break; + case 2: + printk(" %2.2X%2.2X", + (unsigned) s[i+(j*4)+4], + (unsigned) s[i+(j*4)+5]); + break; + case 3: + printk(" %2.2X%2.2X%2.2X", + (unsigned) s[i+(j*4)+4], + (unsigned) s[i+(j*4)+5], + (unsigned) s[i+(j*4)+6]); + break; + } + + printk("\n"); + } +} + +/* + * interrupts_enabled() + * + * Return 1 if interrupts are enabled, otherwise return 0. + */ +STATIC int +interrupts_enabled(void) +{ + int flags; + + save_flags(flags); + if (flags & 0x0200) { + return ASC_TRUE; + } else { + return ASC_FALSE; + } +} + +#endif /* ADVANSYS_DEBUG */ + + +/* + * --- Asc Library Functions + */ + +ushort +AscGetEisaChipCfg( + PortAddr iop_base +) +{ + PortAddr eisa_cfg_iop; + + eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) | + (PortAddr) (ASC_EISA_CFG_IOP_MASK); + return (inpw(eisa_cfg_iop)); +} + +uchar +AscSetChipScsiID( + PortAddr iop_base, + uchar new_host_id +) +{ + ushort cfg_lsw; + + if (AscGetChipScsiID(iop_base) == new_host_id) { + return (new_host_id); + } + cfg_lsw = AscGetChipCfgLsw(iop_base); + cfg_lsw &= 0xF8FF; + cfg_lsw |= (ushort) ((new_host_id & ASC_MAX_TID) << 8); + AscSetChipCfgLsw(iop_base, cfg_lsw); + return (AscGetChipScsiID(iop_base)); +} + +ushort +AscGetChipBiosAddress( + PortAddr iop_base, + ushort bus_type +) +{ + ushort cfg_lsw; + ushort bios_addr; + + if ((bus_type & ASC_IS_EISA) != 0) { + cfg_lsw = AscGetEisaChipCfg(iop_base); + cfg_lsw &= 0x000F; + bios_addr = (ushort) (ASC_BIOS_MIN_ADDR + + (cfg_lsw * ASC_BIOS_BANK_SIZE)); + return (bios_addr); + } + cfg_lsw = AscGetChipCfgLsw(iop_base); + bios_addr = (ushort) (((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) + ASC_BIOS_MIN_ADDR); + return (bios_addr); +} + +uchar +AscGetChipVersion( + PortAddr iop_base, + ushort bus_type +) +{ + if ((bus_type & ASC_IS_EISA) != 0) { + + PortAddr eisa_iop; + uchar revision; + + eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) | + (PortAddr) ASC_EISA_REV_IOP_MASK; + revision = inp(eisa_iop); + return ((uchar) ((ASC_CHIP_MIN_VER_EISA - 1) + revision)); + } + return (AscGetChipVerNo(iop_base)); +} + +ushort +AscGetChipBusType( + PortAddr iop_base +) +{ + ushort chip_ver; + + chip_ver = AscGetChipVerNo(iop_base); + if ((chip_ver >= ASC_CHIP_MIN_VER_VL) && + (chip_ver <= ASC_CHIP_MAX_VER_VL)) { + if (((iop_base & 0x0C30) == 0x0C30) || + ((iop_base & 0x0C50) == 0x0C50)) { + return (ASC_IS_EISA); + } + return (ASC_IS_VL); + } else if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) && + (chip_ver <= ASC_CHIP_MAX_VER_ISA)) { + if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) { + return (ASC_IS_ISAPNP); + } + return (ASC_IS_ISA); + } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) && + (chip_ver <= ASC_CHIP_MAX_VER_PCI)) { + return (ASC_IS_PCI); + } else { + return (0); + } +} + +void +AscEnableIsaDma( + uchar dma_channel +) +{ + if (dma_channel < 4) { + outp(0x000B, (ushort) (0xC0 | dma_channel)); + outp(0x000A, dma_channel); + } else if (dma_channel < 8) { + + outp(0x00D6, (ushort) (0xC0 | (dma_channel - 4))); + outp(0x00D4, (ushort) (dma_channel - 4)); + } + return; +} + +ulong +AscLoadMicroCode( + PortAddr iop_base, + ushort s_addr, + ushort dosfar * mcode_buf, + ushort mcode_size +) +{ + ulong chksum; + ushort mcode_word_size; + ushort mcode_chksum; + + mcode_word_size = (ushort) (mcode_size >> 1); + AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size); + AscMemWordCopyToLram(iop_base, s_addr, mcode_buf, mcode_word_size); + + chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size); + mcode_chksum = (ushort) AscMemSumLramWord(iop_base, + (ushort) ASC_CODE_SEC_BEG, + (ushort) ((mcode_size - s_addr - (ushort) ASC_CODE_SEC_BEG) / 2)); + AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum); + AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size); + return (chksum); +} + +uchar _hextbl_[16] = +{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F'}; + +uchar _isa_pnp_inited = 0; + +PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] = +{ + 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4, + ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8 +}; + +PortAddr +AscSearchIOPortAddr( + PortAddr iop_beg, + ushort bus_type +) +{ + if (bus_type & ASC_IS_VL) { + while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) { + if (AscGetChipVersion(iop_beg, bus_type) <= ASC_CHIP_MAX_VER_VL) { + return (iop_beg); + } + } + return (0); + } + if (bus_type & ASC_IS_ISA) { + if (_isa_pnp_inited == 0) { + AscSetISAPNPWaitForKey(); + _isa_pnp_inited++; + } + while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) { + if ((AscGetChipVersion(iop_beg, bus_type) & ASC_CHIP_VER_ISA_BIT) != 0) { + return (iop_beg); + } + } + return (0); + } + if (bus_type & ASC_IS_EISA) { + if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) { + return (iop_beg); + } + return (0); + } + return (0); +} + +PortAddr +AscSearchIOPortAddr11( + PortAddr s_addr +) +{ + + int i; + PortAddr iop_base; + + for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) { + if (_asc_def_iop_base[i] > s_addr) { + break; + } + } + for (; i < ASC_IOADR_TABLE_MAX_IX; i++) { + iop_base = _asc_def_iop_base[i]; + if (AscFindSignature(iop_base)) { + return (iop_base); + } + } + return (0); +} + +int +AscFindSignature( + PortAddr iop_base +) +{ + ushort sig_word; + + if ((inp((PortAddr) (iop_base + 1)) & 0xFF) == (uchar) ASC_1000_ID1B) { + sig_word = inpw(iop_base); + if ((sig_word == (ushort) ASC_1000_ID0W) || + (sig_word == (ushort) ASC_1000_ID0W_FIX)) { + return (1); + } + } + return (0); +} + +void +AscToggleIRQAct( + PortAddr iop_base +) +{ + AscSetChipStatus(iop_base, CIW_IRQ_ACT); + AscSetChipStatus(iop_base, 0); + return; +} + +#if CC_INIT_INQ_DISPLAY + +#endif + +void +AscSetISAPNPWaitForKey( + void) +{ + + outp(ASC_ISA_PNP_PORT_ADDR, 0x02); + outp(ASC_ISA_PNP_PORT_WRITE, 0x02); + return; +} + +uchar +AscGetChipIRQ( + PortAddr iop_base, + ushort bus_type +) +{ + ushort cfg_lsw; + uchar chip_irq; + + if ((bus_type & ASC_IS_EISA) != 0) { + + cfg_lsw = AscGetEisaChipCfg(iop_base); + chip_irq = (uchar) (((cfg_lsw >> 8) & 0x07) + 10); + if ((chip_irq == 13) || (chip_irq > 15)) { + + return (0); + } + return (chip_irq); + } else { + + cfg_lsw = AscGetChipCfgLsw(iop_base); + + if ((bus_type & ASC_IS_VL) != 0) { + + chip_irq = (uchar) (((cfg_lsw >> 2) & 0x07)); + if ((chip_irq == 0) || + (chip_irq == 4) || + (chip_irq == 7)) { + return (0); + } + return ((uchar) (chip_irq + (ASC_MIN_IRQ_NO - 1))); + } + chip_irq = (uchar) (((cfg_lsw >> 2) & 0x03)); + if (chip_irq == 3) + chip_irq += (uchar) 2; + return ((uchar) (chip_irq + ASC_MIN_IRQ_NO)); + } +} + +uchar +AscSetChipIRQ( + PortAddr iop_base, + uchar irq_no, + ushort bus_type +) +{ + ushort cfg_lsw; + + if ((bus_type & ASC_IS_VL) != 0) { + + if (irq_no != 0) { + if ((irq_no < ASC_MIN_IRQ_NO) || (irq_no > ASC_MAX_IRQ_NO)) { + irq_no = 0; + } else { + irq_no -= (uchar) ((ASC_MIN_IRQ_NO - 1)); + } + } + cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE3); + cfg_lsw |= (ushort) 0x0010; + AscSetChipCfgLsw(iop_base, cfg_lsw); + AscToggleIRQAct(iop_base); + + cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE0); + cfg_lsw |= (ushort) ((irq_no & 0x07) << 2); + AscSetChipCfgLsw(iop_base, cfg_lsw); + AscToggleIRQAct(iop_base); + + return (AscGetChipIRQ(iop_base, bus_type)); + + } else if ((bus_type & (ASC_IS_ISA)) != 0) { + + if (irq_no == 15) + irq_no -= (uchar) 2; + irq_no -= (uchar) ASC_MIN_IRQ_NO; + cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFF3); + cfg_lsw |= (ushort) ((irq_no & 0x03) << 2); + AscSetChipCfgLsw(iop_base, cfg_lsw); + return (AscGetChipIRQ(iop_base, bus_type)); + } else { + + return (0); + } +} + +uchar +AscGetChipScsiCtrl( + PortAddr iop_base +) +{ + uchar sc; + + AscSetBank(iop_base, 1); + sc = inp(iop_base + IOP_REG_SC); + AscSetBank(iop_base, 0); + return (sc); +} + +extern uchar _sdtr_period_tbl_[]; + +int +AscIsrChipHalted( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + SDTR_XMSG sdtr_xmsg; + SDTR_XMSG out_msg; + ushort halt_q_addr; + int sdtr_accept; + ushort int_halt_code; + ASC_SCSI_BIT_ID_TYPE scsi_busy; + ASC_SCSI_BIT_ID_TYPE target_id; + PortAddr iop_base; + uchar tag_code; + uchar q_status; + uchar halt_qp; + uchar sdtr_data; + uchar target_ix; + uchar q_cntl, tid_no; + uchar cur_dvc_qng; + uchar asyn_sdtr; + uchar scsi_status; + + iop_base = asc_dvc->iop_base; + int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W); + + halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B); + halt_q_addr = ASC_QNO_TO_QADDR(halt_qp); + target_ix = AscReadLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TARGET_IX)); + q_cntl = AscReadLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL)); + tid_no = ASC_TIX_TO_TID(target_ix); + target_id = (uchar) ASC_TID_TO_TARGET_ID(tid_no); + if (asc_dvc->pci_fix_asyn_xfer & target_id) { + + asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB; + } else { + asyn_sdtr = 0; + } + if (int_halt_code == ASC_HALT_EXTMSG_IN) { + + AscMemWordCopyFromLram(iop_base, + ASCV_MSGIN_BEG, + (ushort dosfar *) & sdtr_xmsg, + (ushort) (sizeof (SDTR_XMSG) >> 1)); + if ((sdtr_xmsg.msg_type == MS_EXTEND) && + (sdtr_xmsg.msg_len == MS_SDTR_LEN)) { + sdtr_accept = TRUE; + if (sdtr_xmsg.msg_req == MS_SDTR_CODE) { + if (sdtr_xmsg.req_ack_offset > ASC_SYN_MAX_OFFSET) { + + sdtr_accept = FALSE; + sdtr_xmsg.req_ack_offset = ASC_SYN_MAX_OFFSET; + } + sdtr_data = AscCalSDTRData(sdtr_xmsg.xfer_period, + sdtr_xmsg.req_ack_offset); + if (sdtr_xmsg.req_ack_offset == 0) { + + q_cntl &= ~QC_MSG_OUT; + asc_dvc->init_sdtr &= ~target_id; + asc_dvc->sdtr_done &= ~target_id; + AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); + } else if ((sdtr_data == 0xFF)) { + + q_cntl |= QC_MSG_OUT; + asc_dvc->init_sdtr &= ~target_id; + asc_dvc->sdtr_done &= ~target_id; + AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); + } else { + if (sdtr_accept && (q_cntl & QC_MSG_OUT)) { + + q_cntl &= ~QC_MSG_OUT; + asc_dvc->sdtr_done |= target_id; + asc_dvc->init_sdtr |= target_id; + asc_dvc->pci_fix_asyn_xfer &= ~target_id; + AscSetChipSDTR(iop_base, sdtr_data, tid_no); + } else { + + q_cntl |= QC_MSG_OUT; + + AscMsgOutSDTR(iop_base, + sdtr_xmsg.xfer_period, + sdtr_xmsg.req_ack_offset); + asc_dvc->pci_fix_asyn_xfer &= ~target_id; + AscSetChipSDTR(iop_base, sdtr_data, tid_no); + asc_dvc->sdtr_done |= target_id; + asc_dvc->init_sdtr |= target_id; + } + } + + AscWriteLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), + q_cntl); + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return (0); + } + } + } else if (int_halt_code == ASC_HALT_CHK_CONDITION) { + + q_cntl |= QC_REQ_SENSE; + if (((asc_dvc->init_sdtr & target_id) != 0) && + ((asc_dvc->sdtr_done & target_id) != 0)) { + + sdtr_data = AscReadLramByte(iop_base, + (ushort) ((ushort) ASCV_SDTR_DATA_BEG + (ushort) tid_no)); + AscMsgOutSDTR(iop_base, + _sdtr_period_tbl_[(sdtr_data >> 4) & (uchar) (ASC_SYN_XFER_NO - 1)], + (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET)); + q_cntl |= QC_MSG_OUT; + } + AscWriteLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), + q_cntl); + + tag_code = AscReadLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE)); + tag_code &= 0xDC; + AscWriteLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE), + tag_code); + + q_status = AscReadLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS)); + q_status |= (QS_READY | QS_BUSY); + AscWriteLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS), + q_status); + + scsi_busy = AscReadLramByte(iop_base, + (ushort) ASCV_SCSIBUSY_B); + scsi_busy &= ~target_id; + AscWriteLramByte(iop_base, (ushort) ASCV_SCSIBUSY_B, scsi_busy); + + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return (0); + } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) { + + AscMemWordCopyFromLram(iop_base, + ASCV_MSGOUT_BEG, + (ushort dosfar *) & out_msg, + (ushort) (sizeof (SDTR_XMSG) >> 1)); + + if ((out_msg.msg_type == MS_EXTEND) && + (out_msg.msg_len == MS_SDTR_LEN) && + (out_msg.msg_req == MS_SDTR_CODE)) { + + asc_dvc->init_sdtr &= ~target_id; + asc_dvc->sdtr_done &= ~target_id; + AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); + + } else { + + } + + q_cntl &= ~QC_MSG_OUT; + AscWriteLramByte(iop_base, + (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), + q_cntl); + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return (0); + } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) { + + scsi_status = AscReadLramByte(iop_base, + (ushort) ((ushort) halt_q_addr + (ushort) ASC_SCSIQ_SCSI_STATUS)); + cur_dvc_qng = AscReadLramByte(iop_base, + (ushort) ((ushort) ASC_QADR_BEG + (ushort) target_ix)); + if ((cur_dvc_qng > 0) && + (asc_dvc->cur_dvc_qng[tid_no] > 0)) { + + scsi_busy = AscReadLramByte(iop_base, + (ushort) ASCV_SCSIBUSY_B); + scsi_busy |= target_id; + AscWriteLramByte(iop_base, + (ushort) ASCV_SCSIBUSY_B, scsi_busy); + asc_dvc->queue_full_or_busy |= target_id; + + if (scsi_status == SS_QUEUE_FULL) { + if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) { + cur_dvc_qng -= 1; + asc_dvc->max_dvc_qng[tid_no] = cur_dvc_qng; + + AscWriteLramByte(iop_base, + (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) tid_no), + cur_dvc_qng); + } + } + } + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return (0); + } + return (0); +} + +uchar +_AscCopyLramScsiDoneQ( + PortAddr iop_base, + ushort q_addr, + ASC_QDONE_INFO dosfar * scsiq, + ulong max_dma_count +) +{ + ushort _val; + uchar sg_queue_cnt; + + DvcGetQinfo(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_DONE_INFO_BEG), + (ushort dosfar *) scsiq, + (ushort) ((sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2)); + +#if !CC_LITTLE_ENDIAN_HOST + AscAdjEndianQDoneInfo(scsiq); +#endif + + _val = AscReadLramWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS)); + scsiq->q_status = (uchar) _val; + scsiq->q_no = (uchar) (_val >> 8); + + _val = AscReadLramWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_CNTL)); + scsiq->cntl = (uchar) _val; + sg_queue_cnt = (uchar) (_val >> 8); + + _val = AscReadLramWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SENSE_LEN)); + scsiq->sense_len = (uchar) _val; + scsiq->user_def = (uchar) (_val >> 8); + + scsiq->remain_bytes = AscReadLramDWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT)); + scsiq->remain_bytes &= max_dma_count; + + return (sg_queue_cnt); +} + +int +AscIsrQDone( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + uchar next_qp; + uchar i; + uchar n_q_used; + uchar sg_list_qp; + uchar sg_queue_cnt; + uchar done_q_tail; + + uchar tid_no; + ASC_SCSI_BIT_ID_TYPE scsi_busy; + ASC_SCSI_BIT_ID_TYPE target_id; + PortAddr iop_base; + ushort q_addr; + ushort sg_q_addr; + uchar cur_target_qng; + ASC_QDONE_INFO scsiq_buf; + ASC_QDONE_INFO dosfar *scsiq; + int false_overrun; + ASC_ISR_CALLBACK asc_isr_callback; + + uchar tag_code; + +#if CC_LINK_BUSY_Q + ushort n_busy_q_done; + +#endif + + iop_base = asc_dvc->iop_base; + asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; + + n_q_used = 1; + scsiq = (ASC_QDONE_INFO dosfar *) & scsiq_buf; + done_q_tail = (uchar) AscGetVarDoneQTail(iop_base); + q_addr = ASC_QNO_TO_QADDR(done_q_tail); + next_qp = AscReadLramByte(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_FWD)); + if (next_qp != ASC_QLINK_END) { + + AscPutVarDoneQTail(iop_base, next_qp); + q_addr = ASC_QNO_TO_QADDR(next_qp); + + sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count); + + AscWriteLramByte(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), + (uchar) (scsiq->q_status & (uchar) ~ (QS_READY | QS_ABORTED))); + tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix); + target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix); + if ((scsiq->cntl & QC_SG_HEAD) != 0) { + sg_q_addr = q_addr; + sg_list_qp = next_qp; + for (i = 0; i < sg_queue_cnt; i++) { + sg_list_qp = AscReadLramByte(iop_base, + (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_FWD)); + sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp); + if (sg_list_qp == ASC_QLINK_END) { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_Q_LINKS); + scsiq->d3.done_stat = QD_WITH_ERROR; + scsiq->d3.host_stat = QHSTA_D_QDONE_SG_LIST_CORRUPTED; + goto FATAL_ERR_QDONE; + } + AscWriteLramByte(iop_base, + (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_STATUS), + QS_FREE); + } + + n_q_used = sg_queue_cnt + 1; + AscPutVarDoneQTail(iop_base, sg_list_qp); + } + if (asc_dvc->queue_full_or_busy & target_id) { + + cur_target_qng = AscReadLramByte(iop_base, + (ushort) ((ushort) ASC_QADR_BEG + (ushort) scsiq->d2.target_ix)); + if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) { + scsi_busy = AscReadLramByte(iop_base, + (ushort) ASCV_SCSIBUSY_B); + scsi_busy &= ~target_id; + AscWriteLramByte(iop_base, + (ushort) ASCV_SCSIBUSY_B, scsi_busy); + asc_dvc->queue_full_or_busy &= ~target_id; + } + } + if (asc_dvc->cur_total_qng >= n_q_used) { + asc_dvc->cur_total_qng -= n_q_used; + if (asc_dvc->cur_dvc_qng[tid_no] != 0) { + asc_dvc->cur_dvc_qng[tid_no]--; + } + } else { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG); + scsiq->d3.done_stat = QD_WITH_ERROR; + goto FATAL_ERR_QDONE; + } + + if ((scsiq->d2.srb_ptr == 0UL) || + ((scsiq->q_status & QS_ABORTED) != 0)) { + + return (0x11); + } else if (scsiq->q_status == QS_DONE) { + + false_overrun = FALSE; + + if (asc_dvc->bug_fix_cntl) { + if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ADD_ONE_BYTE) { + tag_code = AscReadLramByte(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE)); + if (tag_code & ASC_TAG_FLAG_ADD_ONE_BYTE) { + if (scsiq->remain_bytes != 0UL) { + scsiq->remain_bytes--; + if (scsiq->remain_bytes == 0UL) { + false_overrun = TRUE; + } + } + } + } + } + if ((scsiq->d3.done_stat == QD_WITH_ERROR) && + (scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN)) { + if ((scsiq->cntl & (QC_DATA_IN | QC_DATA_OUT)) == 0) { + scsiq->d3.done_stat = QD_NO_ERROR; + scsiq->d3.host_stat = QHSTA_NO_ERROR; + } else if (false_overrun) { + scsiq->d3.done_stat = QD_NO_ERROR; + scsiq->d3.host_stat = QHSTA_NO_ERROR; + } + } +#if CC_CLEAR_LRAM_SRB_PTR + AscWriteLramDWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), + asc_dvc->int_count); +#endif + + if ((scsiq->cntl & QC_NO_CALLBACK) == 0) { + (*asc_isr_callback) (asc_dvc, scsiq); + } else { + if ((AscReadLramByte(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG)) == + SCSICMD_StartStopUnit)) { + + asc_dvc->unit_not_ready &= ~target_id; + if (scsiq->d3.done_stat != QD_NO_ERROR) { + asc_dvc->start_motor &= ~target_id; + } + } + } + +#if CC_LINK_BUSY_Q + n_busy_q_done = AscIsrExeBusyQueue(asc_dvc, tid_no); + if (n_busy_q_done == 0) { + + i = tid_no + 1; + while (TRUE) { + if (i > ASC_MAX_TID) + i = 0; + if (i == tid_no) + break; + n_busy_q_done = AscIsrExeBusyQueue(asc_dvc, i); + if (n_busy_q_done != 0) + break; + i++; + } + } + if (n_busy_q_done == 0xFFFF) + return (0x80); +#endif + + return (1); + } else { + + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS); + + FATAL_ERR_QDONE: + if ((scsiq->cntl & QC_NO_CALLBACK) == 0) { + (*asc_isr_callback) (asc_dvc, scsiq); + } + return (0x80); + } + } + return (0); +} + +int +AscISR( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + ASC_CS_TYPE chipstat; + PortAddr iop_base; + ushort saved_ram_addr; + uchar ctrl_reg; + uchar saved_ctrl_reg; + int int_pending; + int status; + uchar host_flag; + + iop_base = asc_dvc->iop_base; + int_pending = FALSE; + + asc_dvc->int_count++; + + if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) || + (asc_dvc->isr_callback == 0)) { + + return (ERR); + } + if (asc_dvc->in_critical_cnt != 0) { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL); + return (ERR); + } + if (asc_dvc->is_in_int) { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY); + asc_dvc->busy_count++; + return (ERR); + } + asc_dvc->is_in_int = TRUE; + ctrl_reg = AscGetChipControl(iop_base); + saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET | + CC_SINGLE_STEP | CC_DIAG | CC_TEST)); + + if ((chipstat = AscGetChipStatus(iop_base)) & CSW_INT_PENDING) { + int_pending = TRUE; + AscAckInterrupt(iop_base); + + host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B); + AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, + (uchar) (host_flag | (uchar) ASC_HOST_FLAG_IN_ISR)); + saved_ram_addr = AscGetChipLramAddr(iop_base); + + if ((chipstat & CSW_HALTED) && + (ctrl_reg & CC_SINGLE_STEP)) { + if (AscIsrChipHalted(asc_dvc) == ERR) { + + goto ISR_REPORT_QDONE_FATAL_ERROR; + + } else { + saved_ctrl_reg &= ~CC_HALT; + } + } else { + ISR_REPORT_QDONE_FATAL_ERROR: + if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) { + while (((status = AscIsrQDone(asc_dvc)) & 0x01) != 0) { + + } + } else { + do { + if ((status = AscIsrQDone(asc_dvc)) == 1) { + + break; + } + } while (status == 0x11); + } + if ((status & 0x80) != 0) + int_pending = ERR; + } + AscSetChipLramAddr(iop_base, saved_ram_addr); + if (AscGetChipLramAddr(iop_base) != saved_ram_addr) { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SET_LRAM_ADDR); + } + AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); + } + AscSetChipControl(iop_base, saved_ctrl_reg); + asc_dvc->is_in_int = FALSE; + return (int_pending); +} + +int +AscScsiSetupCmdQ( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_REQ_Q dosfar * scsiq, + uchar dosfar * buf_addr, + ulong buf_len +) +{ + ulong phy_addr; + + scsiq->r1.cntl = 0; + scsiq->r1.sg_queue_cnt = 0; + scsiq->r1.q_no = 0; + scsiq->r1.user_def = 0; + scsiq->cdbptr = (uchar dosfar *) scsiq->cdb; + scsiq->r3.scsi_stat = 0; + scsiq->r3.scsi_msg = 0; + scsiq->r3.host_stat = 0; + scsiq->r3.done_stat = 0; + scsiq->r2.vm_id = 0; + scsiq->r1.data_cnt = buf_len; + + scsiq->r2.tag_code = (uchar) M2_QTAG_MSG_SIMPLE; + scsiq->r2.flag = (uchar) ASC_FLAG_SCSIQ_REQ; + scsiq->r2.srb_ptr = (ulong) scsiq; + scsiq->r1.status = (uchar) QS_READY; + scsiq->r1.data_addr = 0L; + + if (buf_len != 0L) { + if ((phy_addr = AscGetOnePhyAddr(asc_dvc, + (uchar dosfar *) buf_addr, scsiq->r1.data_cnt)) == 0L) { + return (ERR); + } + scsiq->r1.data_addr = phy_addr; + } + return (0); +} + +uchar _mcode_buf[] = +{ + 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 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, 0xDD, 0x0A, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x16, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x88, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC8, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40, + 0xB6, 0x00, 0x36, 0x00, 0x06, 0xD6, 0x0D, 0xD2, 0x15, 0xDE, 0x12, 0xDA, 0x00, 0xA2, 0xC8, 0x00, + 0x92, 0x80, 0xE0, 0x97, 0x50, 0x00, 0xF5, 0x00, 0x0A, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, + 0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00, 0x0A, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, + 0x80, 0x62, 0x92, 0x80, 0x00, 0x62, 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, 0x13, 0xEA, 0x02, 0x01, + 0x09, 0xD8, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDC, 0x00, 0x68, 0x97, 0x7F, 0x23, 0x04, 0x61, + 0x84, 0x01, 0xB2, 0x84, 0xCF, 0xC1, 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE8, 0x01, + 0x68, 0x97, 0xD4, 0x81, 0x00, 0x33, 0x02, 0x00, 0x82, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, + 0x01, 0xA1, 0x08, 0x01, 0x4F, 0x00, 0x46, 0x97, 0x07, 0xA6, 0x12, 0x01, 0x00, 0x33, 0x03, 0x00, + 0x82, 0x88, 0x03, 0x03, 0x03, 0xDE, 0x00, 0x33, 0x05, 0x00, 0x82, 0x88, 0xCE, 0x00, 0x69, 0x60, + 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x86, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x32, 0x01, + 0x86, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, 0x42, 0x01, 0x00, 0x33, 0x04, 0x00, + 0x82, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23, 0x2A, 0x98, 0x4D, 0x04, 0xD0, 0x84, + 0x05, 0xD8, 0x0D, 0x23, 0x2A, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xB8, 0x88, 0xFB, 0x23, 0x02, 0x61, + 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x70, 0x01, 0x00, 0x33, 0x0A, 0x00, 0x82, 0x88, + 0x4E, 0x00, 0x07, 0xA3, 0x7C, 0x01, 0x00, 0x33, 0x0B, 0x00, 0x82, 0x88, 0xCD, 0x04, 0x36, 0x2D, + 0x00, 0x33, 0x1A, 0x00, 0x82, 0x88, 0x50, 0x04, 0x96, 0x81, 0x06, 0xAB, 0x90, 0x01, 0x96, 0x81, + 0x4E, 0x00, 0x07, 0xA3, 0xA0, 0x01, 0x50, 0x00, 0x00, 0xA3, 0x4A, 0x01, 0x00, 0x05, 0x8A, 0x81, + 0x08, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xCC, 0x81, + 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xC2, 0x01, + 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00, 0x82, 0x88, 0x06, 0x23, 0x2A, 0x98, + 0xCD, 0x04, 0xB2, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xE2, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE8, 0x01, + 0xB2, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xB2, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, + 0x10, 0x02, 0x04, 0x01, 0x0D, 0xDE, 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x46, 0x97, 0x0A, 0x82, + 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x24, 0x97, 0x48, 0x04, 0xFF, 0x23, 0x84, 0x80, + 0xB2, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, + 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x66, 0xEB, 0x11, 0x23, 0xB8, 0x88, 0xC6, 0x97, 0xFA, 0x80, + 0x80, 0x73, 0x80, 0x77, 0x06, 0xA6, 0x3E, 0x02, 0x00, 0x33, 0x31, 0x00, 0x82, 0x88, 0x04, 0x01, + 0x03, 0xD8, 0x74, 0x98, 0x02, 0x96, 0x50, 0x82, 0xA2, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, + 0xB6, 0x2D, 0x02, 0xA6, 0x7A, 0x02, 0x07, 0xA6, 0x68, 0x02, 0x06, 0xA6, 0x6C, 0x02, 0x03, 0xA6, + 0x70, 0x02, 0x00, 0x33, 0x10, 0x00, 0x82, 0x88, 0x4A, 0x95, 0x52, 0x82, 0xF8, 0x95, 0x52, 0x82, + 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x16, 0x84, 0x04, 0x01, 0x0C, 0xDC, 0xE0, 0x23, + 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, + 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAC, 0x02, 0x07, 0xA6, + 0x68, 0x02, 0x06, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x12, 0x00, 0x82, 0x88, 0x00, 0x0E, 0x80, 0x63, + 0x00, 0x43, 0x00, 0xA0, 0x9A, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, + 0x84, 0x01, 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, + 0xEC, 0x82, 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE4, 0x02, 0x04, 0x01, 0x8E, 0xC8, 0x00, 0x33, + 0x1F, 0x00, 0x82, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x40, 0x98, 0xB6, 0x2D, + 0x01, 0xA6, 0x0E, 0x03, 0x00, 0xA6, 0x1C, 0x03, 0x07, 0xA6, 0x2A, 0x03, 0x06, 0xA6, 0x2E, 0x03, + 0x03, 0xA6, 0xFA, 0x03, 0x02, 0xA6, 0x7A, 0x02, 0x00, 0x33, 0x33, 0x00, 0x82, 0x88, 0x08, 0x23, + 0xB3, 0x01, 0x04, 0x01, 0x0E, 0xD0, 0x00, 0x33, 0x14, 0x00, 0x82, 0x88, 0x10, 0x23, 0xB3, 0x01, + 0x04, 0x01, 0x07, 0xCC, 0x00, 0x33, 0x15, 0x00, 0x82, 0x88, 0x4A, 0x95, 0xF0, 0x82, 0xF8, 0x95, + 0xF0, 0x82, 0x44, 0x98, 0x80, 0x42, 0x40, 0x98, 0x48, 0xE4, 0x04, 0x01, 0x29, 0xC8, 0x31, 0x05, + 0x07, 0x01, 0x00, 0xA2, 0x72, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x48, 0x98, 0x40, 0x98, + 0x00, 0xA6, 0x34, 0x03, 0x07, 0xA6, 0x6A, 0x03, 0x03, 0xA6, 0x16, 0x04, 0x06, 0xA6, 0x6E, 0x03, + 0x01, 0xA6, 0x34, 0x03, 0x00, 0x33, 0x25, 0x00, 0x82, 0x88, 0x4A, 0x95, 0x50, 0x83, 0xF8, 0x95, + 0x50, 0x83, 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, 0x00, 0x33, 0x42, 0x00, 0x82, 0x88, 0x00, 0x01, + 0x05, 0x05, 0xFF, 0xA2, 0x90, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x4C, 0x83, 0x05, 0x05, + 0x01, 0xA6, 0x9A, 0x03, 0x00, 0xA6, 0xAA, 0x03, 0xF0, 0x83, 0x68, 0x98, 0x80, 0x42, 0x01, 0xA6, + 0x9A, 0x03, 0xBA, 0x83, 0x00, 0x33, 0x2F, 0x00, 0x82, 0x88, 0x68, 0x98, 0x80, 0x42, 0x00, 0xA6, + 0xAA, 0x03, 0xBA, 0x83, 0x00, 0x33, 0x26, 0x00, 0x82, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, + 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0xF0, 0x83, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, + 0x20, 0x00, 0x82, 0x88, 0x03, 0xA6, 0xEE, 0x03, 0x07, 0xA6, 0xE6, 0x03, 0x06, 0xA6, 0xEA, 0x03, + 0x00, 0x33, 0x17, 0x00, 0x82, 0x88, 0x4A, 0x95, 0xD4, 0x83, 0xF8, 0x95, 0xD4, 0x83, 0xFA, 0x83, + 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00, 0x82, 0x88, 0xB6, 0x2D, 0x03, 0xA6, 0x16, 0x04, + 0x07, 0xA6, 0x0E, 0x04, 0x06, 0xA6, 0x12, 0x04, 0x00, 0x33, 0x30, 0x00, 0x82, 0x88, 0x4A, 0x95, + 0xFA, 0x83, 0xF8, 0x95, 0xFA, 0x83, 0xA2, 0x0D, 0x80, 0x63, 0x07, 0xA6, 0x24, 0x04, 0x00, 0x33, + 0x18, 0x00, 0x82, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x2E, 0x04, 0x23, 0x01, + 0x00, 0xA2, 0x50, 0x04, 0x0A, 0xA0, 0x40, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00, 0x82, 0x88, + 0x0B, 0xA0, 0x4C, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, 0x82, 0x88, 0x42, 0x23, 0xB8, 0x88, + 0x00, 0x23, 0x22, 0xA3, 0xB2, 0x04, 0x08, 0x23, 0x22, 0xA3, 0x6C, 0x04, 0x28, 0x23, 0x22, 0xA3, + 0x78, 0x04, 0x02, 0x23, 0x22, 0xA3, 0x8E, 0x04, 0x42, 0x23, 0xB8, 0x88, 0x4A, 0x00, 0x06, 0x61, + 0x00, 0xA0, 0x78, 0x04, 0x45, 0x23, 0xB8, 0x88, 0xC6, 0x97, 0x00, 0xA2, 0x8A, 0x04, 0x74, 0x98, + 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xF6, 0x81, 0x47, 0x23, 0xB8, 0x88, 0x04, 0x01, + 0x0C, 0xDE, 0x14, 0x01, 0x00, 0xA2, 0xA6, 0x04, 0xC6, 0x97, 0x74, 0x98, 0x00, 0x33, 0x00, 0x81, + 0xC0, 0x20, 0x81, 0x62, 0x10, 0x82, 0x43, 0x23, 0xB8, 0x88, 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23, + 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xC0, 0x04, 0x00, 0x33, 0x27, 0x00, 0x82, 0x88, + 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xC6, 0x97, 0xF4, 0x94, + 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0xEE, 0x04, 0x00, 0x05, 0x76, 0x00, + 0x06, 0x61, 0x00, 0xA2, 0xE8, 0x04, 0xD6, 0x84, 0x08, 0x97, 0xCD, 0x04, 0xF2, 0x84, 0x48, 0x04, + 0xFF, 0x23, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x02, 0x85, 0x02, 0x23, + 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x0E, 0x05, 0x1D, 0x01, 0x04, 0xD6, 0xFF, 0x23, + 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x49, 0x00, 0x81, 0x01, 0x04, 0x01, + 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00, + 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x2E, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, 0x5D, 0x00, + 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xA0, 0x05, 0x03, 0x03, + 0x02, 0xA0, 0x5C, 0x05, 0x9C, 0x85, 0x00, 0x33, 0x2D, 0x00, 0x82, 0x88, 0x04, 0xA0, 0x82, 0x05, + 0x80, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x6E, 0x05, 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, + 0x02, 0x41, 0x82, 0x01, 0x50, 0x00, 0x24, 0x97, 0xD0, 0x84, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, + 0xD0, 0x84, 0x08, 0xA0, 0x88, 0x05, 0x9C, 0x85, 0x03, 0xA0, 0x8E, 0x05, 0x9C, 0x85, 0x01, 0xA0, + 0x9A, 0x05, 0x88, 0x00, 0x80, 0x63, 0x78, 0x96, 0x4A, 0x85, 0x88, 0x86, 0x80, 0x63, 0x4A, 0x85, + 0x00, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xDE, 0x05, 0x1D, 0x01, 0x18, 0xD4, 0xC0, 0x23, + 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0xC0, 0x05, 0x00, 0x33, 0x37, 0x00, 0x82, 0x88, + 0x1D, 0x01, 0x02, 0xD6, 0x46, 0x23, 0xB8, 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, + 0xD8, 0x05, 0x00, 0x33, 0x38, 0x00, 0x82, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, + 0x06, 0x41, 0xCB, 0x00, 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xF2, 0x05, 0xC0, 0x23, 0x07, 0x41, + 0x00, 0x63, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63, 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, + 0x00, 0x63, 0x06, 0xA6, 0x14, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x02, 0xA6, 0xBC, 0x06, 0x00, 0x33, + 0x39, 0x00, 0x82, 0x88, 0x00, 0x00, 0x01, 0xA0, 0xD6, 0x06, 0xA2, 0x95, 0x83, 0x03, 0x80, 0x63, + 0x06, 0xA6, 0x28, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x00, 0x00, 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63, + 0x01, 0x00, 0x06, 0xA6, 0x40, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x00, 0x33, 0x3A, 0x00, 0x82, 0x88, + 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x32, 0x06, 0x06, 0xA6, 0x58, 0x06, 0x07, 0xA6, + 0x64, 0x06, 0x00, 0x33, 0x3B, 0x00, 0x82, 0x88, 0x80, 0x67, 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6, + 0x64, 0x06, 0x00, 0x63, 0x03, 0x03, 0x80, 0x63, 0x88, 0x00, 0x01, 0xA2, 0x78, 0x06, 0x07, 0xA2, + 0xBC, 0x06, 0x00, 0x33, 0x35, 0x00, 0x82, 0x88, 0x07, 0xA6, 0x82, 0x06, 0x00, 0x33, 0x2A, 0x00, + 0x82, 0x88, 0x03, 0x03, 0x03, 0xA2, 0x8E, 0x06, 0x07, 0x23, 0x80, 0x00, 0xC8, 0x86, 0x80, 0x63, + 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0x9E, 0x06, 0x00, 0x33, 0x29, 0x00, 0x82, 0x88, 0x00, 0x43, + 0x00, 0xA2, 0xAA, 0x06, 0xC0, 0x0E, 0x80, 0x63, 0x94, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, + 0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x08, 0xDA, 0x80, 0x63, 0x00, 0x63, 0x80, 0x67, 0x00, 0x33, + 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x20, 0x06, + 0x00, 0x33, 0x2C, 0x00, 0x82, 0x88, 0x0C, 0xA2, 0xF0, 0x06, 0xA2, 0x95, 0x83, 0x03, 0x80, 0x63, + 0x06, 0xA6, 0xEE, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x00, 0x33, 0x3D, 0x00, 0x82, 0x88, 0x00, 0x00, + 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x06, 0x07, 0x07, 0xA6, 0x64, 0x06, 0xBF, 0x23, + 0x04, 0x61, 0x84, 0x01, 0xB2, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, + 0xF2, 0x00, 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, 0x80, 0x05, + 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, + 0x81, 0x01, 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, + 0x80, 0x01, 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, 0xF1, 0x00, + 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, + 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, + 0xA2, 0x01, 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, 0x86, 0x07, + 0x00, 0x33, 0x07, 0x00, 0x82, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, + 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, + 0xA6, 0x07, 0x00, 0x05, 0x9C, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x05, 0x05, + 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, + 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, + 0x00, 0xA0, 0xD6, 0x07, 0xD8, 0x87, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, + 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, + 0x06, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0xE6, 0x07, + 0xC6, 0x97, 0xF4, 0x94, 0xE6, 0x87, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x1C, 0x88, + 0x02, 0x01, 0x04, 0xD8, 0x08, 0x97, 0xC6, 0x97, 0xF4, 0x94, 0x0C, 0x88, 0x75, 0x00, 0x00, 0xA3, + 0x26, 0x08, 0x00, 0x05, 0x10, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, + 0x38, 0x08, 0x00, 0x33, 0x3E, 0x00, 0x82, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, + 0x38, 0x2B, 0x5E, 0x88, 0x38, 0x2B, 0x54, 0x88, 0x32, 0x09, 0x31, 0x05, 0x54, 0x98, 0x05, 0x05, + 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, + 0x80, 0x36, 0x80, 0x3A, 0x80, 0x3E, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A, + 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0x74, 0x08, 0x5D, 0x00, 0xFE, 0xC3, + 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, + 0x13, 0x23, 0xB8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01, + 0x81, 0x62, 0xA2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, + 0xF1, 0xC7, 0x41, 0x23, 0xB8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xB2, 0x84, + +}; + +ushort _mcode_size = sizeof (_mcode_buf); +ulong _mcode_chksum = 0x012258FBUL; + +extern uchar _sdtr_period_tbl_[]; + +int +AscExeScsiQueue( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_Q dosfar * scsiq +) +{ + PortAddr iop_base; + int last_int_level; + int sta; + ulong addr; + uchar sg_entry_cnt; + uchar target_ix; + int n_q_required; + uchar sg_entry_cnt_minus_one; + uchar tid_no; + uchar sdtr_data; + ASC_EXE_CALLBACK asc_exe_callback; + +#if CC_DEBUG_SG_LIST + int i; + +#endif +#if CC_LINK_BUSY_Q + ASC_SCSI_Q dosfar *scsiq_tail; + ASC_SCSI_Q dosfar *scsiq_next; + ASC_SCSI_Q dosfar *scsiq_prev; + +#endif + + iop_base = asc_dvc->iop_base; + asc_exe_callback = (ASC_EXE_CALLBACK) asc_dvc->exe_callback; + if (asc_dvc->err_code != 0) + return (ERR); + if (scsiq == (ASC_SCSI_Q dosfar *) 0L) { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR); + return (ERR); + } + scsiq->q1.q_no = 0; + sta = 0; + target_ix = scsiq->q2.target_ix; + tid_no = ASC_TIX_TO_TID(target_ix); + + n_q_required = 1; + + if (scsiq->cdbptr[0] == SCSICMD_RequestSense) { + + if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) && + ((asc_dvc->sdtr_done & scsiq->q1.target_id) != 0)) { + sdtr_data = AscReadLramByte(iop_base, + (ushort) ((ushort) ASCV_SDTR_DATA_BEG + (ushort) tid_no)); + AscMsgOutSDTR(iop_base, + _sdtr_period_tbl_[(sdtr_data >> 4) & (uchar) (ASC_SYN_XFER_NO - 1)], + (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET)); + scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT); + } + } + last_int_level = DvcEnterCritical(); + if (asc_dvc->in_critical_cnt != 0) { + DvcLeaveCritical(last_int_level); + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY); + return (ERR); + } + asc_dvc->in_critical_cnt++; + + if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { + + if ((sg_entry_cnt = scsiq->sg_head->entry_cnt) == 0) { + asc_dvc->in_critical_cnt--; + DvcLeaveCritical(last_int_level); + return (ERR); + } + if (sg_entry_cnt == 1) { + scsiq->q1.data_addr = scsiq->sg_head->sg_list[0].addr; + scsiq->q1.data_cnt = scsiq->sg_head->sg_list[0].bytes; + scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE); + goto NON_SG_LIST_REQ; + } + if (sg_entry_cnt > ASC_MAX_SG_LIST) { + + return (ERR); + } + sg_entry_cnt_minus_one = sg_entry_cnt - 1; + +#if CC_DEBUG_SG_LIST + if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) { + for (i = 0; i < sg_entry_cnt_minus_one; i++) { + + addr = scsiq->sg_head->sg_list[i].addr + + scsiq->sg_head->sg_list[i].bytes; + + if (((ushort) addr & 0x0003) != 0) { + asc_dvc->in_critical_cnt--; + DvcLeaveCritical(last_int_level); + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_LIST_ODD_ADDRESS); + return (ERR); + } + } + } +#endif + + if (asc_dvc->bug_fix_cntl) { + if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ADD_ONE_BYTE) { + + addr = scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].addr + + scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes; + if (((ushort) addr & 0x0003) != 0) { + if ((scsiq->cdbptr[0] == SCSICMD_Read6) || + (scsiq->cdbptr[0] == SCSICMD_Read10)) { + if ((scsiq->q2.tag_code & ASC_TAG_FLAG_ADD_ONE_BYTE) == 0) { + + scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes++; + scsiq->q2.tag_code |= ASC_TAG_FLAG_ADD_ONE_BYTE; + } + } + } + } + } + scsiq->sg_head->entry_to_copy = scsiq->sg_head->entry_cnt; + n_q_required = AscSgListToQueue(sg_entry_cnt); + +#if CC_LINK_BUSY_Q + scsiq_next = (ASC_SCSI_Q dosfar *) asc_dvc->scsiq_busy_head[tid_no]; + if (scsiq_next != (ASC_SCSI_Q dosfar *) 0L) { + goto link_scisq_to_busy_list; + } +#endif + + if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) + >= (uint) n_q_required) || + ((scsiq->q1.cntl & QC_URGENT) != 0)) { + if ((sta = AscSendScsiQueue(asc_dvc, scsiq, + n_q_required)) == 1) { + + asc_dvc->in_critical_cnt--; + if (asc_exe_callback != 0) { + (*asc_exe_callback) (asc_dvc, scsiq); + } + DvcLeaveCritical(last_int_level); + return (sta); + } + } + } else { + + NON_SG_LIST_REQ: + + if (asc_dvc->bug_fix_cntl) { + if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ADD_ONE_BYTE) { + + addr = scsiq->q1.data_addr + scsiq->q1.data_cnt; + if ((scsiq->cdbptr[0] == SCSICMD_Read6) || + (scsiq->cdbptr[0] == SCSICMD_Read10)) { + if (((ushort) addr & 0x0003) != 0) { + if (((ushort) scsiq->q1.data_cnt & 0x01FF) == 0) { + + if ((scsiq->q2.tag_code & ASC_TAG_FLAG_ADD_ONE_BYTE) == 0) { + + scsiq->q2.tag_code |= ASC_TAG_FLAG_ADD_ONE_BYTE; + scsiq->q1.data_cnt++; + } + } + } + } + } + } + n_q_required = 1; + +#if CC_LINK_BUSY_Q + scsiq_next = (ASC_SCSI_Q dosfar *) asc_dvc->scsiq_busy_head[tid_no]; + if (scsiq_next != (ASC_SCSI_Q dosfar *) 0L) { + goto link_scisq_to_busy_list; + } +#endif + if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) || + ((scsiq->q1.cntl & QC_URGENT) != 0)) { + if ((sta = AscSendScsiQueue(asc_dvc, scsiq, + n_q_required)) == 1) { + + asc_dvc->in_critical_cnt--; + if (asc_exe_callback != 0) { + (*asc_exe_callback) (asc_dvc, scsiq); + } + DvcLeaveCritical(last_int_level); + return (sta); + } + } + } + +#if CC_LINK_BUSY_Q + if (sta == 0) { + + link_scisq_to_busy_list: + scsiq->ext.q_required = n_q_required; + if (scsiq_next == (ASC_SCSI_Q dosfar *) 0L) { + asc_dvc->scsiq_busy_head[tid_no] = (ASC_SCSI_Q dosfar *) scsiq; + asc_dvc->scsiq_busy_tail[tid_no] = (ASC_SCSI_Q dosfar *) scsiq; + scsiq->ext.next = (ASC_SCSI_Q dosfar *) 0L; + scsiq->ext.join = (ASC_SCSI_Q dosfar *) 0L; + scsiq->q1.status = QS_BUSY; + sta = 1; + } else { + scsiq_tail = (ASC_SCSI_Q dosfar *) asc_dvc->scsiq_busy_tail[tid_no]; + if (scsiq_tail->ext.next == (ASC_SCSI_Q dosfar *) 0L) { + if ((scsiq->q1.cntl & QC_URGENT) != 0) { + + asc_dvc->scsiq_busy_head[tid_no] = (ASC_SCSI_Q dosfar *) scsiq; + scsiq->ext.next = scsiq_next; + scsiq->ext.join = (ASC_SCSI_Q dosfar *) 0L; + } else { + if (scsiq->ext.cntl & QCX_SORT) { + do { + scsiq_prev = scsiq_next; + scsiq_next = scsiq_next->ext.next; + if (scsiq->ext.lba < scsiq_prev->ext.lba) + break; + } while (scsiq_next != (ASC_SCSI_Q dosfar *) 0L); + + scsiq_prev->ext.next = scsiq; + scsiq->ext.next = scsiq_next; + if (scsiq_next == (ASC_SCSI_Q dosfar *) 0L) { + asc_dvc->scsiq_busy_tail[tid_no] = (ASC_SCSI_Q dosfar *) scsiq; + } + scsiq->ext.join = (ASC_SCSI_Q dosfar *) 0L; + } else { + + scsiq_tail->ext.next = (ASC_SCSI_Q dosfar *) scsiq; + asc_dvc->scsiq_busy_tail[tid_no] = (ASC_SCSI_Q dosfar *) scsiq; + scsiq->ext.next = (ASC_SCSI_Q dosfar *) 0L; + scsiq->ext.join = (ASC_SCSI_Q dosfar *) 0L; + } + } + scsiq->q1.status = QS_BUSY; + sta = 1; + } else { + + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_BAD_NEXT_PTR); + sta = ERR; + } + } + } +#endif + asc_dvc->in_critical_cnt--; + DvcLeaveCritical(last_int_level); + return (sta); +} + +int +AscSendScsiQueue( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_Q dosfar * scsiq, + uchar n_q_required +) +{ + PortAddr iop_base; + uchar free_q_head; + uchar next_qp; + uchar tid_no; + uchar target_ix; + int sta; + + iop_base = asc_dvc->iop_base; + target_ix = scsiq->q2.target_ix; + tid_no = ASC_TIX_TO_TID(target_ix); + sta = 0; + free_q_head = (uchar) AscGetVarFreeQHead(iop_base); + if (n_q_required > 1) { + if ((next_qp = AscAllocMultipleFreeQueue(iop_base, + free_q_head, (uchar) (n_q_required))) + != (uchar) ASC_QLINK_END) { + asc_dvc->last_q_shortage = 0; + scsiq->sg_head->queue_cnt = n_q_required - 1; + scsiq->q1.q_no = free_q_head; + + if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq, + free_q_head)) == 1) { + +#if CC_WRITE_IO_COUNT + asc_dvc->req_count++; +#endif + + AscPutVarFreeQHead(iop_base, next_qp); + asc_dvc->cur_total_qng += (uchar) (n_q_required); + asc_dvc->cur_dvc_qng[tid_no]++; + } + return (sta); + } + } else if (n_q_required == 1) { + + if ((next_qp = AscAllocFreeQueue(iop_base, + free_q_head)) != ASC_QLINK_END) { + + scsiq->q1.q_no = free_q_head; + if ((sta = AscPutReadyQueue(asc_dvc, scsiq, + free_q_head)) == 1) { + +#if CC_WRITE_IO_COUNT + asc_dvc->req_count++; +#endif + + AscPutVarFreeQHead(iop_base, next_qp); + asc_dvc->cur_total_qng++; + asc_dvc->cur_dvc_qng[tid_no]++; + } + return (sta); + } + } + return (sta); +} + +int +AscSgListToQueue( + int sg_list +) +{ + int n_sg_list_qs; + + n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q); + if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0) + n_sg_list_qs++; + return (n_sg_list_qs + 1); +} + +uint +AscGetNumOfFreeQueue( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + uchar target_ix, uchar n_qs +) +{ + uint cur_used_qs; + uint cur_free_qs; + ASC_SCSI_BIT_ID_TYPE target_id; + uchar tid_no; + + target_id = ASC_TIX_TO_TARGET_ID(target_ix); + tid_no = ASC_TIX_TO_TID(target_ix); + if ((asc_dvc->unit_not_ready & target_id) || + (asc_dvc->queue_full_or_busy & target_id)) { + return (0); + } + if (n_qs == 1) { + cur_used_qs = (uint) asc_dvc->cur_total_qng + + (uint) asc_dvc->last_q_shortage + + (uint) ASC_MIN_FREE_Q; + } else { + cur_used_qs = (uint) asc_dvc->cur_total_qng + + (uint) ASC_MIN_FREE_Q; + } + + if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) { + cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs; + if (asc_dvc->cur_dvc_qng[tid_no] >= + asc_dvc->max_dvc_qng[tid_no]) { + return (0); + } + return (cur_free_qs); + } + if (n_qs > 1) { + if (n_qs > asc_dvc->last_q_shortage) { + asc_dvc->last_q_shortage = n_qs; + } + } + return (0); +} + +int +AscPutReadyQueue( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_Q dosfar * scsiq, + uchar q_no +) +{ + ushort q_addr; + uchar tid_no; + uchar sdtr_data; + uchar syn_period_ix; + uchar syn_offset; + PortAddr iop_base; + + iop_base = asc_dvc->iop_base; + + if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) && + ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) { + + tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix); + + sdtr_data = AscReadLramByte(iop_base, + (ushort) ((ushort) ASCV_SDTR_DATA_BEG + (ushort) tid_no)); + syn_period_ix = (sdtr_data >> 4) & (ASC_SYN_XFER_NO - 1); + syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET; + AscMsgOutSDTR(iop_base, + _sdtr_period_tbl_[syn_period_ix], + syn_offset); + + scsiq->q1.cntl |= QC_MSG_OUT; + } + q_addr = ASC_QNO_TO_QADDR(q_no); + + if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) { + scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE; + } + scsiq->q1.status = QS_FREE; + + AscMemWordCopyToLram(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG), + (ushort dosfar *) scsiq->cdbptr, + (ushort) ((ushort) scsiq->q2.cdb_len >> 1)); + +#if !CC_LITTLE_ENDIAN_HOST + AscAdjEndianScsiQ(scsiq); +#endif + + DvcPutScsiQ(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG), + (ushort dosfar *) & scsiq->q1.cntl, + (ushort) ((((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1))); + +#if CC_WRITE_IO_COUNT + AscWriteLramWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_W_REQ_COUNT), + (ushort) asc_dvc->req_count); + +#endif + +#if CC_VERIFY_LRAM_COPY + if ((asc_dvc->dvc_cntl & ASC_CNTL_NO_VERIFY_COPY) == 0) { + + if (AscMemWordCmpToLram(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG), + (ushort dosfar *) scsiq->cdbptr, + (ushort) (scsiq->q2.cdb_len >> 1)) != 0) { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_LOCAL_MEM); + return (ERR); + } + if (AscMemWordCmpToLram(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG), + (ushort dosfar *) & scsiq->q1.cntl, + (ushort) (((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1)) + != 0) { + AscSetLibErrorCode(asc_dvc, ASCQ_ERR_LOCAL_MEM); + return (ERR); + } + } +#endif + +#if CC_CLEAR_DMA_REMAIN + + AscWriteLramDWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_ADDR), 0UL); + AscWriteLramDWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT), 0UL); + +#endif + + AscWriteLramWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), + (ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY)); + return (1); +} + +int +AscPutReadySgListQueue( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_Q dosfar * scsiq, + uchar q_no +) +{ + uchar sg_list_dwords; + uchar sg_index, i; + uchar sg_entry_cnt; + uchar next_qp; + ushort q_addr; + int sta; + ASC_SG_HEAD dosfar *sg_head; + ASC_SG_LIST_Q scsi_sg_q; + ulong saved_data_addr; + ulong saved_data_cnt; + PortAddr iop_base; + + iop_base = asc_dvc->iop_base; + + sg_head = scsiq->sg_head; + + saved_data_addr = scsiq->q1.data_addr; + saved_data_cnt = scsiq->q1.data_cnt; + scsiq->q1.data_addr = sg_head->sg_list[0].addr; + scsiq->q1.data_cnt = sg_head->sg_list[0].bytes; + sg_entry_cnt = sg_head->entry_cnt - 1; + if (sg_entry_cnt != 0) { + scsiq->q1.cntl |= QC_SG_HEAD; + q_addr = ASC_QNO_TO_QADDR(q_no); + sg_index = 1; + scsiq->q1.sg_queue_cnt = sg_head->queue_cnt; + scsi_sg_q.sg_head_qp = q_no; + scsi_sg_q.cntl = QCSG_SG_XFER_LIST; + for (i = 0; i < sg_head->queue_cnt; i++) { + scsi_sg_q.seq_no = i + 1; + if (sg_entry_cnt > ASC_SG_LIST_PER_Q) { + sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2); + sg_entry_cnt -= ASC_SG_LIST_PER_Q; + if (i == 0) { + scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q; + scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q; + } else { + scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1; + scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1; + } + } else { + + scsi_sg_q.cntl |= QCSG_SG_XFER_END; + sg_list_dwords = sg_entry_cnt << 1; + if (i == 0) { + scsi_sg_q.sg_list_cnt = sg_entry_cnt; + scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt; + } else { + scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1; + scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1; + } + sg_entry_cnt = 0; + } + next_qp = AscReadLramByte(iop_base, + (ushort) (q_addr + ASC_SCSIQ_B_FWD)); + scsi_sg_q.q_no = next_qp; + q_addr = ASC_QNO_TO_QADDR(next_qp); + + AscMemWordCopyToLram(iop_base, + (ushort) (q_addr + ASC_SCSIQ_SGHD_CPY_BEG), + (ushort dosfar *) & scsi_sg_q, + (ushort) (sizeof (ASC_SG_LIST_Q) >> 1)); + + AscMemDWordCopyToLram(iop_base, + (ushort) (q_addr + ASC_SGQ_LIST_BEG), + (ulong dosfar *) & sg_head->sg_list[sg_index], + (ushort) sg_list_dwords); + + sg_index += ASC_SG_LIST_PER_Q; + } + } else { + + scsiq->q1.cntl &= ~QC_SG_HEAD; + } + sta = AscPutReadyQueue(asc_dvc, scsiq, q_no); + + scsiq->q1.data_addr = saved_data_addr; + scsiq->q1.data_cnt = saved_data_cnt; + return (sta); +} + +int +AscAbortSRB( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ulong srb_ptr +) +{ + int sta; + ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready; + PortAddr iop_base; + + iop_base = asc_dvc->iop_base; + sta = ERR; + saved_unit_not_ready = asc_dvc->unit_not_ready; + asc_dvc->unit_not_ready = 0xFF; + AscWaitISRDone(asc_dvc); + if (AscStopQueueExe(iop_base) == 1) { + if (AscRiscHaltedAbortSRB(asc_dvc, srb_ptr) == 1) { + sta = 1; + AscCleanUpBusyQueue(iop_base); + AscStartQueueExe(iop_base); + + } else { + sta = 0; + AscStartQueueExe(iop_base); + } + } + asc_dvc->unit_not_ready = saved_unit_not_ready; + return (sta); +} + +int +AscResetDevice( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + uchar target_ix +) +{ + PortAddr iop_base; + int sta; + uchar tid_no; + ASC_SCSI_BIT_ID_TYPE target_id; + int i; + ASC_SCSI_REQ_Q scsiq_buf; + ASC_SCSI_REQ_Q dosfar *scsiq; + uchar dosfar *buf; + ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready; + + iop_base = asc_dvc->iop_base; + tid_no = ASC_TIX_TO_TID(target_ix); + target_id = ASC_TID_TO_TARGET_ID(tid_no); + saved_unit_not_ready = asc_dvc->unit_not_ready; + asc_dvc->unit_not_ready = target_id; + sta = ERR; + AscWaitTixISRDone(asc_dvc, target_ix); + if (AscStopQueueExe(iop_base) == 1) { + if (AscRiscHaltedAbortTIX(asc_dvc, target_ix) == 1) { + + AscCleanUpBusyQueue(iop_base); + AscStartQueueExe(iop_base); + + AscWaitTixISRDone(asc_dvc, target_ix); + + sta = TRUE; + scsiq = (ASC_SCSI_REQ_Q dosfar *) & scsiq_buf; + buf = (uchar dosfar *) & scsiq_buf; + for (i = 0; i < sizeof (ASC_SCSI_REQ_Q); i++) { + *buf++ = 0x00; + } + + scsiq->r1.status = (uchar) QS_READY; + scsiq->r2.cdb_len = 6; + scsiq->r2.tag_code = M2_QTAG_MSG_SIMPLE; + scsiq->r1.target_id = target_id; + + scsiq->r2.target_ix = ASC_TIDLUN_TO_IX(tid_no, 0); + scsiq->cdbptr = (uchar dosfar *) scsiq->cdb; + + scsiq->r1.cntl = QC_NO_CALLBACK | QC_MSG_OUT | QC_URGENT; + AscWriteLramByte(asc_dvc->iop_base, ASCV_MSGOUT_BEG, + M1_BUS_DVC_RESET); + + asc_dvc->unit_not_ready &= ~target_id; + + asc_dvc->sdtr_done |= target_id; + + if (AscExeScsiQueue(asc_dvc, (ASC_SCSI_Q dosfar *) scsiq) + == 1) { + asc_dvc->unit_not_ready = target_id; + DvcSleepMilliSecond(1000); + _AscWaitQDone(iop_base, (ASC_SCSI_Q dosfar *) scsiq); + if (AscStopQueueExe(iop_base) == 1) { + + AscCleanUpDiscQueue(iop_base); + AscStartQueueExe(iop_base); + if (asc_dvc->pci_fix_asyn_xfer & target_id) { + + AscSetRunChipSynRegAtID(iop_base, tid_no, + ASYN_SDTR_DATA_FIX_PCI_REV_AB); + } + AscWaitTixISRDone(asc_dvc, target_ix); + } + } else { + + sta = 0; + } + + asc_dvc->sdtr_done &= ~target_id; + } else { + sta = ERR; + AscStartQueueExe(iop_base); + } + } + asc_dvc->unit_not_ready = saved_unit_not_ready; + return (sta); +} + +int +AscResetSB( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + int sta; + int i; + PortAddr iop_base; + + iop_base = asc_dvc->iop_base; + asc_dvc->unit_not_ready = 0xFF; + sta = TRUE; + AscWaitISRDone(asc_dvc); + AscStopQueueExe(iop_base); + + asc_dvc->sdtr_done = 0; + AscResetChipAndScsiBus(iop_base); + + DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); + +#if CC_SCAM + if (!(asc_dvc->dvc_cntl & ASC_CNTL_NO_SCAM)) { + AscSCAM(asc_dvc); + } +#endif + AscReInitLram(asc_dvc); + + for (i = 0; i <= ASC_MAX_TID; i++) { + asc_dvc->cur_dvc_qng[i] = 0; + if (asc_dvc->pci_fix_asyn_xfer & (0x01 << i)) { + + AscSetChipSynRegAtID(iop_base, i, ASYN_SDTR_DATA_FIX_PCI_REV_AB); + } + } + + asc_dvc->err_code = 0; + + AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); + if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { + sta = ERR; + } + if (AscStartChip(iop_base) == 0) { + sta = ERR; + } + AscStartQueueExe(iop_base); + asc_dvc->unit_not_ready = 0; + asc_dvc->queue_full_or_busy = 0; + return (sta); +} + +int +AscSetRunChipSynRegAtID( + PortAddr iop_base, + uchar tid_no, + uchar sdtr_data +) +{ + int sta = FALSE; + + if (AscHostReqRiscHalt(iop_base)) { + sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); + + AscStartChip(iop_base); + return (sta); + } + return (sta); +} + +int +AscSetChipSynRegAtID( + PortAddr iop_base, + uchar id, + uchar sdtr_data +) +{ + AscSetBank(iop_base, 1); + AscWriteChipScsiID(iop_base, id); + if (AscReadChipScsiID(iop_base) != (0x01 << id)) { + return (FALSE); + } + AscSetBank(iop_base, 0); + AscWriteChipSyn(iop_base, sdtr_data); + if (AscReadChipSyn(iop_base) != sdtr_data) { + return (FALSE); + } + return (TRUE); +} + +int +AscReInitLram( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + AscInitLram(asc_dvc); + AscInitQLinkVar(asc_dvc); + return (0); +} + +ushort +AscInitLram( + ASC_DVC_VAR asc_ptr_type * asc_dvc) +{ + uchar i; + ushort s_addr; + PortAddr iop_base; + ushort warn_code; + + iop_base = asc_dvc->iop_base; + warn_code = 0; + + AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0, + (ushort) (((int) (asc_dvc->max_total_qng + 2 + 1) * 64) >> 1) + ); + + i = ASC_MIN_ACTIVE_QNO; + s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE; + + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD), + (uchar) (i + 1)); + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD), + (uchar) (asc_dvc->max_total_qng)); + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO), + (uchar) i); + i++; + s_addr += ASC_QBLK_SIZE; + for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) { + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD), + (uchar) (i + 1)); + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD), + (uchar) (i - 1)); + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO), + (uchar) i); + } + + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD), + (uchar) ASC_QLINK_END); + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD), + (uchar) (asc_dvc->max_total_qng - 1)); + AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO), + (uchar) asc_dvc->max_total_qng); + i++; + s_addr += ASC_QBLK_SIZE; + + for (; i <= (uchar) (asc_dvc->max_total_qng + 3); + i++, s_addr += ASC_QBLK_SIZE) { + + AscWriteLramByte(iop_base, + (ushort) (s_addr + (ushort) ASC_SCSIQ_B_FWD), i); + AscWriteLramByte(iop_base, + (ushort) (s_addr + (ushort) ASC_SCSIQ_B_BWD), i); + AscWriteLramByte(iop_base, + (ushort) (s_addr + (ushort) ASC_SCSIQ_B_QNO), i); + } + + return (warn_code); +} + +ushort +AscInitQLinkVar( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + PortAddr iop_base; + int i; + ushort lram_addr; + + iop_base = asc_dvc->iop_base; + AscPutRiscVarFreeQHead(iop_base, 1); + AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng); + + AscPutVarFreeQHead(iop_base, 1); + AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng); + + AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B, + (uchar) ((int) asc_dvc->max_total_qng + 1)); + AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B, + (uchar) ((int) asc_dvc->max_total_qng + 2)); + + AscWriteLramByte(iop_base, (ushort) ASCV_TOTAL_READY_Q_B, + asc_dvc->max_total_qng); + + AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0); + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0); + AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0); + AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0); + + AscWriteLramByte(iop_base, (ushort) ASCV_CDBCNT_B, 0); + + lram_addr = ASC_QADR_BEG; + for (i = 0; i < 32; i++, lram_addr += 2) { + AscWriteLramWord(iop_base, lram_addr, 0); + } + + return (0); +} + +int +AscSetLibErrorCode( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ushort err_code +) +{ + if (asc_dvc->err_code == 0) { + + asc_dvc->err_code = err_code; + AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W, + err_code); + } + return (err_code); +} + +int +_AscWaitQDone( + PortAddr iop_base, + ASC_SCSI_Q dosfar * scsiq +) +{ + ushort q_addr; + uchar q_status; + int count = 0; + + while (scsiq->q1.q_no == 0) ; + q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no); + + do { + q_status = AscReadLramByte(iop_base, q_addr + ASC_SCSIQ_B_STATUS); + DvcSleepMilliSecond(100L); + if (count++ > 30) { + return (0); + } + } while ((q_status & QS_READY) != 0); + return (1); +} + +uchar _sdtr_period_tbl_[ASC_SYN_XFER_NO] = +{ + SYN_XFER_NS_0, + SYN_XFER_NS_1, + SYN_XFER_NS_2, + SYN_XFER_NS_3, + SYN_XFER_NS_4, + SYN_XFER_NS_5, + SYN_XFER_NS_6, + SYN_XFER_NS_7}; + +uchar +AscMsgOutSDTR( + PortAddr iop_base, + uchar sdtr_period, + uchar sdtr_offset +) +{ + SDTR_XMSG sdtr_buf; + uchar sdtr_period_index; + + sdtr_buf.msg_type = MS_EXTEND; + sdtr_buf.msg_len = MS_SDTR_LEN; + sdtr_buf.msg_req = MS_SDTR_CODE; + sdtr_buf.xfer_period = sdtr_period; + sdtr_offset &= ASC_SYN_MAX_OFFSET; + sdtr_buf.req_ack_offset = sdtr_offset; + AscMemWordCopyToLram(iop_base, ASCV_MSGOUT_BEG, + (ushort dosfar *) & sdtr_buf, SYN_XMSG_WLEN); + if ((sdtr_period_index = AscGetSynPeriodIndex(sdtr_period)) <= + ASC_MAX_SDTR_PERIOD_INDEX) { + return ((sdtr_period_index << 4) | sdtr_offset); + } else { + + return (0); + } +} + +uchar +AscCalSDTRData( + uchar sdtr_period, + uchar syn_offset +) +{ + uchar byte; + uchar sdtr_period_ix; + + sdtr_period_ix = AscGetSynPeriodIndex(sdtr_period); + if ((sdtr_period_ix > ASC_MAX_SDTR_PERIOD_INDEX) || + (sdtr_period_ix > ASC_SDTR_PERIOD_IX_MIN)) { + return (0xFF); + } + byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET); + return (byte); +} + +void +AscSetChipSDTR( + PortAddr iop_base, + uchar sdtr_data, + uchar tid_no +) +{ + + AscWriteChipSyn(iop_base, sdtr_data); + AscWriteLramByte(iop_base, + (ushort) ((ushort) ASCV_SDTR_DONE_BEG + (ushort) tid_no), + sdtr_data); + return; +} + +uchar +AscGetSynPeriodIndex( + uchar syn_time +) +{ + if ((syn_time >= SYN_XFER_NS_0) && (syn_time <= SYN_XFER_NS_7)) { + if (syn_time <= SYN_XFER_NS_6) { + if (syn_time <= SYN_XFER_NS_5) { + if (syn_time <= SYN_XFER_NS_4) { + if (syn_time <= SYN_XFER_NS_3) { + if (syn_time <= SYN_XFER_NS_2) { + if (syn_time <= SYN_XFER_NS_1) { + if (syn_time <= SYN_XFER_NS_0) { + return (0); + } else + return (1); + } else { + return (2); + } + } else { + return (3); + } + } else { + return (4); + } + } else { + return (5); + } + } else { + return (6); + } + } else { + return (7); + } + } else { + + return (8); + } +} + +uchar +AscAllocFreeQueue( + PortAddr iop_base, + uchar free_q_head +) +{ + ushort q_addr; + uchar next_qp; + uchar q_status; + + q_addr = ASC_QNO_TO_QADDR(free_q_head); + q_status = (uchar) AscReadLramByte(iop_base, + (ushort) (q_addr + ASC_SCSIQ_B_STATUS)); + next_qp = AscReadLramByte(iop_base, + (ushort) (q_addr + ASC_SCSIQ_B_FWD)); + if (((q_status & QS_READY) == 0) && + (next_qp != ASC_QLINK_END)) { + return (next_qp); + } + return (ASC_QLINK_END); +} + +uchar +AscAllocMultipleFreeQueue( + PortAddr iop_base, + uchar free_q_head, + uchar n_free_q +) +{ + uchar i; + + for (i = 0; i < n_free_q; i++) { + if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head)) + == ASC_QLINK_END) { + return (ASC_QLINK_END); + } + } + return (free_q_head); +} + +int +AscRiscHaltedAbortSRB( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ulong srb_ptr +) +{ + PortAddr iop_base; + ushort q_addr; + uchar q_no; + ASC_QDONE_INFO scsiq_buf; + ASC_QDONE_INFO dosfar *scsiq; + ASC_ISR_CALLBACK asc_isr_callback; + int last_int_level; + + iop_base = asc_dvc->iop_base; + asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; + last_int_level = DvcEnterCritical(); + scsiq = (ASC_QDONE_INFO dosfar *) & scsiq_buf; + +#if CC_LINK_BUSY_Q + _AscAbortSrbBusyQueue(asc_dvc, scsiq, srb_ptr); +#endif + + for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng; + q_no++) { + q_addr = ASC_QNO_TO_QADDR(q_no); + scsiq->d2.srb_ptr = AscReadLramDWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR)); + if (scsiq->d2.srb_ptr == srb_ptr) { + _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count); + if (((scsiq->q_status & QS_READY) != 0) && + ((scsiq->q_status & QS_ABORTED) == 0) && + ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) { + + scsiq->q_status |= QS_ABORTED; + scsiq->d3.done_stat = QD_ABORTED_BY_HOST; + AscWriteLramDWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), + 0L); + AscWriteLramByte(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), + scsiq->q_status); + (*asc_isr_callback) (asc_dvc, scsiq); + return (1); + } + } + } + DvcLeaveCritical(last_int_level); + return (0); +} + +int +AscRiscHaltedAbortTIX( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + uchar target_ix +) +{ + PortAddr iop_base; + ushort q_addr; + uchar q_no; + ASC_QDONE_INFO scsiq_buf; + ASC_QDONE_INFO dosfar *scsiq; + ASC_ISR_CALLBACK asc_isr_callback; + int last_int_level; + +#if CC_LINK_BUSY_Q + uchar tid_no; + +#endif + + iop_base = asc_dvc->iop_base; + asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; + last_int_level = DvcEnterCritical(); + scsiq = (ASC_QDONE_INFO dosfar *) & scsiq_buf; + +#if CC_LINK_BUSY_Q + + tid_no = ASC_TIX_TO_TID(target_ix); + _AscAbortTidBusyQueue(asc_dvc, scsiq, tid_no); + +#endif + + for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng; + q_no++) { + q_addr = ASC_QNO_TO_QADDR(q_no); + _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count); + if (((scsiq->q_status & QS_READY) != 0) && + ((scsiq->q_status & QS_ABORTED) == 0) && + ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) { + if (scsiq->d2.target_ix == target_ix) { + scsiq->q_status |= QS_ABORTED; + scsiq->d3.done_stat = QD_ABORTED_BY_HOST; + + AscWriteLramDWord(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), + 0L); + + AscWriteLramByte(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), + scsiq->q_status); + (*asc_isr_callback) (asc_dvc, scsiq); + } + } + } + DvcLeaveCritical(last_int_level); + return (1); +} + +#if CC_LINK_BUSY_Q + +#endif + +int +AscHostReqRiscHalt( + PortAddr iop_base +) +{ + int count = 0; + int sta = 0; + uchar saved_stop_code; + + if (AscIsChipHalted(iop_base)) + return (1); + saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); + + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, + ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP + ); + do { + if (AscIsChipHalted(iop_base)) { + sta = 1; + break; + } + DvcSleepMilliSecond(100); + } while (count++ < 20); + + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code); + return (sta); +} + +int +AscStopQueueExe( + PortAddr iop_base +) +{ + int count; + + count = 0; + if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) { + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, + ASC_STOP_REQ_RISC_STOP); + do { + if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) & + ASC_STOP_ACK_RISC_STOP) { + return (1); + } + DvcSleepMilliSecond(100); + } while (count++ < 20); + } + return (0); +} + +int +AscStartQueueExe( + PortAddr iop_base +) +{ + if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0); + } + return (1); +} + +int +AscCleanUpBusyQueue( + PortAddr iop_base +) +{ + int count; + uchar stop_code; + + count = 0; + if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, + ASC_STOP_CLEAN_UP_BUSY_Q); + do { + stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); + if ((stop_code & ASC_STOP_CLEAN_UP_BUSY_Q) == 0) + break; + DvcSleepMilliSecond(100); + } while (count++ < 20); + } + return (1); +} + +int +AscCleanUpDiscQueue( + PortAddr iop_base +) +{ + int count; + uchar stop_code; + + count = 0; + if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { + AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, + ASC_STOP_CLEAN_UP_DISC_Q); + do { + stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); + if ((stop_code & ASC_STOP_CLEAN_UP_DISC_Q) == 0) + break; + DvcSleepMilliSecond(100); + } while (count++ < 20); + } + return (1); +} + +int +AscWaitTixISRDone( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + uchar target_ix +) +{ + uchar cur_req; + uchar tid_no; + + tid_no = ASC_TIX_TO_TID(target_ix); + while (TRUE) { + if ((cur_req = asc_dvc->cur_dvc_qng[tid_no]) == 0) { + break; + } + DvcSleepMilliSecond(1000L); + if (asc_dvc->cur_dvc_qng[tid_no] == cur_req) { + break; + } + } + return (1); +} + +int +AscWaitISRDone( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + int tid; + + for (tid = 0; tid <= ASC_MAX_TID; tid++) { + AscWaitTixISRDone(asc_dvc, ASC_TID_TO_TIX(tid)); + } + return (1); +} + +ulong +AscGetOnePhyAddr( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + uchar dosfar * buf_addr, + ulong buf_size +) +{ + ASC_MIN_SG_HEAD sg_head; + + sg_head.entry_cnt = ASC_MIN_SG_LIST; + if (DvcGetSGList(asc_dvc, (uchar dosfar *) buf_addr, + buf_size, (ASC_SG_HEAD dosfar *) & sg_head) != buf_size) { + return (0L); + } + if (sg_head.entry_cnt > 1) { + return (0L); + } + return (sg_head.sg_list[0].addr); +} + +ulong +AscGetEisaProductID( + PortAddr iop_base +) +{ + PortAddr eisa_iop; + ushort product_id_high, product_id_low; + ulong product_id; + + eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK; + product_id_low = inpw(eisa_iop); + product_id_high = inpw(eisa_iop + 2); + product_id = ((ulong) product_id_high << 16) | (ulong) product_id_low; + return (product_id); +} + +PortAddr +AscSearchIOPortAddrEISA( + PortAddr iop_base +) +{ + ulong eisa_product_id; + + if (iop_base == 0) { + iop_base = ASC_EISA_MIN_IOP_ADDR; + } else { + if (iop_base == ASC_EISA_MAX_IOP_ADDR) + return (0); + if ((iop_base & 0x0050) == 0x0050) { + iop_base += ASC_EISA_BIG_IOP_GAP; + } else { + iop_base += ASC_EISA_SMALL_IOP_GAP; + } + } + while (iop_base <= ASC_EISA_MAX_IOP_ADDR) { + + eisa_product_id = AscGetEisaProductID(iop_base); + if ((eisa_product_id == ASC_EISA_ID_740) || + (eisa_product_id == ASC_EISA_ID_750)) { + if (AscFindSignature(iop_base)) { + + inpw(iop_base + 4); + return (iop_base); + } + } + if (iop_base == ASC_EISA_MAX_IOP_ADDR) + return (0); + if ((iop_base & 0x0050) == 0x0050) { + iop_base += ASC_EISA_BIG_IOP_GAP; + } else { + iop_base += ASC_EISA_SMALL_IOP_GAP; + } + } + return (0); +} + +int +AscStartChip( + PortAddr iop_base +) +{ + AscSetChipControl(iop_base, 0); + if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) { + return (0); + } + return (1); +} + +int +AscStopChip( + PortAddr iop_base +) +{ + uchar cc_val; + + cc_val = AscGetChipControl(iop_base) & (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG)); + AscSetChipControl(iop_base, (uchar) (cc_val | CC_HALT)); + AscSetChipIH(iop_base, INS_HALT); + AscSetChipIH(iop_base, INS_RFLAG_WTM); + if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) { + return (0); + } + return (1); +} + +int +AscIsChipHalted( + PortAddr iop_base +) +{ + + if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) { + if ((AscGetChipControl(iop_base) & CC_HALT) != 0) { + return (1); + } + } + return (0); +} + +void +AscSetChipIH( + PortAddr iop_base, + ushort ins_code +) +{ + AscSetBank(iop_base, 1); + AscWriteChipIH(iop_base, ins_code); + AscSetBank(iop_base, 0); + return; +} + +void +AscAckInterrupt( + PortAddr iop_base +) +{ + + uchar host_flag; + uchar risc_flag; + ushort loop; + + loop = 0; + do { + risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B); + if (loop++ > 0x7FFF) { + break; + } + } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0); + + host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B); + AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, + (uchar) (host_flag | ASC_HOST_FLAG_ACK_INT)); + + AscSetChipStatus(iop_base, CIW_INT_ACK); + loop = 0; + while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) { + + AscSetChipStatus(iop_base, CIW_INT_ACK); + if (loop++ > 3) { + break; + } + } + + AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); + return; +} + +void +AscDisableInterrupt( + PortAddr iop_base +) +{ + ushort cfg; + + cfg = AscGetChipCfgLsw(iop_base); + AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON)); + return; +} + +void +AscEnableInterrupt( + PortAddr iop_base +) +{ + ushort cfg; + + cfg = AscGetChipCfgLsw(iop_base); + AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON); + return; +} + +void +AscSetBank( + PortAddr iop_base, + uchar bank +) +{ + uchar val; + + val = AscGetChipControl(iop_base) & + (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | CC_CHIP_RESET)); + if (bank == 1) { + val |= CC_BANK_ONE; + } else if (bank == 2) { + val |= CC_DIAG | CC_BANK_ONE; + } else { + val &= ~CC_BANK_ONE; + } + AscSetChipControl(iop_base, val); + return; +} + +int +AscResetChipAndScsiBus( + PortAddr iop_base +) +{ + AscStopChip(iop_base); + AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT); + DvcSleepMilliSecond(200); + + AscSetChipIH(iop_base, INS_RFLAG_WTM); + AscSetChipIH(iop_base, INS_HALT); + + AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT); + AscSetChipControl(iop_base, CC_HALT); + DvcSleepMilliSecond(200); + return (AscIsChipHalted(iop_base)); +} + +ushort +AscGetIsaDmaChannel( + PortAddr iop_base +) +{ + ushort channel; + + channel = AscGetChipCfgLsw(iop_base) & 0x0003; + if (channel == 0x03) + return (0); + else if (channel == 0x00) + return (7); + return (channel + 4); +} + +ushort +AscSetIsaDmaChannel( + PortAddr iop_base, + ushort dma_channel +) +{ + ushort cfg_lsw; + uchar value; + + if ((dma_channel >= 5) && (dma_channel <= 7)) { + + if (dma_channel == 7) + value = 0x00; + else + value = dma_channel - 4; + cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC; + cfg_lsw |= value; + AscSetChipCfgLsw(iop_base, cfg_lsw); + return (AscGetIsaDmaChannel(iop_base)); + } + return (0); +} + +uchar +AscSetIsaDmaSpeed( + PortAddr iop_base, + uchar speed_value +) +{ + speed_value &= 0x07; + AscSetBank(iop_base, 1); + AscSetChipDmaSpeed(iop_base, speed_value); + AscSetBank(iop_base, 0); + return (AscGetIsaDmaSpeed(iop_base)); +} + +uchar +AscGetIsaDmaSpeed( + PortAddr iop_base +) +{ + uchar speed_value; + + AscSetBank(iop_base, 1); + speed_value = AscGetChipDmaSpeed(iop_base); + speed_value &= 0x07; + AscSetBank(iop_base, 0); + return (speed_value); +} + +ulong +AscGetMaxDmaCount( + ushort bus_type +) +{ + if (bus_type & ASC_IS_ISA) + return (ASC_MAX_ISA_DMA_COUNT); + else if (bus_type & (ASC_IS_EISA | ASC_IS_VL)) + return (ASC_MAX_VL_DMA_COUNT); + return (ASC_MAX_PCI_DMA_COUNT); +} + +ushort +AscInitGetConfig( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + ushort warn_code; + + warn_code = 0; + asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG; + if (asc_dvc->err_code != 0) + return (UW_ERR); + if (AscFindSignature(asc_dvc->iop_base)) { + warn_code |= AscInitAscDvcVar(asc_dvc); + warn_code |= AscInitFromEEP(asc_dvc); + asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG; + + if (asc_dvc->scsi_reset_wait > 10) + asc_dvc->scsi_reset_wait = 10; + + } else { + asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; + } + return (warn_code); +} + +ushort +AscInitSetConfig( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + ushort warn_code; + + warn_code = 0; + asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG; + if (asc_dvc->err_code != 0) + return (UW_ERR); + if (AscFindSignature(asc_dvc->iop_base)) { + warn_code |= AscInitFromAscDvcVar(asc_dvc); + asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG; + } else { + asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; + } + return (warn_code); +} + +ushort +AscInitAsc1000Driver( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + ushort warn_code; + PortAddr iop_base; + + extern ushort _mcode_size; + extern ulong _mcode_chksum; + extern uchar _mcode_buf[]; + + ASC_DBG(3, "AscInitAsc1000Driver: begin\n"); + iop_base = asc_dvc->iop_base; + warn_code = 0; + + if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) && + !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) { + + ASC_DBG(3, "AscInitAsc1000Driver: AscResetChipAndScsiBus()\n"); + AscResetChipAndScsiBus(iop_base); + DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); + } + asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC; + if (asc_dvc->err_code != 0) + return (UW_ERR); + ASC_DBG(3, "AscInitAsc1000Driver: AscFindSignature()\n"); + if (!AscFindSignature(asc_dvc->iop_base)) { + asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; + return (warn_code); + } + ASC_DBG(3, "AscInitAsc1000Driver: AscDisableInterrupt()\n"); + AscDisableInterrupt(iop_base); + + ASC_DBG(3, "AscInitAsc1000Driver: AscInitLram()\n"); + warn_code |= AscInitLram(asc_dvc); + if (asc_dvc->err_code != 0) + return (UW_ERR); + ASC_DBG(3, "AscInitAsc1000Driver: AscLoadMicroCode()\n"); + if (AscLoadMicroCode(iop_base, 0, (ushort dosfar *) _mcode_buf, + _mcode_size) != _mcode_chksum) { + asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; + return (warn_code); + } + ASC_DBG(3, "AscInitAsc1000Driver: AscInitMicroCodeVar()\n"); + warn_code |= AscInitMicroCodeVar(asc_dvc); + asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC; + ASC_DBG(3, "AscInitAsc1000Driver: AscEnableInterrupt()\n"); + AscEnableInterrupt(iop_base); + return (warn_code); +} + +ushort +AscInitAscDvcVar( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + int i; + PortAddr iop_base; + ushort warn_code; + + iop_base = asc_dvc->iop_base; + warn_code = 0; + asc_dvc->err_code = 0; + + if ((asc_dvc->bus_type & + (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) { + asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE; + } +#if CC_LINK_BUSY_Q + for (i = 0; i <= ASC_MAX_TID; i++) { + asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q dosfar *) 0L; + asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q dosfar *) 0L; + } +#endif + + asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL; + asc_dvc->bug_fix_cntl = 0; + asc_dvc->pci_fix_asyn_xfer = 0; + asc_dvc->init_sdtr = 0; + asc_dvc->sdtr_done = 0; + asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG; + asc_dvc->cur_total_qng = 0; + asc_dvc->is_in_int = 0; + asc_dvc->scsi_reset_wait = 3; + asc_dvc->in_critical_cnt = 0; + + asc_dvc->last_q_shortage = 0; + asc_dvc->use_tagged_qng = 0; + asc_dvc->cfg->can_tagged_qng = 0; + asc_dvc->no_scam = 0; + asc_dvc->irq_no = 10; + asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET; + asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET; + asc_dvc->cfg->cmd_qng_enabled = ASC_SCSI_WIDTH_BIT_SET; + asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID; + asc_dvc->cfg->chip_version = AscGetChipVersion(iop_base, + asc_dvc->bus_type); + if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) { + + AscPutChipIFC(iop_base, IFC_INIT_DEFAULT); + asc_dvc->bus_type = ASC_IS_ISAPNP; + } + asc_dvc->unit_not_ready = 0; + asc_dvc->queue_full_or_busy = 0; + + if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) { + asc_dvc->cfg->isa_dma_channel = (uchar) AscGetIsaDmaChannel(iop_base); + asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED; + } + asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER; + asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) | + ASC_LIB_VERSION_MINOR; + asc_dvc->int_count = 0L; + asc_dvc->req_count = 0L; + asc_dvc->busy_count = 0L; + asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type); + + for (i = 0; i <= ASC_MAX_TID; i++) { + asc_dvc->cfg->sdtr_data[i] = + (uchar) (ASC_DEF_SDTR_OFFSET | (ASC_DEF_SDTR_INDEX << 4)); + asc_dvc->cur_dvc_qng[i] = 0; + asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG; + asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q dosfar *) 0L; + asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q dosfar *) 0L; + } + return (warn_code); +} + +ushort +AscInitFromAscDvcVar( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + PortAddr iop_base; + ushort cfg_msw; + ushort warn_code; + + iop_base = asc_dvc->iop_base; + warn_code = 0; + + cfg_msw = AscGetChipCfgMsw(iop_base); + + if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { + cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); + warn_code |= ASC_WARN_CFG_MSW_RECOVER; + AscSetChipCfgMsw(iop_base, cfg_msw); + } + if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { + warn_code |= ASC_WARN_AUTO_CONFIG; + + } + if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) != + asc_dvc->cfg->cmd_qng_enabled) { + asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled; + warn_code |= ASC_WARN_CMD_QNG_CONFLICT; + } + if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) { + + if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type) + != asc_dvc->irq_no) { + asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO; + } + } + if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) != + asc_dvc->cfg->chip_scsi_id) { + asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID; + } + if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) { + AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel); + AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed); + } + return (warn_code); +} + +ushort +AscInitFromEEP( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + ASCEEP_CONFIG eep_config_buf; + ASCEEP_CONFIG dosfar *eep_config; + PortAddr iop_base; + ushort chksum; + ushort warn_code; + ushort cfg_msw, cfg_lsw; + uchar i; + + iop_base = asc_dvc->iop_base; + warn_code = 0; + + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE); + + AscStopQueueExe(iop_base); + if ((AscStopChip(iop_base) == FALSE) || + (AscGetChipScsiCtrl(iop_base) != 0)) { + asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE; + AscResetChipAndScsiBus(iop_base); + DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); + } + if (AscIsChipHalted(iop_base) == FALSE) { + asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; + return (warn_code); + } + AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); + if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { + asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; + return (warn_code); + } + eep_config = (ASCEEP_CONFIG dosfar *) & eep_config_buf; + + cfg_msw = AscGetChipCfgMsw(iop_base); + cfg_lsw = AscGetChipCfgLsw(iop_base); + + if (asc_dvc->bus_type & ASC_IS_PCI) { +#if CC_DISABLE_PCI_PARITY_INT + cfg_msw &= 0xFFC0; + AscSetChipCfgMsw(iop_base, cfg_msw); +#endif + if (asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_A) { + asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ADD_ONE_BYTE; + } + } + if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { + cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); + warn_code |= ASC_WARN_CFG_MSW_RECOVER; + AscSetChipCfgMsw(iop_base, cfg_msw); + } + chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); + + eep_config->cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); + + if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { + warn_code |= ASC_WARN_AUTO_CONFIG; + + if (asc_dvc->cfg->chip_version == 3) { + + if (eep_config->cfg_lsw != cfg_lsw) { + warn_code |= ASC_WARN_EEPROM_RECOVER; + eep_config->cfg_lsw = AscGetChipCfgLsw(iop_base); + } + if (eep_config->cfg_msw != cfg_msw) { + warn_code |= ASC_WARN_EEPROM_RECOVER; + eep_config->cfg_msw = AscGetChipCfgMsw(iop_base); + } + } + } + eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON; + if (chksum != eep_config->chksum) { + warn_code |= ASC_WARN_EEPROM_CHKSUM; + } + asc_dvc->init_sdtr = eep_config->init_sdtr; + asc_dvc->cfg->disc_enable = eep_config->disc_enable; + + asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng; + asc_dvc->cfg->isa_dma_speed = eep_config->isa_dma_speed; + asc_dvc->start_motor = eep_config->start_motor; + asc_dvc->dvc_cntl = eep_config->cntl; + asc_dvc->no_scam = eep_config->no_scam; + + if ((asc_dvc->bus_type & ASC_IS_PCI) && + !(asc_dvc->dvc_cntl & ASC_CNTL_NO_PCI_FIX_ASYN_XFER)) { + if ((asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_A) || + (asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) { + asc_dvc->pci_fix_asyn_xfer = ASC_ALL_DEVICE_BIT_SET; + } + } else if (asc_dvc->bus_type & ASC_IS_ISAPNP) { + + if (AscGetChipVersion(iop_base, asc_dvc->bus_type) + == ASC_CHIP_VER_ASYN_BUG) { + asc_dvc->pci_fix_asyn_xfer = ASC_ALL_DEVICE_BIT_SET; + } + } + if (!AscTestExternalLram(asc_dvc)) { + if (asc_dvc->bus_type & ASC_IS_PCI) { + eep_config->cfg_msw |= 0x0800; + cfg_msw |= 0x0800; + AscSetChipCfgMsw(iop_base, cfg_msw); + eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG; + eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG; + } + } else { +#if CC_TEST_RW_LRAM + asc_dvc->err_code |= AscTestLramEndian(iop_base); +#endif + } + if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) { + eep_config->max_total_qng = ASC_MIN_TOTAL_QNG; + } + if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) { + eep_config->max_total_qng = ASC_MAX_TOTAL_QNG; + } + if (eep_config->max_tag_qng > eep_config->max_total_qng) { + eep_config->max_tag_qng = eep_config->max_total_qng; + } + if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) { + eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC; + } + asc_dvc->max_total_qng = eep_config->max_total_qng; + + if ((eep_config->use_cmd_qng & eep_config->disc_enable) != + eep_config->use_cmd_qng) { + eep_config->disc_enable = eep_config->use_cmd_qng; + warn_code |= ASC_WARN_CMD_QNG_CONFLICT; + } + asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type); + eep_config->chip_scsi_id &= ASC_MAX_TID; + asc_dvc->cfg->chip_scsi_id = eep_config->chip_scsi_id; + + for (i = 0; i <= ASC_MAX_TID; i++) { + asc_dvc->cfg->sdtr_data[i] = eep_config->sdtr_data[i]; + asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng; + } + + eep_config->cfg_msw = AscGetChipCfgMsw(iop_base); + if (AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type) != 0) { + asc_dvc->err_code |= ASC_IERR_WRITE_EEPROM; + } + return (warn_code); +} + +ushort +AscInitMicroCodeVar( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + int i; + ushort warn_code; + PortAddr iop_base; + ulong phy_addr; + + iop_base = asc_dvc->iop_base; + warn_code = 0; + for (i = 0; i <= ASC_MAX_TID; i++) { + AscWriteLramByte(iop_base, (ushort) (ASCV_SDTR_DATA_BEG + i), + asc_dvc->cfg->sdtr_data[i]); + } + + AscInitQLinkVar(asc_dvc); + + AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, + asc_dvc->cfg->disc_enable); + AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B, + ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id)); + if ((phy_addr = AscGetOnePhyAddr(asc_dvc, + (uchar dosfar *) asc_dvc->cfg->overrun_buf, + ASC_OVERRUN_BSIZE)) == 0L) { + asc_dvc->err_code |= ASC_IERR_GET_PHY_ADDR; + } else { + + phy_addr = (phy_addr & 0xFFFFFFF8UL) + 8; + AscWriteLramDWord(iop_base, ASCV_OVERRUN_PADDR_D, phy_addr); + AscWriteLramDWord(iop_base, ASCV_OVERRUN_BSIZE_D, + ASC_OVERRUN_BSIZE - 8); + } + + asc_dvc->cfg->mcode_date = AscReadLramWord(iop_base, + (ushort) ASCV_MC_DATE_W); + asc_dvc->cfg->mcode_version = AscReadLramWord(iop_base, + (ushort) ASCV_MC_VER_W); + AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); + if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { + asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; + return (warn_code); + } + if (AscStartChip(iop_base) != 1) { + asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; + return (warn_code); + } + return (warn_code); +} + +void dosfar +AscInitPollIsrCallBack( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_QDONE_INFO dosfar * scsi_done_q +) +{ + ASC_SCSI_REQ_Q dosfar *scsiq_req; + ASC_ISR_CALLBACK asc_isr_callback; + uchar cp_sen_len; + uchar i; + + if ((scsi_done_q->d2.flag & ASC_FLAG_SCSIQ_REQ) != 0) { + scsiq_req = (ASC_SCSI_REQ_Q dosfar *) scsi_done_q->d2.srb_ptr; + ASC_DBG2(3, "AscInitPollIsrCallBack: done_stat %x, host_stat %x\n", + scsiq_req->r3.done_stat, scsiq_req->r3.host_stat); + scsiq_req->r3.done_stat = scsi_done_q->d3.done_stat; + scsiq_req->r3.host_stat = scsi_done_q->d3.host_stat; + scsiq_req->r3.scsi_stat = scsi_done_q->d3.scsi_stat; + scsiq_req->r3.scsi_msg = scsi_done_q->d3.scsi_msg; + if ((scsi_done_q->d3.scsi_stat == SS_CHK_CONDITION) && + (scsi_done_q->d3.host_stat == 0)) { + cp_sen_len = (uchar) ASC_MIN_SENSE_LEN; + if (scsiq_req->r1.sense_len < ASC_MIN_SENSE_LEN) { + cp_sen_len = (uchar) scsiq_req->r1.sense_len; + } + for (i = 0; i < cp_sen_len; i++) { + scsiq_req->sense[i] = scsiq_req->sense_ptr[i]; + } + } + } else { + ASC_DBG1(3, "AscInitPollIsrCallBack: isr_callback %x\n", + (unsigned) asc_dvc->isr_callback); + if (asc_dvc->isr_callback != 0) { + asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; + (*asc_isr_callback) (asc_dvc, scsi_done_q); + } + } + return; +} + +int +AscTestExternalLram( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + PortAddr iop_base; + ushort q_addr; + ushort saved_word; + int sta; + + iop_base = asc_dvc->iop_base; + sta = 0; + + q_addr = ASC_QNO_TO_QADDR(241); + saved_word = AscReadLramWord(iop_base, q_addr); + if (AscVerWriteLramWord(iop_base, q_addr, 0x55AA) == 0) { + sta = 1; + AscWriteLramWord(iop_base, q_addr, saved_word); + } + return (sta); +} + +#if CC_TEST_LRAM_ENDIAN + +#endif + +int +AscWriteEEPCmdReg( + PortAddr iop_base, + uchar cmd_reg +) +{ + uchar read_back; + int retry; + + retry = 0; + while (TRUE) { + AscSetChipEEPCmd(iop_base, cmd_reg); + DvcSleepMilliSecond(1); + read_back = AscGetChipEEPCmd(iop_base); + if (read_back == cmd_reg) { + return (1); + } + if (retry++ > ASC_EEP_MAX_RETRY) { + return (0); + } + } +} + +int +AscWriteEEPDataReg( + PortAddr iop_base, + ushort data_reg +) +{ + ushort read_back; + int retry; + + retry = 0; + while (TRUE) { + AscSetChipEEPData(iop_base, data_reg); + DvcSleepMilliSecond(1); + read_back = AscGetChipEEPData(iop_base); + if (read_back == data_reg) { + return (1); + } + if (retry++ > ASC_EEP_MAX_RETRY) { + return (0); + } + } +} + +void +AscWaitEEPRead( + void +) +{ + DvcSleepMilliSecond(1); + return; +} + +void +AscWaitEEPWrite( + void +) +{ + DvcSleepMilliSecond(20); + return; +} + +ushort +AscReadEEPWord( + PortAddr iop_base, + uchar addr +) +{ + ushort read_wval; + uchar cmd_reg; + + AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE); + AscWaitEEPRead(); + cmd_reg = addr | ASC_EEP_CMD_READ; + AscWriteEEPCmdReg(iop_base, cmd_reg); + AscWaitEEPRead(); + read_wval = AscGetChipEEPData(iop_base); + AscWaitEEPRead(); + return (read_wval); +} + +ushort +AscWriteEEPWord( + PortAddr iop_base, + uchar addr, + ushort word_val +) +{ + ushort read_wval; + + read_wval = AscReadEEPWord(iop_base, addr); + if (read_wval != word_val) { + AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE); + AscWaitEEPRead(); + + AscWriteEEPDataReg(iop_base, word_val); + AscWaitEEPRead(); + + AscWriteEEPCmdReg(iop_base, + (uchar) ((uchar) ASC_EEP_CMD_WRITE | addr)); + AscWaitEEPWrite(); + + AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE); + AscWaitEEPRead(); + return (AscReadEEPWord(iop_base, addr)); + } + return (read_wval); +} + +ushort +AscGetEEPConfig( + PortAddr iop_base, + ASCEEP_CONFIG dosfar * cfg_buf, ushort bus_type +) +{ + ushort wval; + ushort sum; + ushort dosfar *wbuf; + int cfg_beg; + int cfg_end; + int s_addr; + int isa_pnp_wsize; + + wbuf = (ushort dosfar *) cfg_buf; + sum = 0; + + isa_pnp_wsize = 0; + for (s_addr = 0; s_addr < (2 + isa_pnp_wsize); s_addr++, wbuf++) { + wval = AscReadEEPWord(iop_base, (uchar) s_addr); + sum += wval; + *wbuf = wval; + } + + if (bus_type & ASC_IS_VL) { + cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; + cfg_end = ASC_EEP_MAX_DVC_ADDR_VL; + } else { + cfg_beg = ASC_EEP_DVC_CFG_BEG; + cfg_end = ASC_EEP_MAX_DVC_ADDR; + } + + for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); + s_addr++, wbuf++) { + wval = AscReadEEPWord(iop_base, (uchar) s_addr); + sum += wval; + *wbuf = wval; + } + *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr); + return (sum); +} + +int +AscSetEEPConfigOnce( + PortAddr iop_base, + ASCEEP_CONFIG dosfar * cfg_buf, ushort bus_type +) +{ + int n_error; + ushort dosfar *wbuf; + ushort sum; + int s_addr; + int cfg_beg; + int cfg_end; + + wbuf = (ushort dosfar *) cfg_buf; + n_error = 0; + sum = 0; + for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { + sum += *wbuf; + if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) { + n_error++; + } + } + if (bus_type & ASC_IS_VL) { + cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; + cfg_end = ASC_EEP_MAX_DVC_ADDR_VL; + } else { + cfg_beg = ASC_EEP_DVC_CFG_BEG; + cfg_end = ASC_EEP_MAX_DVC_ADDR; + } + for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); + s_addr++, wbuf++) { + sum += *wbuf; + if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) { + n_error++; + } + } + *wbuf = sum; + if (sum != AscWriteEEPWord(iop_base, (uchar) s_addr, sum)) { + n_error++; + } + wbuf = (ushort dosfar *) cfg_buf; + for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { + if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) { + n_error++; + } + } + for (s_addr = cfg_beg; s_addr <= cfg_end; + s_addr++, wbuf++) { + if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) { + n_error++; + } + } + return (n_error); +} + +int +AscSetEEPConfig( + PortAddr iop_base, + ASCEEP_CONFIG dosfar * cfg_buf, ushort bus_type +) +{ + int retry; + int n_error; + + retry = 0; + while (TRUE) { + if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf, + bus_type)) == 0) { + break; + } + if (++retry > ASC_EEP_MAX_RETRY) { + break; + } + } + return (n_error); +} + +int +AscInitPollBegin( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + PortAddr iop_base; + + iop_base = asc_dvc->iop_base; + +#if CC_INIT_INQ_DISPLAY + DvcDisplayString((uchar dosfar *) "\r\n"); +#endif + + AscDisableInterrupt(iop_base); + + asc_dvc->init_state |= ASC_INIT_STATE_BEG_INQUIRY; + + AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, 0x00); + asc_dvc->use_tagged_qng = 0; + asc_dvc->cfg->can_tagged_qng = 0; + asc_dvc->saved_ptr2func = (ulong) asc_dvc->isr_callback; + asc_dvc->isr_callback = ASC_GET_PTR2FUNC(AscInitPollIsrCallBack); + return (0); +} + +int +AscInitPollEnd( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + PortAddr iop_base; + int i; + + iop_base = asc_dvc->iop_base; + asc_dvc->isr_callback = (Ptr2Func) asc_dvc->saved_ptr2func; + AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, + asc_dvc->cfg->disc_enable); + AscWriteLramByte(iop_base, ASCV_USE_TAGGED_QNG_B, + asc_dvc->use_tagged_qng); + AscWriteLramByte(iop_base, ASCV_CAN_TAGGED_QNG_B, + asc_dvc->cfg->can_tagged_qng); + + for (i = 0; i <= ASC_MAX_TID; i++) { + AscWriteLramByte(iop_base, + (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) i), + asc_dvc->max_dvc_qng[i]); + } + + AscEnableInterrupt(iop_base); + +#if CC_INIT_INQ_DISPLAY + DvcDisplayString((uchar dosfar *) "\r\n"); +#endif + asc_dvc->init_state |= ASC_INIT_STATE_END_INQUIRY; + + return (0); +} + +int _asc_wait_slow_device_ = FALSE; + +int +AscInitPollTarget( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_REQ_Q dosfar * scsiq, + ASC_SCSI_INQUIRY dosfar * inq, + ASC_CAP_INFO dosfar * cap_info +) +{ + uchar tid_no, lun; + uchar dvc_type; + ASC_SCSI_BIT_ID_TYPE tid_bits; + int dvc_found; + int support_read_cap; + int tmp_disable_init_sdtr; + ulong phy_addr; + + dvc_found = 0; + tmp_disable_init_sdtr = FALSE; + tid_bits = scsiq->r1.target_id; + lun = scsiq->r1.target_lun; + tid_no = ASC_TIX_TO_TID(scsiq->r2.target_ix); + if ((phy_addr = AscGetOnePhyAddr(asc_dvc, + (uchar dosfar *) scsiq->sense_ptr, + (ulong) scsiq->r1.sense_len)) == 0L) { + return (ERR); + } + scsiq->r1.sense_addr = phy_addr; + if (((asc_dvc->init_sdtr & tid_bits) != 0) && + ((asc_dvc->sdtr_done & tid_bits) == 0)) { + + asc_dvc->init_sdtr &= ~tid_bits; + tmp_disable_init_sdtr = TRUE; + } + ASC_DBG(3, "AscInitPollTarget: PollScsiInquiry()\n"); + if (PollScsiInquiry(asc_dvc, scsiq, (uchar dosfar *) inq, + sizeof (ASC_SCSI_INQUIRY)) == 1) { + dvc_found = 1; + support_read_cap = TRUE; + dvc_type = inq->byte0.peri_dvc_type; + if (dvc_type != SCSI_TYPE_UNKNOWN) { + if ((dvc_type != SCSI_TYPE_DASD) && + (dvc_type != SCSI_TYPE_WORM) && + (dvc_type != SCSI_TYPE_CDROM) && + (dvc_type != SCSI_TYPE_OPTMEM)) { + asc_dvc->start_motor &= ~tid_bits; + support_read_cap = FALSE; + } + if ((dvc_type != SCSI_TYPE_DASD) || + inq->byte1.rmb) { + + if (!_asc_wait_slow_device_) { + DvcSleepMilliSecond(3000 - ((int) tid_no * 250)); + _asc_wait_slow_device_ = TRUE; + } + } +#if CC_INIT_INQ_DISPLAY + AscDispInquiry(tid_no, lun, inq); +#endif + + if (lun == 0) { + + if ((inq->byte3.rsp_data_fmt >= 2) || + (inq->byte2.ansi_apr_ver >= 2)) { + + if (inq->byte7.CmdQue) { + asc_dvc->cfg->can_tagged_qng |= tid_bits; + if (asc_dvc->cfg->cmd_qng_enabled & tid_bits) { + asc_dvc->use_tagged_qng |= tid_bits; + asc_dvc->max_dvc_qng[tid_no] = + asc_dvc->cfg->max_tag_qng[tid_no]; + } + } + if (!inq->byte7.Sync) { + + asc_dvc->init_sdtr &= ~tid_bits; + asc_dvc->sdtr_done &= ~tid_bits; + } else if (tmp_disable_init_sdtr) { + + asc_dvc->init_sdtr |= tid_bits; + } + } else { + + asc_dvc->init_sdtr &= ~tid_bits; + asc_dvc->sdtr_done &= ~tid_bits; + asc_dvc->use_tagged_qng &= ~tid_bits; + } + } + if (asc_dvc->pci_fix_asyn_xfer & tid_bits) { + if (!(asc_dvc->init_sdtr & tid_bits)) { + + AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no, + ASYN_SDTR_DATA_FIX_PCI_REV_AB); + } + } + ASC_DBG(3, "AscInitPollTarget: InitTestUnitReady()\n"); + if (InitTestUnitReady(asc_dvc, scsiq) != 1) { + + } else { + if ((cap_info != 0L) && support_read_cap) { + ASC_DBG(3, "AscInitPollTarget: PollScsiReadCapacity()\n"); + if (PollScsiReadCapacity(asc_dvc, scsiq, + cap_info) != 1) { + cap_info->lba = 0L; + cap_info->blk_size = 0x0000; + } else { + + } + } + } + } else { + asc_dvc->start_motor &= ~tid_bits; + } + } else { + + } + return (dvc_found); +} + +int +PollQueueDone( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_REQ_Q dosfar * scsiq, + int timeout_sec +) +{ + int status; + int retry; + + retry = 0; + do { + ASC_DBG(3, "PollQueueDone: AscExeScsiQueue()\n"); + if ((status = AscExeScsiQueue(asc_dvc, + (ASC_SCSI_Q dosfar *) scsiq)) == 1) { + ASC_DBG(3, "PollQueueDone: AscPollQDone()\n"); + if ((status = AscPollQDone(asc_dvc, scsiq, + timeout_sec)) != 1) { + ASC_DBG1(3, "PollQueueDone: AscPollQDone() status %x\n", status); + if (status == 0x80) { + if (retry++ > ASC_MAX_INIT_BUSY_RETRY) { + break; + } + scsiq->r3.done_stat = 0; + scsiq->r3.host_stat = 0; + scsiq->r3.scsi_stat = 0; + scsiq->r3.scsi_msg = 0; + DvcSleepMilliSecond(100); + continue; + } + scsiq->r3.done_stat = 0; + scsiq->r3.host_stat = 0; + scsiq->r3.scsi_stat = 0; + scsiq->r3.scsi_msg = 0; + ASC_DBG1(3, "PollQueueDone: AscAbortSRB() scsiq %x\n", + (unsigned) scsiq); + + AscAbortSRB(asc_dvc, (ulong) scsiq); + } + ASC_DBG1(3, "PollQueueDone: done_stat %x\n", scsiq->r3.done_stat); + return (scsiq->r3.done_stat); + } + } while ((status == 0) || (status == 0x80)); + ASC_DBG(3, "PollQueueDone: done_stat QD_WITH_ERROR\n"); + return (scsiq->r3.done_stat = QD_WITH_ERROR); +} + +int +PollScsiInquiry( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_REQ_Q dosfar * scsiq, + uchar dosfar * buf, + int buf_len +) +{ + if (AscScsiInquiry(asc_dvc, scsiq, buf, buf_len) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); + } + return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 4)); +} + +int +PollScsiReadCapacity( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_REQ_Q dosfar * scsiq, + ASC_CAP_INFO dosfar * cap_info +) +{ + ASC_CAP_INFO scsi_cap_info; + int status; + + if (AscScsiReadCapacity(asc_dvc, scsiq, + (uchar dosfar *) & scsi_cap_info) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); + } + status = PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 8); + if (status == 1) { +#if CC_LITTLE_ENDIAN_HOST + cap_info->lba = (ulong) * swapfarbuf4((uchar dosfar *) & scsi_cap_info.lba); + cap_info->blk_size = (ulong) * swapfarbuf4((uchar dosfar *) & scsi_cap_info.blk_size); +#else + cap_info->lba = scsi_cap_info.lba; + cap_info->blk_size = scsi_cap_info.blk_size; +#endif + return (scsiq->r3.done_stat); + } + return (scsiq->r3.done_stat = QD_WITH_ERROR); +} + +ulong dosfar * +swapfarbuf4( + uchar dosfar * buf +) +{ + uchar tmp; + + tmp = buf[3]; + buf[3] = buf[0]; + buf[0] = tmp; + + tmp = buf[1]; + buf[1] = buf[2]; + buf[2] = tmp; + + return ((ulong dosfar *) buf); +} + +int +PollScsiTestUnitReady( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_REQ_Q dosfar * scsiq +) +{ + if (AscScsiTestUnitReady(asc_dvc, scsiq) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); + } + return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 12)); +} + +int +PollScsiStartUnit( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_REQ_Q dosfar * scsiq +) +{ + if (AscScsiStartStopUnit(asc_dvc, scsiq, 1) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); + } + return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 40)); +} + +int +InitTestUnitReady( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_REQ_Q dosfar * scsiq +) +{ + ASC_SCSI_BIT_ID_TYPE tid_bits; + int retry; + ASC_REQ_SENSE dosfar *sen; + + retry = 0; + tid_bits = scsiq->r1.target_id; + while (retry++ < 2) { + ASC_DBG(3, "InitTestUnitReady: PollScsiTestUnitReady()\n"); + PollScsiTestUnitReady(asc_dvc, scsiq); + ASC_DBG1(3, "InitTestUnitReady: done_stat %x\n", scsiq->r3.done_stat); + if (scsiq->r3.done_stat == 0x01) { + return (1); + } else if (scsiq->r3.done_stat == QD_WITH_ERROR) { + DvcSleepMilliSecond(100); + + sen = (ASC_REQ_SENSE dosfar *) scsiq->sense_ptr; + + if ((scsiq->r3.scsi_stat == SS_CHK_CONDITION) && + ((sen->err_code & 0x70) != 0)) { + + if (sen->sense_key == SCSI_SENKEY_NOT_READY) { + + if (asc_dvc->start_motor & tid_bits) { + if (PollScsiStartUnit(asc_dvc, scsiq) == 1) { + retry = 0; + continue; + } else { + asc_dvc->start_motor &= ~tid_bits; + break; + } + } else { + DvcSleepMilliSecond(100); + } + } else if (sen->sense_key == SCSI_SENKEY_ATTENSION) { + DvcSleepMilliSecond(100); + } else { + break; + } + } else { + break; + } + } else if (scsiq->r3.done_stat == QD_ABORTED_BY_HOST) { + break; + } else { + break; + } + } + return (0); +} + +#if CC_INIT_INQ_DISPLAY + +#endif + +int +AscPollQDone( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_REQ_Q dosfar * scsiq, + int timeout_sec +) +{ + int loop, loop_end; + int sta; + PortAddr iop_base; + + iop_base = asc_dvc->iop_base; + loop = 0; + loop_end = timeout_sec * 100; + sta = 1; + + while (TRUE) { + ASC_DBG4(3, + "AscPollQDone: loop %d, err_code %x, done_stat %x, scsi_stat %x\n", + loop, asc_dvc->err_code, scsiq->r3.done_stat, scsiq->r3.scsi_stat); + if (asc_dvc->err_code != 0) { + scsiq->r3.done_stat = QD_WITH_ERROR; + sta = ERR; + break; + } + if (scsiq->r3.done_stat != QD_IN_PROGRESS) { + if ((scsiq->r3.done_stat == QD_WITH_ERROR) && + (scsiq->r3.scsi_stat == SS_TARGET_BUSY)) { + sta = 0x80; + break; + } + break; + } + DvcSleepMilliSecond(10); + if (loop++ > loop_end) { + sta = 0; + break; + } + if (AscIsChipHalted(iop_base)) { + AscISR(asc_dvc); + loop = 0; + } else { + ASC_DBG(3, "AscPollQDone: AscIsIntPending()\n"); + if (AscIsIntPending(iop_base)) { + ASC_DBG(3, "AscPollQDone: AscISR()\n"); + AscISR(asc_dvc); + } + } + } + ASC_DBG1(3, "AscPollQDone: sta %x\n", sta); + return (sta); +} + +uchar +AscReadLramByte( + PortAddr iop_base, + ushort addr +) +{ + uchar byte_data; + ushort word_data; + + if (isodd_word(addr)) { + AscSetChipLramAddr(iop_base, addr - 1); + word_data = AscGetChipLramData(iop_base); + +#if CC_LITTLE_ENDIAN_HOST + byte_data = (uchar) ((word_data >> 8) & 0xFF); +#else + byte_data = (uchar) (word_data & 0xFF); +#endif + + } else { + AscSetChipLramAddr(iop_base, addr); + word_data = AscGetChipLramData(iop_base); + +#if CC_LITTLE_ENDIAN_HOST + byte_data = (uchar) (word_data & 0xFF); +#else + byte_data = (uchar) ((word_data >> 8) & 0xFF); +#endif + + } + return (byte_data); +} + +ushort +AscReadLramWord( + PortAddr iop_base, + ushort addr +) +{ + ushort word_data; + + AscSetChipLramAddr(iop_base, addr); + word_data = AscGetChipLramData(iop_base); + return (word_data); +} + +ulong +AscReadLramDWord( + PortAddr iop_base, + ushort addr +) +{ + ushort val_low, val_high; + ulong dword_data; + + AscSetChipLramAddr(iop_base, addr); + +#if CC_LITTLE_ENDIAN_HOST + val_low = AscGetChipLramData(iop_base); + + val_high = AscGetChipLramData(iop_base); +#else + val_high = AscGetChipLramData(iop_base); + val_low = AscGetChipLramData(iop_base); +#endif + + dword_data = ((ulong) val_high << 16) | (ulong) val_low; + return (dword_data); +} + +void +AscWriteLramWord( + PortAddr iop_base, + ushort addr, + ushort word_val +) +{ + AscSetChipLramAddr(iop_base, addr); + AscPutChipLramData(iop_base, word_val); + return; +} + +void +AscWriteLramDWord( + PortAddr iop_base, + ushort addr, + ulong dword_val +) +{ + ushort word_val; + + AscSetChipLramAddr(iop_base, addr); + +#if CC_LITTLE_ENDIAN_HOST + word_val = (ushort) dword_val; + AscPutChipLramData(iop_base, word_val); + word_val = (ushort) (dword_val >> 16); + AscPutChipLramData(iop_base, word_val); +#else + word_val = (ushort) (dword_val >> 16); + AscPutChipLramData(iop_base, word_val); + word_val = (ushort) dword_val; + AscPutChipLramData(iop_base, word_val); +#endif + return; +} + +void +AscWriteLramByte( + PortAddr iop_base, + ushort addr, + uchar byte_val +) +{ + ushort word_data; + + if (isodd_word(addr)) { + addr--; + word_data = AscReadLramWord(iop_base, addr); + word_data &= 0x00FF; + word_data |= (((ushort) byte_val << 8) & 0xFF00); + } else { + word_data = AscReadLramWord(iop_base, addr); + word_data &= 0xFF00; + word_data |= ((ushort) byte_val & 0x00FF); + } + AscWriteLramWord(iop_base, addr, word_data); + return; +} + +int +AscVerWriteLramWord( + PortAddr iop_base, + ushort addr, + ushort word_val +) +{ + int sta; + + sta = 0; + AscSetChipLramAddr(iop_base, addr); + AscPutChipLramData(iop_base, word_val); + AscSetChipLramAddr(iop_base, addr); + if (word_val != AscGetChipLramData(iop_base)) { + sta = ERR; + } + return (sta); +} + +void +AscMemWordCopyToLram( + PortAddr iop_base, + ushort s_addr, + ushort dosfar * s_buffer, + int words +) +{ + AscSetChipLramAddr(iop_base, s_addr); + DvcOutPortWords(iop_base + IOP_RAM_DATA, s_buffer, words); + return; +} + +void +AscMemDWordCopyToLram( + PortAddr iop_base, + ushort s_addr, + ulong dosfar * s_buffer, + int dwords +) +{ + AscSetChipLramAddr(iop_base, s_addr); + DvcOutPortDWords(iop_base + IOP_RAM_DATA, s_buffer, dwords); + return; +} + +void +AscMemWordCopyFromLram( + PortAddr iop_base, + ushort s_addr, + ushort dosfar * d_buffer, + int words +) +{ + AscSetChipLramAddr(iop_base, s_addr); + DvcInPortWords(iop_base + IOP_RAM_DATA, d_buffer, words); + return; +} + +ulong +AscMemSumLramWord( + PortAddr iop_base, + ushort s_addr, + rint words +) +{ + ulong sum; + int i; + + sum = 0L; + for (i = 0; i < words; i++, s_addr += 2) { + sum += AscReadLramWord(iop_base, s_addr); + } + return (sum); +} + +void +AscMemWordSetLram( + PortAddr iop_base, + ushort s_addr, + ushort set_wval, + rint words +) +{ + rint i; + + AscSetChipLramAddr(iop_base, s_addr); + for (i = 0; i < words; i++) { + AscPutChipLramData(iop_base, set_wval); + } + return; +} + +int +AscScsiInquiry( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_REQ_Q dosfar * scsiq, + uchar dosfar * buf, int buf_len +) +{ + if (AscScsiSetupCmdQ(asc_dvc, scsiq, buf, + (ulong) buf_len) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); + } + scsiq->cdb[0] = (uchar) SCSICMD_Inquiry; + scsiq->cdb[1] = scsiq->r1.target_lun << 5; + scsiq->cdb[2] = 0; + scsiq->cdb[3] = 0; + scsiq->cdb[4] = buf_len; + scsiq->cdb[5] = 0; + scsiq->r2.cdb_len = 6; + return (0); +} + +int +AscScsiReadCapacity( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_REQ_Q dosfar * scsiq, + uchar dosfar * info +) +{ + if (AscScsiSetupCmdQ(asc_dvc, scsiq, info, 8L) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); + } + scsiq->cdb[0] = (uchar) SCSICMD_ReadCapacity; + scsiq->cdb[1] = scsiq->r1.target_lun << 5; + scsiq->cdb[2] = 0; + scsiq->cdb[3] = 0; + scsiq->cdb[4] = 0; + scsiq->cdb[5] = 0; + scsiq->cdb[6] = 0; + scsiq->cdb[7] = 0; + scsiq->cdb[8] = 0; + scsiq->cdb[9] = 0; + scsiq->r2.cdb_len = 10; + return (0); +} + +int +AscScsiTestUnitReady( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_REQ_Q dosfar * scsiq +) +{ + if (AscScsiSetupCmdQ(asc_dvc, scsiq, FNULLPTR, + (ulong) 0L) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); + } + scsiq->r1.cntl = (uchar) ASC_SCSIDIR_NODATA; + scsiq->cdb[0] = (uchar) SCSICMD_TestUnitReady; + scsiq->cdb[1] = scsiq->r1.target_lun << 5; + scsiq->cdb[2] = 0; + scsiq->cdb[3] = 0; + scsiq->cdb[4] = 0; + scsiq->cdb[5] = 0; + scsiq->r2.cdb_len = 6; + return (0); +} + +int +AscScsiStartStopUnit( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ASC_SCSI_REQ_Q dosfar * scsiq, + uchar op_mode +) +{ + if (AscScsiSetupCmdQ(asc_dvc, scsiq, FNULLPTR, (ulong) 0L) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); + } + scsiq->r1.cntl = (uchar) ASC_SCSIDIR_NODATA; + scsiq->cdb[0] = (uchar) SCSICMD_StartStopUnit; + scsiq->cdb[1] = scsiq->r1.target_lun << 5; + scsiq->cdb[2] = 0; + scsiq->cdb[3] = 0; + scsiq->cdb[4] = op_mode; + + scsiq->cdb[5] = 0; + scsiq->r2.cdb_len = 6; + return (0); +} diff --git a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h new file mode 100644 index 000000000000..9d0a79dd7036 --- /dev/null +++ b/drivers/scsi/advansys.h @@ -0,0 +1,131 @@ +/* $Id: advansys.h,v 1.10 1996/01/15 04:51:06 bobf Exp bobf $ */ +/* + * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters + * + * Copyright (c) 1995-1996 Advanced System Products, Inc. + * + * This driver may be modified and freely distributed provided that + * the above copyright message and this comment are included in the + * distribution. The latest version of this driver is available at + * the AdvanSys FTP and BBS sites listed below. + * + * Please send questions, comments, and bug reports to: + * bobf@advansys.com (Bob Frey) + */ + +#ifndef _ADVANSYS_H +#define _ADVANSYS_H + +/* The driver can be used in Linux 1.2.X or 1.3.X. */ +#if !defined(LINUX_1_2) && !defined(LINUX_1_3) +#ifndef LINUX_VERSION_CODE +#include +#endif /* LINUX_VERSION_CODE */ +#if LINUX_VERSION_CODE > 65536 + 3 * 256 +#define LINUX_1_3 +#else /* LINUX_VERSION_CODE */ +#define LINUX_1_2 +#endif /* LINUX_VERSION_CODE */ +#endif /* !defined(LINUX_1_2) && !defined(LINUX_1_3) */ + +/* + * Scsi_Host_Template function prototypes. + */ +int advansys_detect(Scsi_Host_Template *); +int advansys_release(struct Scsi_Host *); +const char *advansys_info(struct Scsi_Host *); +int advansys_command(Scsi_Cmnd *); +int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +int advansys_abort(Scsi_Cmnd *); +int advansys_reset(Scsi_Cmnd *); +#ifdef LINUX_1_2 +int advansys_biosparam(Disk *, int, int[]); +#else /* LINUX_1_3 */ +int advansys_biosparam(Disk *, kdev_t, int[]); +extern struct proc_dir_entry proc_scsi_advansys; +int advansys_proc_info(char *, char **, off_t, int, int, int); +#endif /* LINUX_1_3 */ + +/* init/main.c setup function */ +void advansys_setup(char *, int *); + +/* + * AdvanSys Host Driver Scsi_Host_Template (struct SHT) from hosts.h. + */ +#ifdef LINUX_1_2 +#define ADVANSYS { \ + NULL, /* struct SHT *next */ \ + NULL, /* int *usage_count */ \ + "advansys", /* char *name */ \ + advansys_detect, /* int (*detect)(struct SHT *) */ \ + advansys_release, /* int (*release)(struct Scsi_Host *) */ \ + advansys_info, /* const char *(*info)(struct Scsi_Host *) */ \ + advansys_command, /* int (*command)(Scsi_Cmnd *) */ \ + advansys_queuecommand, \ + /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \ + advansys_abort, /* int (*abort)(Scsi_Cmnd *) */ \ + advansys_reset, /* int (*reset)(Scsi_Cmnd *) */ \ + NULL, /* int (*slave_attach)(int, int) */ \ + advansys_biosparam, /* int (* bios_param)(Disk *, int, int []) */ \ + /* \ + * The following fields are set per adapter in advansys_detect(). \ + */ \ + 0, /* int can_queue */ \ + 0, /* int this_id */ \ + 0, /* short unsigned int sg_tablesize */ \ + 0, /* short cmd_per_lun */ \ + 0, /* unsigned char present */ \ + /* \ + * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ + * must be set. The flag will be cleared in advansys_detect for non-ISA \ + * adapters. Refer to the comment in scsi_module.c for more information. \ + */ \ + 1, /* unsigned unchecked_isa_dma:1 */ \ + /* \ + * All adapters controlled by this driver are capable of large \ + * scatter-gather lists. This apparently obviates any performance + * gain provided by setting 'use_clustering'. \ + */ \ + DISABLE_CLUSTERING, /* unsigned use_clustering:1 */ \ +} +#else /* LINUX_1_3 */ +#define ADVANSYS { \ + NULL, /* struct SHT *next */ \ + NULL, /* long *usage_count */ \ + &proc_scsi_advansys, /* struct proc_dir_entry *proc_dir */ \ + advansys_proc_info, \ + /* int (*proc_info)(char *, char **, off_t, int, int, int) */ \ + "advansys", /* const char *name */ \ + advansys_detect, /* int (*detect)(struct SHT *) */ \ + advansys_release, /* int (*release)(struct Scsi_Host *) */ \ + advansys_info, /* const char *(*info)(struct Scsi_Host *) */ \ + advansys_command, /* int (*command)(Scsi_Cmnd *) */ \ + advansys_queuecommand, \ + /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \ + advansys_abort, /* int (*abort)(Scsi_Cmnd *) */ \ + advansys_reset, /* int (*reset)(Scsi_Cmnd *) */ \ + NULL, /* int (*slave_attach)(int, int) */ \ + advansys_biosparam, /* int (* bios_param)(Disk *, kdev_t, int []) */ \ + /* \ + * The following fields are set per adapter in advansys_detect(). \ + */ \ + 0, /* int can_queue */ \ + 0, /* int this_id */ \ + 0, /* short unsigned int sg_tablesize */ \ + 0, /* short cmd_per_lun */ \ + 0, /* unsigned char present */ \ + /* \ + * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ + * must be set. The flag will be cleared in advansys_detect for non-ISA \ + * adapters. Refer to the comment in scsi_module.c for more information. \ + */ \ + 1, /* unsigned unchecked_isa_dma:1 */ \ + /* \ + * All adapters controlled by this driver are capable of large \ + * scatter-gather lists. This apparently obviates any performance + * gain provided by setting 'use_clustering'. \ + */ \ + DISABLE_CLUSTERING, /* unsigned use_clustering:1 */ \ +} +#endif /* LINUX_1_3 */ +#endif /* _ADVANSYS_H */ diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 5e8d826b3a85..df08d810163f 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -15,10 +15,7 @@ * Accept parameters from LILO cmd-line. -- 1-Oct-94 */ -#ifdef MODULE -#include #include -#endif #include #include diff --git a/drivers/scsi/aic7xxx.seq b/drivers/scsi/aic7xxx.seq index 4da0c7fefa39..f5ea6aab56c2 100644 --- a/drivers/scsi/aic7xxx.seq +++ b/drivers/scsi/aic7xxx.seq @@ -136,9 +136,9 @@ CMDCMPLT = 0x02 # Command Complete SEND_REJECT = 0x11 # sending a message reject NO_IDENT = 0x21 # no IDENTIFY after reconnect NO_MATCH = 0x31 # no cmd match for reconnect -MSG_SDTR = 0x41 # SDTR message recieved -MSG_WDTR = 0x51 # WDTR message recieved -MSG_REJECT = 0x61 # Reject message recieved +MSG_SDTR = 0x41 # SDTR message received +MSG_WDTR = 0x51 # WDTR message received +MSG_REJECT = 0x61 # Reject message received BAD_STATUS = 0x71 # Bad status from target RESIDUAL = 0x81 # Residual byte count != 0 ABORT_TAG = 0x91 # Sent an ABORT_TAG message diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 661d8c41cf82..aa47bad0b589 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -41,6 +41,10 @@ #include "hosts.h" +#ifdef CONFIG_SCSI_ADVANSYS +#include "advansys.h" +#endif + #ifdef CONFIG_SCSI_AHA152X #include "aha152x.h" #endif @@ -158,6 +162,9 @@ Scsi_Host_Template * scsi_hosts = NULL; static Scsi_Host_Template builtin_scsi_hosts[] = { +#ifdef CONFIG_SCSI_ADVANSYS + ADVANSYS, +#endif /* BusLogic must come before aha1542.c */ #ifdef CONFIG_SCSI_BUSLOGIC BUSLOGIC, diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index c10bb21c23ce..fb2dd9061304 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -82,6 +82,8 @@ static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev , struct Scsi_Host *shpnt, char * scsi_result); void scsi_build_commandblocks(Scsi_Device * SDpnt); +extern struct symbol_table scsi_symbol_table; + static FreeSectorBitmap * dma_malloc_freelist = NULL; static int scsi_need_isa_bounce_buffers; @@ -395,8 +397,8 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded, /* Make sure we have something that is valid for DMA purposes */ - scsi_result = ((!dma_malloc_freelist || !shpnt->unchecked_isa_dma) - ? &scsi_result0[0] : scsi_malloc (512)); + scsi_result = ( ( !shpnt->unchecked_isa_dma ) + ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA)); if (scsi_result == NULL) { printk ("Unable to obtain scsi_result buffer\n"); @@ -489,7 +491,7 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded, /* If we allocated a buffer so we could do DMA, free it now */ if (scsi_result != &scsi_result0[0] && scsi_result != NULL) - scsi_free (scsi_result, 512); + scsi_init_free (scsi_result, 512); } @@ -2329,6 +2331,7 @@ int scsi_dev_init(void) timer_table[SCSI_TIMER].fn = scsi_main_timeout; timer_table[SCSI_TIMER].expires = 0; + register_symtab(&scsi_symbol_table); /* Register the /proc/scsi/scsi entry */ #if CONFIG_PROC_FS @@ -3117,8 +3120,6 @@ scsi_dump_status(void) #ifdef MODULE -extern struct symbol_table scsi_symbol_table; - int init_module(void) { unsigned long size; diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 90374a769dba..536534672493 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -7,10 +7,7 @@ * anything out of the ordinary is seen. */ -#ifdef MODULE -#include #include -#endif #include #include diff --git a/drivers/sound/.blurb b/drivers/sound/.blurb index 50f5ec1263f1..2af6747a9d7f 100644 --- a/drivers/sound/.blurb +++ b/drivers/sound/.blurb @@ -1,8 +1,4 @@ ********************************************************* -* IF YOU HAVE ANY PROBLEMS WITH THE SOUND DRIVER, * -* PLEASE READ THE SOUND-HOWTO. IT'S AVAILABLE FROM YOUR * -* NEAREST LINUX FTP SITE AND CONTAINS ANSWER TO YOUR * -* PROBLEM. * * Readme.cards (this directory) contains some card * * specific instructions. * ********************************************************* diff --git a/drivers/sound/.objects b/drivers/sound/.objects index a8695f2d4f46..4ba152101b52 100644 --- a/drivers/sound/.objects +++ b/drivers/sound/.objects @@ -64,14 +64,10 @@ ifdef CONFIG_PSS OBJS := $(OBJS) pss.o endif -ifdef CONFIG_SB16 - OBJS := $(OBJS) sb16_dsp.o -endif - ifdef CONFIG_SB OBJS := $(OBJS) sb16_midi.o sb_card.o sb_dsp.o sb_midi.o sb_mixer.o OBJS := $(OBJS) sb_card.o - OBJS := $(OBJS) sb_dsp.o + OBJS := $(OBJS) sb_dsp.o sb16_dsp.o OBJS := $(OBJS) sb_midi.o OBJS := $(OBJS) sb_mixer.o endif @@ -92,14 +88,14 @@ ifdef CONFIG_SSCAPE OBJS := $(OBJS) sscape.o endif -ifdef CONFIG_SEQUENCER - OBJS := $(OBJS) sys_timer.o -endif - ifdef CONFIG_TRIX OBJS := $(OBJS) trix.o endif +ifdef CONFIG_SEQUENCER + OBJS := $(OBJS) sys_timer.o +endif + ifdef CONFIG_UART6850 OBJS := $(OBJS) uart6850.o endif diff --git a/drivers/sound/.version b/drivers/sound/.version index 2a33b48270b3..dccae463dcfb 100644 --- a/drivers/sound/.version +++ b/drivers/sound/.version @@ -1,2 +1,2 @@ -3.5-alpha5 +3.5-alpha8 0x030505 diff --git a/drivers/sound/CHANGELOG b/drivers/sound/CHANGELOG index f9c32a7ac7e6..60fbb41c6d03 100644 --- a/drivers/sound/CHANGELOG +++ b/drivers/sound/CHANGELOG @@ -1,6 +1,38 @@ -Changelog for version 3.5-alpha3 +Changelog for version 3.5-alpha8 -------------------------------- +Since 3.5-alpha7 +- Linux kernel compatible configuration (_EXPERIMENTAL_). Enable + using command "cd /linux/drivers/sound;make script" and then + just run kernel's make config normally. +- Minor fixes to the SB support. Hopefully the driver works with + all SB models now. +- Added support for ESS ES1688 "AudioDrive" based cards. + +Since 3.5-alpha6 +- SB Pro and SB16 supports are no longer separately selectable options. + Enabling SB enables them too. +- Changed all #ifndef EXCLUDE_xx stuff to #ifdef CONFIG_xx. Modified +configure to handle this. +- Removed initialization messages from the +modularized version. They can be enabled by using init_trace=1 in +the insmod command line (insmod sound init_trace=1). +- More AIX stuff. +- Added support for syncronizing dsp/audio devices with /dev/sequencer. +- mmap() support for dsp/audio devices. + +Since 3.5-alpha5 +- AIX port. +- Changed some xxx_PATCH macros in soundcard.h to work with + big endian machines. + +Since 3.5-alpha4 +- Removed the 'setfx' stuff from the version distributed with kernel + sources. Running 'setfx' is required again. + +Since 3.5-alpha3 +- Moved stuff from the 'setfx' program to the AudioTriX Pro driver. + Since 3.5-alpha2 - Modifications to makefile and configure.c. Unnecessary sources are no longer compiled. Newly created local.h is also copied to diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index 63d68bfd94d3..de49f5025c7e 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -1,8 +1,12 @@ # # Sound driver configuration # -# This is really ugly: it should probably be changed -# to use the normal config script setup +#-------- +# There is another confic script which is compatible with rest of +# the kernel. It can be activated by running 'make script' in this +# directory. Please note that this is an _experimental_ feature which +# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro). +#-------- # $MAKE -C drivers/sound config || exit 1 diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index 5e3f96623aaf..8bf2ffc9240a 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -25,14 +25,6 @@ OBJS = audio.o dmabuf.o sb_dsp.o \ mad16.o mad16_sb_midi.o cs4232.o maui.o sound_pnp.o endif -ifndef HOSTCC -# -# Running outside the kernel build. -# -CC = gcc -HOSTCC = gcc -CFLAGS = -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -m486 - build: @echo Compiling modularized sound driver @@ -44,18 +36,27 @@ install: sound.o .c.o: $(CC) $(CFLAGS) -c $< -endif ifeq ($(CONFIG_SOUND),y) -OBJS += $(FIXEDOBJS) all: local.h sound.a +OBJS += $(FIXEDOBJS) + else all: endif +ifndef HOSTCC +# +# Running outside the kernel build. +# +CC = gcc +HOSTCC = gcc +CFLAGS = -D__KERNEL__ -DMODULE -DMODVERSIONS -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -m486 +else include $(TOPDIR)/Rules.make +endif sound.a: $(OBJS) -rm -f sound.a @@ -64,7 +65,7 @@ sound.a: $(OBJS) clean: rm -f core core.* *.o *.a tmp_make *~ x y z *% - rm -f configure sound_stub.c + rm -f configure sound_stub.c objects/*.o indent: for n in *.c;do echo indent $$n;indent $$n;done @@ -100,6 +101,24 @@ oldconfig: setup-$(TARGET_OS) configure # @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null @echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h +kernelconfig: setup-$(TARGET_OS) + rm -f configure + $(HOSTCC) -o configure configure.c + ./configure fixedlocal > local.h + ./configure fixeddefines > .defines + @echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h + @echo \#define SOUND_CONFIG_BY \"`whoami`\" >> local.h +# @echo \#define SOUND_CONFIG_HOST \"`hostname`\" >> local.h 2>/dev/null +# @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null + @echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h + +script: setup-$(TARGET_OS) + rm -f configure + $(HOSTCC) -o configure configure.c + ./configure script > Config.in + ./configure fixedlocal > local.h + ./configure fixeddefines > .defines + clrconf: rm -f local.h .depend synth-ld.h trix_boot.h smw-midi0001.h .defines @@ -118,4 +137,12 @@ sound.o: local.h $(FIXEDOBJS) sound.a $(LD) -r -o sound.o $(FIXEDOBJS) sound.a modules: local.h sound.o - ln -fs `pwd`/sound.o $(TOPDIR)/modules/sound.o + ln -fs `pwd`/sound.o /usr/src/linux/modules/sound.o + + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/drivers/sound/Readme b/drivers/sound/Readme index 259414357c7b..c08986977092 100644 --- a/drivers/sound/Readme +++ b/drivers/sound/Readme @@ -1,9 +1,9 @@ -VoxWare v3.5-alpha5 release notes +VoxWare v3.5-alpha4 release notes --------------------------------- IMPORTANT! This version of the driver is compatible only with Linux versions - 1.3.33 and later. It may work with earlier ones as a loadable + 1.3.58 and later. It may work with earlier ones as a loadable module but... Also this is an ALPHA test version which has not been tested @@ -33,11 +33,11 @@ them are still on my mailbox and they should be included in versions after v3.0 (I will not add aditional features before v3.0 is ready). ==================================================== -- THIS VERSION ____REQUIRES____ Linux 1.3.33 OR LATER. +- THIS VERSION ____REQUIRES____ Linux 1.3.58 OR LATER. ==================================================== - THIS VERSION MAY NOT WORK WITH Linux VERSIONS RELEASED - AFTER end of Nov 1995. If this version doesn't compile with + AFTER end of Feb 1996. If this version doesn't compile with your kernel version, please use the sound driver version included in your kernel. @@ -65,7 +65,7 @@ MediaTriX AudioTriX Pro (OPL4 and the optional effect daughtercard the snd-util-3.0.tar.gz package which does it). Ensoniq SoundScape (works but needs some improvements) MV Jazz16 based soundcards (ProSonic, 3D etc). -SoundMan Wave (recording may not work, mixer support is limited) +SoundMan Wave Mozart (OAK OTI-601 interface chip) based soundcards. MAD16 (an interface chip by OPTi) based soundcards (TB Tropez ???). (NOTE! The MAD16 looks similar to the Mozart chip. It could be a good diff --git a/drivers/sound/Readme.cards b/drivers/sound/Readme.cards index c91454788562..3d0da809d2ef 100644 --- a/drivers/sound/Readme.cards +++ b/drivers/sound/Readme.cards @@ -40,7 +40,7 @@ Sound Blasters cards in the market (July95). It's likely that your card is compatible just with SB Pro but there is also a non SB compatible 16 bit mode. Usually it's MSS/WSS but could also - be a proprietary one like MV Jazz16. + be a proprietary one like MV Jazz16 or ESS ES688. Gravis Ultrasound (GUS) GUS @@ -117,6 +117,8 @@ Ensoniq SoundScape and compatibles Several companies (including Ensoniq, Reveal and Spea) are selling cards based on this architecture. + NOTE! The new PnP SoundScape is not supported yet. + MAD16 and Mozart based cards The Mozart (OAK OTI-601) and MAD16 Pro (OPTi 82C929) interface chips are used in many different soundcards, including some @@ -337,12 +339,11 @@ select some options automaticly as well. have one of them. In addition the MAD16 chip is used in some cards made by known manufacturers such as Turtle Beach (Tropez), Reveal (some models) and Diamond (latest ones). - "SoundBlaster Pro support", - - Enable this option if your card is SB Pro or SB16. Enable it - also with any SB Pro clones. Answering 'n' saves some amount of - memory but 'y' is the safe alterative. - "SoundBlaster 16 support", - - Enable if you have a SB16 (including the AWE32). + "Support for TB Maui" + - This is just an experimental extension to the MPU401 driver. + Don't enable this option unless you are writing a .MOD + player for Maui. + "Audio Excel DSP 16 initialization support", - Don't know much about this card. Look at aedsp16.c for more info. @@ -468,6 +469,10 @@ Configuring GUS is simple. Just enable the GUS support and GUS MAX or the 16 bit daughtercard if you have them. Note that enabling the daughter card disables GUS MAX driver. +NOTE for owners of the 16 bit daughtercard: By default the daughtercard +uses /dev/dsp (and /dev/audio). Command "ln -sf /dev/dsp1 /dev/dsp" +selects the daughter card as the default device. + With just the standard GUS enabled the configuration program prompts for the I/O, IRQ and DMA numbers for the card. Use the same values than with DOS. @@ -559,23 +564,17 @@ Also the ATP has a microcontroller for the General MIDI emulation (OPL4). For this reason the driver asks for the name of a file containing the microcode (TRXPRO.HEX). This file is usually located in the directory where the DOS drivers were installed. You must have access to this file -when configuring the driver. - -IMPORTANT!!!!!!!!!!! - -The OPL4/OPL3 chip and the (optional) effects daughtercard require -initialization after boot. Since information about the effect processor -is not public, the initialization must be done by running a special program -after boot. The setfx program is distributed in Linux binary form (only) -in snd-util-3.0.tar.gz package. -It's calls ioperm() so it must be run as root. +when configuring the driver. -Another way to initialize the effects processor (and OPL4) is to boot DOS -before running Linux. +If you have the effects daughtercard, it must be initialized by running +the setfx program of snd-util-3.0.tar.gz package. This step is not required +when using the (future) binary distribution version of the driver. Ensoniq SoundScape ------------------ +NOTE! The new PnP SoundScape is not supported yet. + The SoundScape driver handles initialization of MSS and MPU supports itself so you don't need to enable other drivers than SoundScape (enable also the /dev/dsp, /dev/sequencer and MIDI supports). @@ -695,11 +694,14 @@ MIDI0001.BIN and it's located in the DOS/Windows driver directory. The file may also be called as TSUNAMI.BIN or something else (older cards?). The OPL4 synth will be inaccessible without loading the microcontroller code. -Also remember to enable MPU401 support if you want to use the OPL4 mode. + +Also remember to enable SB MPU401 support if you want to use the OPL4 mode. +(Don't enable the 'normal' MPU401 device as with some earlier driver +versions (pre 3.5-alpha8)). NOTE! Don't answer 'y' when the driver asks about SM Games support (the next question after the MIDI0001.BIN name). However - aneswering 'y' is not dangerous. + aneswering 'y' doesn't cause damage your computer so don't panic. Sound Galaxies -------------- @@ -722,6 +724,11 @@ SG NX Pro. Answer 'y' to these questions if you have one of the above 8 or There are some new Sound Galaxies in the market. I have no experience with them so read the card's manual carefully. +ESS ES1688 'AudioDrive' based cards +----------------------------------- + +Configure these cards just like SB Pro. Enable the 'SB MPU401 MIDI port' +if you want to use MIDI features of the card. Reveal cards ------------ @@ -779,12 +786,6 @@ SB but that may require a TSR which is not possible with Linux. If the card is compatible with MSS, it's a better choise. Some cards don't work in the SB and MSS modes at the same time. -There are some cards which will be supported by VoxWare sooner or later -(currently at least cards based on the ESS chipset). Such cards are -so common that there is some idea in writing the driver. Check the -VoxWare home page (http://personal.eunet.fi/pp/voxware) for latest -information. - Then there are cards which are no longer manufactured and/or which are relatively rarely used (such as the 8 bit ProAudioSpectrum models). It's extremely unlikely that such cards never get supported. @@ -837,8 +838,8 @@ for some of the banned cards. Please, don't send me messages asking if there is any plans to write a driver for the cards mentioned above. I will put any news to the VoxWare www home page (see below). -There are some common audio chipsets that are supported yet. For example -the ESS chips and Sierra Aria. It's likely that these architectures +There are some common audio chipsets that are not supported yet. For example +Sierra Aria and IBM Mwave. It's possible that these architectures get some support in future but I can't make any promises. Just look at the home page for latest info. diff --git a/drivers/sound/Readme.modules b/drivers/sound/Readme.modules index 66a92c54922c..2dab12552d1b 100644 --- a/drivers/sound/Readme.modules +++ b/drivers/sound/Readme.modules @@ -86,3 +86,14 @@ Look at Readme.linux for more info. NOTE! This method is not normally required. You should use it only when you have to use different configuration than normally. The sound= command line parameter is error phrone and not recommended. + +Debugging and tracing +--------------------- + +Modularized sound driver doesn't display messages during initialization as +the kernel compiled one does. This feature can be turned on by adding +init_trace=1 to the insmod command line. + +For example: + + insmod sound init_trace=1 diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c index 78c284192d14..9cc24033afb4 100644 --- a/drivers/sound/ad1848.c +++ b/drivers/sound/ad1848.c @@ -44,7 +44,7 @@ #define DEB1(x) #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AD1848) +#if defined(CONFIG_AD1848) #include "ad1848_mixer.h" @@ -72,6 +72,7 @@ typedef struct #define MD_4231 2 #define MD_4231A 3 #define MD_1845 4 +#define MD_4232 5 /* Mixer parameters */ int recmask; @@ -153,7 +154,8 @@ ad_write (ad1848_info * devc, int reg, int data) unsigned long flags; int timeout = 90000; - while (timeout > 0 && inb (devc->base) == 0x80) /*Are we initializing */ + while (timeout > 0 && + inb (devc->base) == 0x80) /*Are we initializing */ timeout--; save_flags (flags); @@ -436,11 +438,19 @@ ad1848_mixer_reset (ad1848_info * devc) { int i; - devc->recmask = 0; - if (devc->mode != MD_1848) - devc->supported_devices = MODE2_MIXER_DEVICES; - else - devc->supported_devices = MODE1_MIXER_DEVICES; + switch (devc->mode) + { + case MD_4231: + devc->supported_devices = MODE2_MIXER_DEVICES; + break; + + case MD_4232: + devc->supported_devices = MODE3_MIXER_DEVICES; + break; + + default: + devc->supported_devices = MODE1_MIXER_DEVICES; + } devc->supported_rec_devices = MODE1_REC_DEVICES; @@ -466,7 +476,8 @@ ad1848_mixer_ioctl (int dev, unsigned int cmd, ioctl_arg arg) if (((cmd >> 8) & 0xff) == 'M') { - if (cmd & IOC_IN) + + if (_IOC_DIR (cmd) & _IOC_WRITE) switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: @@ -570,6 +581,7 @@ ad1848_open (int dev, int mode) devc->intr_active = 0; devc->opened = 1; devc->irq_mode = 0; + ad1848_trigger (dev, 0); restore_flags (flags); /* * Mute output until the playback really starts. This decreases clicking. @@ -991,7 +1003,7 @@ ad1848_prepare_for_IO (int dev, int bsize, int bcount) restore_flags (flags); devc->xfer_count = 0; -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER if (dev == timer_installed && devc->timer_running) if ((fs & 0x01) != (old_fs & 0x01)) { @@ -1012,11 +1024,14 @@ ad1848_halt (int dev) { ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; unsigned long flags; + int timeout; save_flags (flags); cli (); ad_mute (devc); + ad_enter_MCE (devc); + ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */ ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */ ad_write (devc, 15, 0); /* Clear DMA counter */ @@ -1028,11 +1043,14 @@ ad1848_halt (int dev) ad_write (devc, 31, 0); /* Clear DMA counter */ } - ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */ + for (timeout = 0; timeout < 1000 && !(inb (io_Status (devc)) & 0x80); + timeout++); /* Wait for interrupt */ + ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */ outb (0, io_Status (devc)); /* Clear interrupt status */ outb (0, io_Status (devc)); /* Clear interrupt status */ devc->irq_mode = 0; + ad_leave_MCE (devc); /* DMAbuf_reset_dma (dev); */ restore_flags (flags); @@ -1116,6 +1134,8 @@ ad1848_detect (int io_base, int *ad_flags, sound_os_info * osp) ad1848_info *devc = &dev_info[nr_ad1848_devs]; unsigned char tmp1 = 0xff, tmp2 = 0xff; + DDB (printk ("ad1848_detect(%x)\n", io_base)); + if (ad_flags) *ad_flags = 0; @@ -1149,6 +1169,8 @@ ad1848_detect (int io_base, int *ad_flags, sound_os_info * osp) * * If the I/O address is unused, it typically returns 0xff. */ + + DDB (printk ("ad1848_detect() - step A\n")); if ((inb (devc->base) & 0x80) != 0x00) /* Not a AD1848 */ { DDB (printk ("ad1848 detect error - step A (%02x)\n", @@ -1162,6 +1184,7 @@ ad1848_detect (int io_base, int *ad_flags, sound_os_info * osp) * so try to avoid using it. */ + DDB (printk ("ad1848_detect() - step B\n")); ad_write (devc, 0, 0xaa); ad_write (devc, 1, 0x45); /* 0x55 with bit 0x10 clear */ @@ -1171,6 +1194,7 @@ ad1848_detect (int io_base, int *ad_flags, sound_os_info * osp) return 0; } + DDB (printk ("ad1848_detect() - step C\n")); ad_write (devc, 0, 0x45); ad_write (devc, 1, 0xaa); @@ -1185,6 +1209,7 @@ ad1848_detect (int io_base, int *ad_flags, sound_os_info * osp) * try to change them. */ + DDB (printk ("ad1848_detect() - step D\n")); tmp = ad_read (devc, 12); ad_write (devc, 12, (~tmp) & 0x0f); @@ -1206,6 +1231,7 @@ ad1848_detect (int io_base, int *ad_flags, sound_os_info * osp) * with CS4231. */ + DDB (printk ("ad1848_detect() - step F\n")); ad_write (devc, 12, 0); /* Mode2=disabled */ for (i = 0; i < 16; i++) @@ -1220,6 +1246,7 @@ ad1848_detect (int io_base, int *ad_flags, sound_os_info * osp) * The bit 0x80 is always 1 in CS4248 and CS4231. */ + DDB (printk ("ad1848_detect() - step G\n")); ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */ tmp1 = ad_read (devc, 12); @@ -1238,6 +1265,7 @@ ad1848_detect (int io_base, int *ad_flags, sound_os_info * osp) * * Verify that setting I0 doesn't change I16. */ + DDB (printk ("ad1848_detect() - step H\n")); ad_write (devc, 16, 0); /* Set I16 to known value */ ad_write (devc, 0, 0x45); @@ -1255,6 +1283,7 @@ ad1848_detect (int io_base, int *ad_flags, sound_os_info * osp) * Verify that some bits of I25 are read only. */ + DDB (printk ("ad1848_detect() - step I\n")); tmp1 = ad_read (devc, 25); /* Original bits */ ad_write (devc, 25, ~tmp1); /* Invert all bits */ if ((ad_read (devc, 25) & 0xe7) == (tmp1 & 0xe7)) @@ -1266,10 +1295,7 @@ ad1848_detect (int io_base, int *ad_flags, sound_os_info * osp) */ devc->chip_name = "CS4231"; -#ifdef MOZART_PORT - if (devc->base != MOZART_PORT + 4) -#endif - devc->mode = MD_4231; + devc->mode = MD_4231; /* * It could be an AD1845 or CS4231A as well. @@ -1277,6 +1303,7 @@ ad1848_detect (int io_base, int *ad_flags, sound_os_info * osp) * while the CS4231A reports different. */ + DDB (printk ("ad1848_detect() - step I\n")); id = ad_read (devc, 25) & 0xe7; switch (id) @@ -1289,12 +1316,12 @@ ad1848_detect (int io_base, int *ad_flags, sound_os_info * osp) case 0xa2: devc->chip_name = "CS4232"; - devc->mode = MD_4231A; + devc->mode = MD_4232; break; case 0xb2: devc->chip_name = "CS4232A"; - devc->mode = MD_4231A; + devc->mode = MD_4232; break; case 0x80: @@ -1326,15 +1353,18 @@ ad1848_detect (int io_base, int *ad_flags, sound_os_info * osp) } ad_write (devc, 25, tmp1); /* Restore bits */ + DDB (printk ("ad1848_detect() - step K\n")); } } + DDB (printk ("ad1848_detect() - step L\n")); if (ad_flags) { if (devc->mode != MD_1848) *ad_flags |= AD_F_CS4231; } + DDB (printk ("ad1848_detect() - Detected OK\n")); return 1; } @@ -1360,6 +1390,7 @@ ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; int i, my_dev; + ad1848_info *devc = &dev_info[nr_ad1848_devs]; if (!ad1848_detect (io_base, NULL, osp)) @@ -1402,14 +1433,17 @@ ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture for (i = 16; i < 32; i++) ad_write (devc, i, init_values[i]); - if (devc->mode == MD_4231A) + if (devc->mode == MD_4231A || devc->mode == MD_4232) ad_write (devc, 9, init_values[9] | 0x18); /* Enable full calibration */ if (devc->mode == MD_1845) ad_write (devc, 27, init_values[27] | 0x08); /* Alternate freq select enabled */ } else - ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */ + { + ad1848_pcm_operations[nr_ad1848_devs].flags &= ~DMA_DUPLEX; + ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */ + } outb (0, io_Status (devc)); /* Clear pending interrupts */ @@ -1420,7 +1454,8 @@ ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture sprintf (ad1848_pcm_operations[nr_ad1848_devs].name, "Generic audio codec (%s)", devc->chip_name); - printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name); + conf_printf2 (ad1848_pcm_operations[nr_ad1848_devs].name, + devc->base, devc->irq, dma_playback, dma_capture); if (num_audiodevs < MAX_AUDIO_DEV) { @@ -1473,7 +1508,7 @@ ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode]; nr_ad1848_devs++; -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER if (devc->mode != MD_1848 && devc->irq_ok) ad1848_tmr_install (my_dev); #endif @@ -1546,6 +1581,7 @@ ad1848_interrupt (int irq, struct pt_regs *dummy) unsigned char status; ad1848_info *devc; int dev; + int alt_stat = 0xff; if (irq < 0 || irq > 15) { @@ -1579,54 +1615,78 @@ ad1848_interrupt (int irq, struct pt_regs *dummy) if (status & 0x01) { - int alt_stat; if (devc->mode != MD_1848) - { - alt_stat = ad_read (devc, 24); - if (alt_stat & 0x40) /* Timer interrupt */ - { - devc->timer_ticks++; -#ifndef EXCLUDE_SEQUENCER - if (timer_installed == dev && devc->timer_running) - sound_timer_interrupt (); -#endif - } - } - else - alt_stat = 0xff; + alt_stat = ad_read (devc, 24); if (devc->opened && devc->irq_mode & PCM_ENABLE_INPUT && alt_stat & 0x20) { DMAbuf_inputintr (dev); } - if (devc->opened && devc->irq_mode & PCM_ENABLE_OUTPUT && alt_stat & 0x10) + if (devc->opened && devc->irq_mode & PCM_ENABLE_OUTPUT && + alt_stat & 0x10) { DMAbuf_outputintr (dev, 1); } - } - outb (0, io_Status (devc)); /* Clear interrupt status */ + if (devc->mode != MD_1848 && alt_stat & 0x40) /* Timer interrupt */ + { + devc->timer_ticks++; +#ifdef CONFIG_SEQUENCER + if (timer_installed == dev && devc->timer_running) + sound_timer_interrupt (); +#endif + } + } + if (devc->mode != MD_1848) + ad_write (devc, 24, ad_read (devc, 24) & ~alt_stat); /* Selective ack */ + else + outb (0, io_Status (devc)); /* Clear interrupt status */ } /* * Some extra code for the MS Sound System */ +void +check_opl3 (int base, struct address_info *hw_config) +{ + + if (check_region (base, 4)) + { + printk ("\n\nopl3.c: I/O port %x already in use\n\n", base); + return; + } + + if (!opl3_detect (base, hw_config->osp)) + return; + + opl3_init (0, base, hw_config->osp); + request_region (base, 4, "OPL3/OPL2"); +} + int probe_ms_sound (struct address_info *hw_config) { unsigned char tmp; + DDB (printk ("Entered probe_ms_sound(%x, %d)\n", hw_config->io_base, hw_config->card_subtype)); + if (check_region (hw_config->io_base, 8)) { printk ("MSS: I/O port conflict\n"); return 0; } -#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_MSS) + if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ + { + /* check_opl3(0x388, hw_config); */ + return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp); + } + +#if defined(CONFIG_AEDSP16) && defined(AEDSP16_MSS) /* * Initialize Audio Excel DSP 16 to MSS: before any operation * we must enable MSS I/O ports. @@ -1635,9 +1695,6 @@ probe_ms_sound (struct address_info *hw_config) InitAEDSP16_MSS (hw_config); #endif - if (hw_config->card_subtype == 1) /* Has IRQ/DMA registers */ - return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp); - /* * Check if the IO port returns valid signature. The original MS Sound * system returns 0x04 while some cards (AudioTriX Pro for example) @@ -1645,7 +1702,10 @@ probe_ms_sound (struct address_info *hw_config) */ if ((tmp = inb (hw_config->io_base + 3)) == 0xff) /* Bus float */ - return 0; + { + DDB (printk ("I/O address is inactive (%x)\n", tmp)); + return 0; + } if ((tmp & 0x3f) != 0x04 && (tmp & 0x3f) != 0x0f && (tmp & 0x3f) != 0x00) @@ -1700,11 +1760,22 @@ attach_ms_sound (long mem_start, struct address_info *hw_config) 1, 2, 0, 3 }; - int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; + int config_port = hw_config->io_base + 0; + int version_port = hw_config->io_base + 3; if (!ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp)) return mem_start; + if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ + { + ad1848_init ("MS Sound System", hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + hw_config->dma2, 0, hw_config->osp); + request_region (hw_config->io_base, 4, "WSS config"); + return mem_start; + } + /* * Set the IRQ and DMA addresses. */ @@ -1768,7 +1839,7 @@ unload_pnp_ad1848 (struct address_info *hw_config) release_region (hw_config->io_base, 4); } -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER /* * Timer stuff (for /dev/music). */ diff --git a/drivers/sound/ad1848_mixer.h b/drivers/sound/ad1848_mixer.h index aabbac738c38..3fcacf75503d 100644 --- a/drivers/sound/ad1848_mixer.h +++ b/drivers/sound/ad1848_mixer.h @@ -35,20 +35,6 @@ * (Actually this is not a mapping but rather some kind of interleaving * solution). */ -#ifdef GUSMAX_MIXER -#define MODE1_REC_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD|SOUND_MASK_IMIX) - -#define MODE1_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_MIC | \ - SOUND_MASK_CD | \ - SOUND_MASK_IGAIN | \ - SOUND_MASK_PCM|SOUND_MASK_IMIX) - -#define MODE2_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_SPEAKER | \ - SOUND_MASK_IGAIN | \ - SOUND_MASK_PCM | SOUND_MASK_IMIX) -#else /* Generic mapping */ #define MODE1_REC_DEVICES (SOUND_MASK_LINE3 | SOUND_MASK_MIC | \ SOUND_MASK_LINE1|SOUND_MASK_IMIX) @@ -61,7 +47,8 @@ SOUND_MASK_LINE3 | SOUND_MASK_SPEAKER | \ SOUND_MASK_IGAIN | \ SOUND_MASK_PCM | SOUND_MASK_IMIX) -#endif + +#define MODE3_MIXER_DEVICES (MODE2_MIXER_DEVICES | SOUND_MASK_VOLUME) struct mixer_def { unsigned int regno: 7; @@ -93,8 +80,8 @@ typedef struct mixer_def mixer_ent; #define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r) \ {{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r}} -mixer_ent mix_devices[32][2] = { /* As used in GUS MAX */ -MIX_ENT(SOUND_MIXER_VOLUME, 0, 0, 0, 0, 0, 0, 0, 0), +mixer_ent mix_devices[32][2] = { +MIX_ENT(SOUND_MIXER_VOLUME, 27, 1, 0, 4, 29, 1, 0, 4), MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0), MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0), MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5), @@ -115,11 +102,11 @@ MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5) static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] = { - 0x5a5a, /* Master Volume */ + 0x3232, /* Master Volume */ 0x3232, /* Bass */ 0x3232, /* Treble */ 0x4b4b, /* FM */ - 0x4040, /* PCM */ + 0x3232, /* PCM */ 0x4b4b, /* PC Speaker */ 0x2020, /* Ext Line */ 0x1010, /* Mic */ diff --git a/drivers/sound/adlib_card.c b/drivers/sound/adlib_card.c index 0f469f31fa14..769698560082 100644 --- a/drivers/sound/adlib_card.c +++ b/drivers/sound/adlib_card.c @@ -29,7 +29,7 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_YM3812) +#if defined(CONFIG_YM3812) long attach_adlib_card (long mem_start, struct address_info *hw_config) diff --git a/drivers/sound/aedsp16.c b/drivers/sound/aedsp16.c index 77bfbf3017a9..9dbdc1ca06d0 100644 --- a/drivers/sound/aedsp16.c +++ b/drivers/sound/aedsp16.c @@ -32,10 +32,10 @@ #include "sound_config.h" #ifndef AEDSP16_BASE -#define EXCLUDE_AEDSP16 +#undef CONFIG_AEDSP16 #endif -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AEDSP16) +#if defined(CONFIG_AEDSP16) /* READ THIS @@ -865,4 +865,4 @@ ResetAEDSP16 (void) #endif /* 0 */ -#endif /* !EXCLUDE_AEDSP16 */ +#endif /* CONFIG_AEDSP16 */ diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c index fa747b555ff2..12e071efe54c 100644 --- a/drivers/sound/audio.c +++ b/drivers/sound/audio.c @@ -29,8 +29,7 @@ #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO #include "ulaw.h" #include "coproc.h" @@ -38,14 +37,6 @@ #define ON 1 #define OFF 0 -static int wr_buff_no[MAX_AUDIO_DEV]; /* - - * != -1, if there is - * a incomplete output - * block in the queue. - */ -static int wr_buff_size[MAX_AUDIO_DEV], wr_buff_ptr[MAX_AUDIO_DEV]; - static int audio_mode[MAX_AUDIO_DEV]; static int dev_nblock[MAX_AUDIO_DEV]; /* 1 if in noblocking mode */ @@ -53,12 +44,11 @@ static int dev_nblock[MAX_AUDIO_DEV]; /* 1 if in noblocking mode */ #define AM_WRITE 1 #define AM_READ 2 -static char *wr_dma_buf[MAX_AUDIO_DEV]; static int audio_format[MAX_AUDIO_DEV]; static int local_conversion[MAX_AUDIO_DEV]; static int -set_format (int dev, long fmt) +set_format (int dev, int fmt) { if (fmt != AFMT_QUERY) { @@ -87,7 +77,7 @@ int audio_open (int dev, struct fileinfo *file) { int ret; - long bits; + int bits; int dev_type = dev & 0x0f; int mode = file->mode & O_ACCMODE; @@ -126,14 +116,24 @@ audio_open (int dev, struct fileinfo *file) else set_format (dev, bits); - wr_buff_no[dev] = -1; audio_mode[dev] = AM_NONE; - wr_buff_size[dev] = wr_buff_ptr[dev] = 0; dev_nblock[dev] = 0; return ret; } +void +sync_output (int dev) +{ + int buf_no, buf_ptr, buf_size; + char *dma_buf; + + if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0) + { + DMAbuf_start_output (dev, buf_no, buf_ptr); + } +} + void audio_release (int dev, struct fileinfo *file) { @@ -142,12 +142,7 @@ audio_release (int dev, struct fileinfo *file) dev = dev >> 4; mode = file->mode & O_ACCMODE; - if (wr_buff_no[dev] >= 0) - { - DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); - - wr_buff_no[dev] = -1; - } + sync_output (dev); if (audio_devs[dev]->coproc) audio_devs[dev]->coproc->close (audio_devs[dev]->coproc->devc, COPR_PCM); @@ -188,8 +183,9 @@ translate_bytes (const void *table, void *buff, int n) int audio_write (int dev, struct fileinfo *file, const snd_rw_buf * buf, int count) { - int c, p, l; + int c, p, l, buf_no, buf_ptr, buf_size; int err; + char *dma_buf; dev = dev >> 4; @@ -198,7 +194,6 @@ audio_write (int dev, struct fileinfo *file, const snd_rw_buf * buf, int count) if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) { /* Direction change */ - wr_buff_no[dev] = -1; } if (audio_devs[dev]->flags & DMA_DUPLEX) @@ -206,57 +201,41 @@ audio_write (int dev, struct fileinfo *file, const snd_rw_buf * buf, int count) else audio_mode[dev] = AM_WRITE; - if (!count) /* - * Flush output - */ + if (!count) /* Flush output */ { - if (wr_buff_no[dev] >= 0) - { - DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); - - wr_buff_no[dev] = -1; - } + sync_output (dev); return 0; } while (c) - { /* - * Perform output blocking - */ - if (wr_buff_no[dev] < 0) /* - * There is no incomplete buffers - */ + { + if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) < 0) { - if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], - &wr_buff_size[dev], - dev_nblock[dev])) < 0) + if ((buf_no = DMAbuf_getwrbuffer (dev, &dma_buf, + &buf_size, + dev_nblock[dev])) < 0) { /* Handle nonblocking mode */ - if (dev_nblock[dev] && wr_buff_no[dev] == -EAGAIN) + if (dev_nblock[dev] && buf_no == -EAGAIN) return p; /* No more space. Return # of accepted bytes */ - return wr_buff_no[dev]; + return buf_no; } - wr_buff_ptr[dev] = 0; + buf_ptr = 0; } l = c; - if (l > (wr_buff_size[dev] - wr_buff_ptr[dev])) - l = (wr_buff_size[dev] - wr_buff_ptr[dev]); + if (l > (buf_size - buf_ptr)) + l = (buf_size - buf_ptr); if (!audio_devs[dev]->copy_from_user) { /* * No device specific copy routine */ - memcpy_fromfs (&wr_dma_buf[dev][wr_buff_ptr[dev]], &((buf)[p]), l); + memcpy_fromfs (&dma_buf[buf_ptr], &((buf)[p]), l); } else audio_devs[dev]->copy_from_user (dev, - wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l); - - - /* - * Insert local processing here - */ + dma_buf, buf_ptr, buf, p, l); if (local_conversion[dev] == AFMT_MU_LAW) { @@ -264,22 +243,23 @@ audio_write (int dev, struct fileinfo *file, const snd_rw_buf * buf, int count) * This just allows interrupts while the conversion is running */ sti (); - translate_bytes (ulaw_dsp, (unsigned char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l); + translate_bytes (ulaw_dsp, (unsigned char *) &dma_buf[buf_ptr], l); } c -= l; p += l; - wr_buff_ptr[dev] += l; + buf_ptr += l; - if (wr_buff_ptr[dev] >= wr_buff_size[dev]) + if (buf_ptr >= buf_size) { - if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev])) < 0) + if ((err = DMAbuf_start_output (dev, buf_no, buf_ptr)) < 0) { return err; } - wr_buff_no[dev] = -1; } + else + DMAbuf_set_count (dev, buf_no, buf_ptr); } @@ -291,7 +271,7 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { int c, p, l; char *dmabuf; - int buff_no; + int buf_no; dev = dev >> 4; p = 0; @@ -299,13 +279,7 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) { - if (wr_buff_no[dev] >= 0) - { - DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); - - if (!(audio_devs[dev]->flags & DMA_DUPLEX)) - wr_buff_no[dev] = -1; - } + sync_output (dev); } if (audio_devs[dev]->flags & DMA_DUPLEX) @@ -315,15 +289,15 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) while (c) { - if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l, - dev_nblock[dev])) < 0) + if ((buf_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l, + dev_nblock[dev])) < 0) { /* Nonblocking mode handling. Return current # of bytes */ - if (dev_nblock[dev] && buff_no == -EAGAIN) + if (dev_nblock[dev] && buf_no == -EAGAIN) return p; - return buff_no; + return buf_no; } if (l > c) @@ -345,7 +319,7 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) memcpy_tofs (&((buf)[p]), dmabuf, l); - DMAbuf_rmchars (dev, buff_no, l); + DMAbuf_rmchars (dev, buf_no, l); p += l; c -= l; @@ -374,27 +348,16 @@ audio_ioctl (int dev, struct fileinfo *file, switch (cmd) { case SNDCTL_DSP_SYNC: - if (wr_buff_no[dev] >= 0) - { - DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); - - wr_buff_no[dev] = -1; - } + sync_output (dev); return DMAbuf_ioctl (dev, cmd, arg, 0); break; case SNDCTL_DSP_POST: - if (wr_buff_no[dev] >= 0) - { - DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); - - wr_buff_no[dev] = -1; - } + sync_output (dev); return 0; break; case SNDCTL_DSP_RESET: - wr_buff_no[dev] = -1; audio_mode[dev] = AM_NONE; return DMAbuf_ioctl (dev, cmd, arg, 0); break; @@ -428,14 +391,16 @@ audio_ioctl (int dev, struct fileinfo *file, { audio_buf_info info; + char *dma_buf; + int buf_no, buf_ptr, buf_size; int err = DMAbuf_ioctl (dev, cmd, (ioctl_arg) & info, 1); if (err < 0) return err; - if (wr_buff_no[dev] != -1) - info.bytes += wr_buff_size[dev] - wr_buff_ptr[dev]; + if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0) + info.bytes += buf_size - buf_ptr; memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info)); return 0; @@ -482,8 +447,10 @@ audio_init (long mem_start) } int -audio_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) +audio_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait) { + char *dma_buf; + int buf_no, buf_ptr, buf_size; dev = dev >> 4; @@ -493,7 +460,6 @@ audio_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) if (!(audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) return 0; /* Not recording */ - return DMAbuf_select (dev, file, sel_type, wait); break; @@ -501,7 +467,7 @@ audio_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) if (!(audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) return 0; /* Wrong direction */ - if (wr_buff_no[dev] != -1) + if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0) { return 1; /* There is space in the current buffer */ } @@ -518,4 +484,3 @@ audio_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) #endif -#endif diff --git a/drivers/sound/configure.c b/drivers/sound/configure.c index 9c1eefede236..954918226062 100644 --- a/drivers/sound/configure.c +++ b/drivers/sound/configure.c @@ -1,4 +1,4 @@ -#define DISABLED_OPTIONS (B(OPT_PNP)) +#define DISABLED_OPTIONS (B(OPT_PNP)|B(OPT_AEDSP16)) /* * sound/configure.c - Configuration program for the Linux Sound Driver * @@ -67,6 +67,7 @@ #define OPT_SEQUENCER 24 #define OPT_LAST 24 /* Last defined OPT number */ +#define DUMMY_OPTS (B(OPT_MIDI_AUTO)|B(OPT_YM3812_AUTO)) #define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)| \ B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)| \ @@ -204,10 +205,13 @@ extra_options[] = char *oldconf = "/etc/soundconf"; int old_config_used = 0; +int def_size, sb_base = 0; unsigned long selected_options = 0; int sb_dma = 0; +int dump_only = 0; + void build_defines (void); #include "hex2hex.h" @@ -242,8 +246,7 @@ think_positively (int def_answ) fprintf (stderr, "\n\nERROR! Cannot read stdin\n"); perror ("stdin"); - printf ("#undef CONFIGURE_SOUNDCARD\n"); - printf ("#undef KERNEL_SOUNDCARD\n"); + printf ("invalid_configuration__run_make_config_again\n"); exit (-1); } @@ -273,8 +276,7 @@ play_it_again_Sam: fprintf (stderr, "\n\nERROR! Cannot read stdin\n"); perror ("stdin"); - printf ("#undef CONFIGURE_SOUNDCARD\n"); - printf ("#undef KERNEL_SOUNDCARD\n"); + printf ("invalid_configuration__run_make_config_again\n"); exit (-1); } @@ -294,6 +296,74 @@ play_it_again_Sam: return num; } +#define FMT_HEX 1 +#define FMT_INT 2 + +void +ask_int_choice (int mask, char *macro, + char *question, + int format, + int defa, + char *choices) +{ + int num, i; + + if (dump_only) + { + + for (i = 0; i < OPT_LAST; i++) + if (mask == B (i)) + { + int j; + + for (j = 0; j < strlen (choices); j++) + if (choices[j] == '\'') + choices[j] = '_'; + + printf ("\nif [ \"$CONFIG_%s\" = \"y\" ]; then\n", + hw_table[i].macro); + if (format == FMT_INT) + printf ("int '%s %s' %s %d\n", question, choices, macro, defa); + else + printf ("hex '%s %s' %s %x\n", question, choices, macro, defa); + printf ("fi\n"); + } + } + else + { + if (!(mask & selected_options)) + return; + + fprintf (stderr, "\n%s\n", question); + fprintf (stderr, "Possible values are: %s\n", choices); + + if (format == FMT_INT) + { + if (defa == -1) + fprintf (stderr, "\t(-1 disables this feature)\n"); + fprintf (stderr, "The default value is %d\n", defa); + fprintf (stderr, "Enter the value: "); + num = ask_value ("%d", defa); + if (num == -1) + return; + fprintf (stderr, "%s set to %d.\n", question, num); + printf ("#define %s %d\n", macro, num); + } + else + { + if (defa == 0) + fprintf (stderr, "\t(0 disables this feature)\n"); + fprintf (stderr, "The default value is %x\n", defa); + fprintf (stderr, "Enter the value: "); + num = ask_value ("%x", defa); + if (num == 0) + return; + fprintf (stderr, "%s set to %x.\n", question, num); + printf ("#define %s 0x%x\n", macro, num); + } + } +} + void rebuild_file (char *line) { @@ -398,10 +468,30 @@ use_old_config (char *filename) if (strcmp (tmp, "SELECTED_SOUND_OPTIONS") == 0) continue; + if (strcmp (tmp, "KERNEL_SOUNDCARD") == 0) + continue; + tmp[8] = 0; /* Truncate the string */ if (strcmp (tmp, "EXCLUDE_") == 0) continue; /* Skip excludes */ + strncpy (tmp, id, i); + tmp[7] = 0; /* Truncate the string */ + + if (strcmp (tmp, "CONFIG_") == 0) + { + strncpy (tmp, &id[7], i - 7); + tmp[i - 7] = 0; + + for (i = 0; i <= OPT_LAST; i++) + if (strcmp (hw_table[i].macro, tmp) == 0) + { + selected_options |= (1 << i); + break; + } + continue; + } + printf ("%s", buf); continue; } @@ -416,7 +506,11 @@ use_old_config (char *filename) i++; strncpy (tmp, id, i); - tmp[i] = 0; + tmp[7] = 0; /* Truncate the string */ + if (strcmp (tmp, "CONFIG_") == 0) + continue; + + strncpy (tmp, id, i); tmp[8] = 0; /* Truncate the string */ if (strcmp (tmp, "EXCLUDE_") != 0) @@ -440,9 +534,9 @@ use_old_config (char *filename) for (i = 0; i <= OPT_LAST; i++) if (!hw_table[i].alias) if (selected_options & B (i)) - printf ("#undef EXCLUDE_%s\n", hw_table[i].macro); + printf ("#define CONFIG_%s\n", hw_table[i].macro); else - printf ("#define EXCLUDE_%s\n", hw_table[i].macro); + printf ("#undef CONFIG_%s\n", hw_table[i].macro); printf ("\n"); @@ -452,9 +546,9 @@ use_old_config (char *filename) while (extra_options[i].name != NULL) { if (selected_options & extra_options[i].mask) - printf ("#undef EXCLUDE_%s\n", extra_options[i].name); + printf ("#define CONFIG_%s\n", extra_options[i].name); else - printf ("#define EXCLUDE_%s\n", extra_options[i].name); + printf ("#undef CONFIG_%s\n", extra_options[i].name); i++; } @@ -502,16 +596,484 @@ build_defines (void) fclose (optf); } +void +ask_parameters (void) +{ + int num; + + build_defines (); + /* + * IRQ and DMA settings + */ + + ask_int_choice (B (OPT_AEDSP16), "AEDSP16_BASE", + "I/O base for Audio Excel DSP 16", + FMT_HEX, + 0x220, + "220 or 240"); + + ask_int_choice (B (OPT_SB), "SBC_BASE", + "I/O base for SB", + FMT_HEX, + 0x220, + ""); + + ask_int_choice (B (OPT_SB), "SBC_IRQ", + "SoundBlaster IRQ", + FMT_INT, + 7, + ""); + + ask_int_choice (B (OPT_SB), "SBC_DMA", + "SoundBlaster DMA", + FMT_INT, + 1, + ""); + + ask_int_choice (B (OPT_SB), "SB_DMA2", + "SoundBlaster 16 bit DMA (if required)", + FMT_INT, + -1, + "5, 6 or 7"); + + ask_int_choice (B (OPT_SB), "SB_MPU_BASE", + "MPU401 I/O base of SB16, Jazz16 and ES1688", + FMT_HEX, + 0, + ""); + + ask_int_choice (B (OPT_SB), "SB_MPU_IRQ", + "SB MPU401 IRQ (SB16, Jazz16 and ES1688)", + FMT_INT, + -1, + ""); + + ask_int_choice (B (OPT_PAS), "PAS_IRQ", + "PAS16 IRQ", + FMT_INT, + 10, + ""); + + ask_int_choice (B (OPT_PAS), "PAS_DMA", + "PAS16 DMA", + FMT_INT, + 3, + ""); + + if (selected_options & B (OPT_PAS)) + { + fprintf (stderr, "\nEnable Joystick port on ProAudioSpectrum (n/y) ? "); + if (think_positively (0)) + printf ("#define PAS_JOYSTICK_ENABLE\n"); + + + fprintf (stderr, "PAS16 could be noisy with some mother boards\n" + "There is a command line switch (was it :T?)\n" + "in the DOS driver for PAS16 which solves this.\n" + "Don't enable this feature unless you have problems!\n" + "Do you have to use this switch with DOS (y/n) ?"); + if (think_positively (0)) + printf ("#define BROKEN_BUS_CLOCK\n"); + } + + + ask_int_choice (B (OPT_GUS), "GUS_BASE", + "I/O base for Gravis UltraSound (GUS)", + FMT_HEX, + 0x220, + "210, 220, 230, 240, 250 or 260"); + + + ask_int_choice (B (OPT_GUS), "GUS_IRQ", + "GUS IRQ", + FMT_INT, + 15, + ""); + + ask_int_choice (B (OPT_GUS), "GUS_DMA", + "GUS DMA", + FMT_INT, + 6, + ""); + + ask_int_choice (B (OPT_GUS), "GUS_DMA2", + "Second DMA channel for GUS", + FMT_INT, + -1, + ""); + + ask_int_choice (B (OPT_GUS16), "GUS16_BASE", + "I/O base for the 16 bit daughtercard of GUS", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + + ask_int_choice (B (OPT_GUS16), "GUS16_IRQ", + "GUS 16 bit daughtercard IRQ", + FMT_INT, + 7, + "3, 4, 5, 7, or 9"); + + ask_int_choice (B (OPT_GUS16), "GUS16_DMA", + "GUS DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice (B (OPT_MPU401), "MPU_BASE", + "I/O base for MPU401", + FMT_HEX, + 0x330, + ""); + + ask_int_choice (B (OPT_MPU401), "MPU_IRQ", + "MPU401 IRQ", + FMT_INT, + 9, + ""); + + ask_int_choice (B (OPT_MAUI), "MAUI_BASE", + "I/O base for Maui", + FMT_HEX, + 0x330, + "210, 230, 260, 290, 300, 320, 338 or 330"); + + ask_int_choice (B (OPT_MAUI), "MAUI_IRQ", + "Maui IRQ", + FMT_INT, + 9, + "5, 9, 12 or 15"); + + ask_int_choice (B (OPT_UART6850), "U6850_BASE", + "I/O base for UART 6850 MIDI port", + FMT_HEX, + 0, + "(Unknown)"); + + ask_int_choice (B (OPT_UART6850), "U6850_IRQ", + "UART6850 IRQ", + FMT_INT, + -1, + "(Unknown)"); + + ask_int_choice (B (OPT_PSS), "PSS_BASE", + "PSS I/O base", + FMT_HEX, + 0x220, + "220 or 240"); + + ask_int_choice (B (OPT_PSS), "PSS_MSS_BASE", + "PSS audio I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice (B (OPT_PSS), "PSS_MSS_IRQ", + "PSS audio IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice (B (OPT_PSS), "PSS_MSS_DMA", + "PSS audio DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice (B (OPT_PSS), "PSS_MPU_BASE", + "PSS MIDI I/O base", + FMT_HEX, + 0x330, + ""); + + ask_int_choice (B (OPT_PSS), "PSS_MPU_IRQ", + "PSS MIDI IRQ", + FMT_INT, + 9, + "3, 4, 5, 7 or 9"); + + ask_int_choice (B (OPT_MSS), "MSS_BASE", + "MSS/WSS I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice (B (OPT_MSS), "MSS_IRQ", + "MSS/WSS IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice (B (OPT_MSS), "MSS_DMA", + "MSS/WSS DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice (B (OPT_SSCAPE), "SSCAPE_BASE", + "Soundscape MIDI I/O base", + FMT_HEX, + 0x330, + ""); + + ask_int_choice (B (OPT_SSCAPE), "SSCAPE_IRQ", + "Soundscape MIDI IRQ", + FMT_INT, + 9, + ""); + + ask_int_choice (B (OPT_SSCAPE), "SSCAPE_DMA", + "Soundscape initialization DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_BASE", + "Soundscape audio I/O base", + FMT_HEX, + 0x534, + "534, 608, E84 or F44"); + + ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_IRQ", + "Soundscape audio IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_DMA", + "Soundscape audio DMA", + FMT_INT, + 0, + "0, 1 or 3"); + + if (selected_options & B (OPT_SSCAPE)) + { + int reveal_spea; + + fprintf (stderr, "Is your SoundScape card made/marketed by Reveal or Spea? "); + reveal_spea = think_positively (0); + if (reveal_spea) + printf ("#define REVEAL_SPEA\n"); + + } + + ask_int_choice (B (OPT_TRIX), "TRIX_BASE", + "AudioTriX audio I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice (B (OPT_TRIX), "TRIX_IRQ", + "AudioTriX audio IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice (B (OPT_TRIX), "TRIX_DMA", + "AudioTriX audio DMA", + FMT_INT, + 0, + "0, 1 or 3"); + + ask_int_choice (B (OPT_TRIX), "TRIX_DMA2", + "AudioTriX second (duplex) DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice (B (OPT_TRIX), "TRIX_MPU_BASE", + "AudioTriX MIDI I/O base", + FMT_HEX, + 0x330, + "330, 370, 3B0 or 3F0"); + + ask_int_choice (B (OPT_TRIX), "TRIX_MPU_IRQ", + "AudioTriX MIDI IRQ", + FMT_INT, + 9, + "3, 4, 5, 7 or 9"); + + ask_int_choice (B (OPT_TRIX), "TRIX_SB_BASE", + "AudioTriX SB I/O base", + FMT_HEX, + 0x220, + "220, 210, 230, 240, 250, 260 or 270"); + + ask_int_choice (B (OPT_TRIX), "TRIX_SB_IRQ", + "AudioTriX SB IRQ", + FMT_INT, + 7, + "3, 4, 5 or 7"); + + ask_int_choice (B (OPT_TRIX), "TRIX_SB_DMA", + "AudioTriX SB DMA", + FMT_INT, + 1, + "1 or 3"); + + ask_int_choice (B (OPT_CS4232), "CS4232_BASE", + "CS4232 audio I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice (B (OPT_CS4232), "CS4232_IRQ", + "CS4232 audio IRQ", + FMT_INT, + 11, + "5, 7, 9, 11, 12 or 15"); + + ask_int_choice (B (OPT_CS4232), "CS4232_DMA", + "CS4232 audio DMA", + FMT_INT, + 0, + "0, 1 or 3"); + + ask_int_choice (B (OPT_CS4232), "CS4232_DMA2", + "CS4232 second (duplex) DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice (B (OPT_CS4232), "CS4232_MPU_BASE", + "CS4232 MIDI I/O base", + FMT_HEX, + 0x330, + "330, 370, 3B0 or 3F0"); + + ask_int_choice (B (OPT_CS4232), "CS4232_MPU_IRQ", + "CS4232 MIDI IRQ", + FMT_INT, + 9, + "5, 7, 9, 11, 12 or 15"); + + ask_int_choice (B (OPT_MAD16), "MAD16_BASE", + "MAD16 audio I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice (B (OPT_MAD16), "MAD16_IRQ", + "MAD16 audio IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice (B (OPT_MAD16), "MAD16_DMA", + "MAD16 audio DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice (B (OPT_MAD16), "MAD16_DMA2", + "MAD16 second (duplex) DMA", + FMT_INT, + 0, + "0, 1 or 3"); + + ask_int_choice (B (OPT_MAD16), "MAD16_MPU_BASE", + "MAD16 MIDI I/O base", + FMT_HEX, + 0x330, + "300, 310, 320 or 330 (0 disables)"); + + ask_int_choice (B (OPT_MAD16), "MAD16_MPU_IRQ", + "MAD16 MIDI IRQ", + FMT_INT, + 9, + "5, 7, 9 or 10"); + ask_int_choice (B (OPT_AUDIO), "DSP_BUFFSIZE", + "Audio DMA buffer size", + FMT_INT, + 65536, + "4096, 16384, 32768 or 65536"); +} + +void +dump_script (void) +{ + int i; + + for (i = 0; i <= OPT_LAST; i++) + if (!(DUMMY_OPTS & B (i))) + if (!(DISABLED_OPTIONS & B (i))) + { + printf ("bool '%s' CONFIG_%s\n", questions[i], hw_table[i].macro); + } + + dump_only = 1; + selected_options = 0; + ask_parameters (); + + printf ("#\n$MAKE -C drivers/sound kernelconfig || exit 1\n"); +} + +void +dump_fixed_local (void) +{ + int i = 0; + + printf ("/* Computer generated file. Please don't edit! */\n\n"); + printf ("#define KERNEL_COMPATIBLE_CONFIG\n\n"); + printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n\n", selected_options); + + while (extra_options[i].name != NULL) + { + int n = 0, j; + + printf ("#if "); + + for (j = 0; j < OPT_LAST; j++) + if (!(DISABLED_OPTIONS & B (j))) + if (extra_options[i].mask & B (j)) + { + if (n) + printf (" || "); + if (!(n++ % 2)) + printf ("\\\n "); + + printf ("defined(CONFIG_%s)", hw_table[j].macro); + } + + printf ("\n"); + printf ("#\tdefine CONFIG_%s\n", extra_options[i].name); + printf ("#endif\n\n"); + i++; + } +} + +void +dump_fixed_defines (void) +{ + int i = 0; + + printf ("# Computer generated file. Please don't edit\n\n"); + + while (extra_options[i].name != NULL) + { + int n = 0, j; + + for (j = 0; j < OPT_LAST; j++) + if (!(DISABLED_OPTIONS & B (j))) + if (extra_options[i].mask & B (j)) + { + printf ("ifdef CONFIG_%s\n", hw_table[j].macro); + printf ("CONFIG_%s=y\n", extra_options[i].name); + printf ("endif\n\n"); + } + + i++; + } +} + int main (int argc, char *argv[]) { - int i, num, def_size, full_driver = 1; + int i, num, full_driver = 1; char answ[10]; - int sb_base = 0; char old_config_file[200]; - fprintf (stderr, "\nConfiguring the sound support\n\n"); - if (getuid () != 0) /* Not root */ { char *home; @@ -528,8 +1090,25 @@ main (int argc, char *argv[]) if (strcmp (argv[1], "-o") == 0 && use_old_config (oldconf)) exit (0); + else if (strcmp (argv[1], "script") == 0) + { + dump_script (); + exit (0); + } + else if (strcmp (argv[1], "fixedlocal") == 0) + { + dump_fixed_local (); + exit (0); + } + else if (strcmp (argv[1], "fixeddefines") == 0) + { + dump_fixed_defines (); + exit (0); + } } + fprintf (stderr, "\nConfiguring the sound support\n\n"); + if (access (oldconf, R_OK) == 0) { fprintf (stderr, "Old configuration exists in %s. Use it (y/n) ? ", @@ -540,7 +1119,10 @@ main (int argc, char *argv[]) } - printf ("/*\tGenerated by configure. Don't edit!!!!\t*/\n\n"); + printf ("/*\tGenerated by configure. Don't edit!!!!\t*/\n"); + printf ("/*\tMaking changes to this file is not as simple as it may look.\t*/\n\n"); + printf ("/*\tIf you change the CONFIG_ settings in local.h you\t*/\n"); + printf ("/*\t_have_ to edit .defines too.\t*/\n\n"); { /* @@ -590,18 +1172,6 @@ main (int argc, char *argv[]) fprintf (stderr, "Do you want support for the MV Jazz16 (ProSonic etc.) ? "); if (think_positively (0)) { - printf ("#define JAZZ16\n"); - do - { - fprintf (stderr, "\tValid 16 bit DMA channels for ProSonic/Jazz 16 are\n"); - fprintf (stderr, "\t1, 3, 5 (default), 7\n"); - fprintf (stderr, "\tEnter 16bit DMA channel for Prosonic : "); - num = ask_value ("%d", 5); - } - while (num != 1 && num != 3 && num != 5 && num != 7); - fprintf (stderr, "ProSonic 16 bit DMA set to %d\n", num); - printf ("#define JAZZ_DMA16 %d\n", num); - fprintf (stderr, "Do you have SoundMan Wave (n/y) ? "); if (think_positively (0)) @@ -687,9 +1257,8 @@ main (int argc, char *argv[]) if (sel1 == 0) { - printf ("#undef CONFIGURE_SOUNDCARD\n"); - printf ("#undef KERNEL_SOUNDCARD\n"); - fprintf (stderr, "ERROR!!!!!\nYou loose: you must select at least one mode when using Audio Excel!\n"); + printf ("invalid_configuration__run_make_config_again\n"); + fprintf (stderr, "ERROR!!!!!\nYou must select at least one mode when using Audio Excel!\n"); exit (-1); } if (selected_options & B (OPT_MPU401)) @@ -769,20 +1338,17 @@ main (int argc, char *argv[]) if (!(selected_options & ANY_DEVS)) { - printf ("#undef CONFIGURE_SOUNDCARD\n"); - printf ("#undef KERNEL_SOUNDCARD\n"); + printf ("invalid_configuration__run_make_config_again\n"); fprintf (stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n\n"); exit (0); } - else - printf ("#define KERNEL_SOUNDCARD\n"); for (i = 0; i <= OPT_LAST; i++) if (!hw_table[i].alias) if (selected_options & B (i)) - printf ("#undef EXCLUDE_%s\n", hw_table[i].macro); + printf ("#define CONFIG_%s\n", hw_table[i].macro); else - printf ("#define EXCLUDE_%s\n", hw_table[i].macro); + printf ("#undef CONFIG_%s\n", hw_table[i].macro); printf ("\n"); @@ -792,922 +1358,15 @@ main (int argc, char *argv[]) while (extra_options[i].name != NULL) { if (selected_options & extra_options[i].mask) - printf ("#undef EXCLUDE_%s\n", extra_options[i].name); + printf ("#define CONFIG_%s\n", extra_options[i].name); else - printf ("#define EXCLUDE_%s\n", extra_options[i].name); + printf ("#undef CONFIG_%s\n", extra_options[i].name); i++; } printf ("\n"); - - - build_defines (); - /* - * IRQ and DMA settings - */ - - if (selected_options & B (OPT_AEDSP16)) - { - fprintf (stderr, "\nI/O base for Audio Excel DSP 16 ?\n" - "Warning:\n" - "If you are using Audio Excel SoundBlaster emulation,\n" - "you must use the same I/O base for Audio Excel and SoundBlaster.\n" - "The factory default is 220 (other possible value is 240)\n" - "Enter the Audio Excel DSP 16 I/O base: "); - - num = ask_value ("%x", 0x220); - fprintf (stderr, "Audio Excel DSP 16 I/O base set to %03x\n", num); - printf ("#define AEDSP16_BASE 0x%03x\n", num); - } - - if ((selected_options & B (OPT_SB)) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI))) - { - fprintf (stderr, "\nI/O base for SB?\n" - "The factory default is 220\n" - "Enter the SB I/O base: "); - - sb_base = num = ask_value ("%x", 0x220); - fprintf (stderr, "SB I/O base set to %03x\n", num); - printf ("#define SBC_BASE 0x%03x\n", num); - - fprintf (stderr, "\nIRQ number for SoundBlaster?\n" - "The IRQ address is defined by the jumpers on your card.\n" - "The factory default is either 5 or 7 (depending on the model).\n" - "Valid values are 9(=2), 5, 7 and 10.\n" - "Enter the value: "); - - num = ask_value ("%d", 7); - if (num != 9 && num != 5 && num != 7 && num != 10) - { - - fprintf (stderr, "*** Illegal input! ***\n"); - num = 7; - } - fprintf (stderr, "SoundBlaster IRQ set to %d\n", num); - - printf ("#define SBC_IRQ %d\n", num); - - if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS))) - { - fprintf (stderr, "\nDMA channel for SoundBlaster?\n" - "For SB 1.0, 1.5 and 2.0 this MUST be 1\n" - "SB Pro supports DMA channels 0, 1 and 3 (jumper)\n" - "For SB16 give the 8 bit DMA# here\n" - "The default value is 1\n" - "Enter the value: "); - - num = ask_value ("%d", 1); - if (num < 0 || num > 3) - { - - fprintf (stderr, "*** Illegal input! ***\n"); - num = 1; - } - fprintf (stderr, "SoundBlaster DMA set to %d\n", num); - printf ("#define SBC_DMA %d\n", num); - sb_dma = num; - } - - if (selected_options & B (OPT_SB16)) - { - - fprintf (stderr, "\n16 bit DMA channel for SoundBlaster 16?\n" - "Possible values are 5, 6 or 7\n" - "The default value is 6\n" - "Enter the value: "); - - num = ask_value ("%d", 6); - if ((num < 5 || num > 7) && (num != sb_dma)) - { - - fprintf (stderr, "*** Illegal input! ***\n"); - num = 6; - } - fprintf (stderr, "SoundBlaster DMA set to %d\n", num); - printf ("#define SB16_DMA %d\n", num); - - fprintf (stderr, "\nI/O base for SB16 Midi?\n" - "Possible values are 300 and 330\n" - "The factory default is 330\n" - "Enter the SB16 Midi I/O base: "); - - num = ask_value ("%x", 0x330); - fprintf (stderr, "SB16 Midi I/O base set to %03x\n", num); - printf ("#define SB16MIDI_BASE 0x%03x\n", num); - } - } - - if (selected_options & B (OPT_PAS)) - { - - if (selected_options & (B (OPT_AUDIO) | B (OPT_MIDI))) - { - fprintf (stderr, "\nIRQ number for ProAudioSpectrum?\n" - "The recommended value is the IRQ used under DOS.\n" - "Please refer to the ProAudioSpectrum User's Guide.\n" - "The default value is 10.\n" - "Enter the value: "); - - num = ask_value ("%d", 10); - if (num == 6 || num < 3 || num > 15 || num == 2) /* - * Illegal - */ - { - - fprintf (stderr, "*** Illegal input! ***\n"); - num = 10; - } - fprintf (stderr, "ProAudioSpectrum IRQ set to %d\n", num); - printf ("#define PAS_IRQ %d\n", num); - } - - if (selected_options & B (OPT_AUDIO)) - { - fprintf (stderr, "\nDMA number for ProAudioSpectrum?\n" - "The recommended value is the DMA channel under DOS.\n" - "Please refer to the ProAudioSpectrum User's Guide.\n" - "The default value is 3\n" - "Enter the value: "); - - num = ask_value ("%d", 3); - if (num == 4 || num < 0 || num > 7) - { - - fprintf (stderr, "*** Illegal input! ***\n"); - num = 3; - } - fprintf (stderr, "\nProAudioSpectrum DMA set to %d\n", num); - printf ("#define PAS_DMA %d\n", num); - } - fprintf (stderr, "\nEnable Joystick port on ProAudioSpectrum (n/y) ? "); - if (think_positively (0)) - printf ("#define PAS_JOYSTICK_ENABLE\n"); - - fprintf (stderr, "PAS16 could be noisy with some mother boards\n" - "There is a command line switch (was it :T?)\n" - "in the DOS driver for PAS16 which solves this.\n" - "Don't enable this feature unless you have problems!\n" - "Do you have to use this switch with DOS (y/n) ?"); - if (think_positively (0)) - printf ("#define BROKEN_BUS_CLOCK\n"); - } - - if (selected_options & B (OPT_GUS)) - { - fprintf (stderr, "\nI/O base for Gravis Ultrasound?\n" - "Valid choices are 210, 220, 230, 240, 250 or 260\n" - "The factory default is 220\n" - "Enter the GUS I/O base: "); - - num = ask_value ("%x", 0x220); - if ((num > 0x260) || ((num & 0xf0f) != 0x200) || ((num & 0x0f0) > 0x060)) - { - - fprintf (stderr, "*** Illegal input! ***\n"); - num = 0x220; - } - - if ((selected_options & B (OPT_SB)) && (num == sb_base)) - { - fprintf (stderr, "FATAL ERROR!!!!!!!!!!!!!!\n" - "\t0x220 cannot be used if SoundBlaster is enabled.\n" - "\tRun the config again.\n"); - printf ("#undef CONFIGURE_SOUNDCARD\n"); - printf ("#undef KERNEL_SOUNDCARD\n"); - exit (-1); - } - fprintf (stderr, "GUS I/O base set to %03x\n", num); - printf ("#define GUS_BASE 0x%03x\n", num); - - fprintf (stderr, "\nIRQ number for Gravis UltraSound?\n" - "The recommended value is the IRQ used under DOS.\n" - "Please refer to the Gravis Ultrasound User's Guide.\n" - "The default value is 15.\n" - "Enter the value: "); - - num = ask_value ("%d", 15); - if (num == 6 || num < 3 || num > 15 || num == 2) /* - * Invalid - */ - { - - fprintf (stderr, "*** Illegal input! ***\n"); - num = 15; - } - fprintf (stderr, "Gravis UltraSound IRQ set to %d\n", num); - printf ("#define GUS_IRQ %d\n", num); - - fprintf (stderr, "\nDMA number for Gravis UltraSound?\n" - "The recommended value is the DMA channel under DOS.\n" - "Please refer to the Gravis Ultrasound User's Guide.\n" - "The default value is 6\n" - "Enter the value: "); - - num = ask_value ("%d", 6); - if (num == 4 || num < 0 || num > 7) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 6; - } - fprintf (stderr, "\nGravis UltraSound DMA set to %d\n", num); - printf ("#define GUS_DMA %d\n", num); - - fprintf (stderr, "\nSecond DMA channel for GUS (optional)?\n" - "The default value is 7 (-1 disables)\n" - "Enter the value: "); - - num = ask_value ("%d", 7); - if (num > 7) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 7; - } - - fprintf (stderr, "\nGUS DMA2 set to %d\n", num); - printf ("#define GUS_DMA2 %d\n", num); - - if (selected_options & B (OPT_GUS16)) - { - fprintf (stderr, "\nI/O base for GUS16 (GUS 16 bit sampling option)?\n" - "The factory default is 530\n" - "Other possible values are 604, E80 or F40\n" - "Enter the GUS16 I/O base: "); - - num = ask_value ("%x", 0x530); - fprintf (stderr, "GUS16 I/O base set to %03x\n", num); - printf ("#define GUS16_BASE 0x%03x\n", num); - - fprintf (stderr, "\nIRQ number for GUS16?\n" - "Valid numbers are: 3, 4, 5, 7, or 9(=2).\n" - "The default value is 7.\n" - "Enter the value: "); - - num = ask_value ("%d", 7); - if (num == 6 || num < 3 || num > 15) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 7; - } - fprintf (stderr, "GUS16 IRQ set to %d\n", num); - printf ("#define GUS16_IRQ %d\n", num); - - fprintf (stderr, "\nDMA number for GUS16?\n" - "The default value is 3\n" - "Enter the value: "); - - num = ask_value ("%d", 3); - if (num < 0 || num > 3) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 3; - } - fprintf (stderr, "\nGUS16 DMA set to %d\n", num); - printf ("#define GUS16_DMA %d\n", num); - } - } - - if (selected_options & B (OPT_MPU401)) - { - fprintf (stderr, "\nI/O base for MPU-401?\n" - "The factory default is 330\n" - "Enter the MPU-401 I/O base: "); - - num = ask_value ("%x", 0x330); - fprintf (stderr, "MPU-401 I/O base set to %03x\n", num); - printf ("#define MPU_BASE 0x%03x\n", num); - - fprintf (stderr, "\nIRQ number for MPU-401?\n" - "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n" - "The default value is 9.\n" - "Enter the value: "); - - num = ask_value ("%d", 9); - if (num == 6 || num < 3 || num > 15) - { - - fprintf (stderr, "*** Illegal input! ***\n"); - num = 5; - } - fprintf (stderr, "MPU-401 IRQ set to %d\n", num); - printf ("#define MPU_IRQ %d\n", num); - } - - if (selected_options & B (OPT_MAUI)) - { - fprintf (stderr, "\nI/O base for TB Maui (MIDI I/O of TB Tropez)?\n" - "The factory default is 330\n" - "Valid alternatives are 210, 230, 260, 290, 300, 320, 338 and 330\n" - "Enter the Maui/Tropez MIDI I/O base: "); - - num = ask_value ("%x", 0x330); - fprintf (stderr, "Maui I/O base set to %03x\n", num); - printf ("#define MAUI_BASE 0x%03x\n", num); - - fprintf (stderr, "\nIRQ number for TB Maui (TB Tropez MIDI)?\n" - "Valid numbers are: 5, 9, 12 and 15.\n" - "The default value is 9.\n" - "Enter the value: "); - - num = ask_value ("%d", 9); - if (num == 6 || num < 3 || num > 15) - { - - fprintf (stderr, "*** Illegal input! ***\n"); - num = 5; - } - fprintf (stderr, "Maui/Tropez MIDI IRQ set to %d\n", num); - printf ("#define MAUI_IRQ %d\n", num); - } - - if (selected_options & B (OPT_UART6850)) - { - fprintf (stderr, "\nI/O base for 6850 UART Midi?\n" - "Be carefull. No defaults.\n" - "Enter the 6850 UART I/O base: "); - - num = ask_value ("%x", 0); - if (num == 0) - { - /* - * Invalid value entered - */ - printf ("#define EXCLUDE_UART6850\n"); - } - else - { - fprintf (stderr, "6850 UART I/O base set to %03x\n", num); - printf ("#define U6850_BASE 0x%03x\n", num); - - fprintf (stderr, "\nIRQ number for 6850 UART?\n" - "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n" - "The default value is 5.\n" - "Enter the value: "); - - num = ask_value ("%d", 5); - if (num == 6 || num < 3 || num > 15) - { - - fprintf (stderr, "*** Illegal input! ***\n"); - num = 5; - } - fprintf (stderr, "6850 UART IRQ set to %d\n", num); - printf ("#define U6850_IRQ %d\n", num); - } - } - - if (selected_options & B (OPT_PSS)) - { - fprintf (stderr, "\nI/O base for PSS?\n" - "The factory default is 220 (240 also possible)\n" - "Enter the PSS I/O base: "); - - num = ask_value ("%x", 0x220); - fprintf (stderr, "PSS I/O base set to %03x\n", num); - printf ("#define PSS_BASE 0x%03x\n", num); - -#if YOU_WANT_TO_WASTE_RESOURCES - fprintf (stderr, "\nIRQ number for PSS?\n" - "Valid numbers are: 3, 4, 5, 7, 9(=2) or 10.\n" - "The default value is 10.\n" - "Enter the value: "); - - num = ask_value ("%d", 10); - if (num == 6 || num < 3 || num > 15) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 7; - } - fprintf (stderr, "PSS IRQ set to %d\n", num); - printf ("#define PSS_IRQ %d\n", num); - - fprintf (stderr, "\nDMA number for ECHO-PSS?\n" - "The default value is 5\n" - "Valid values are 5, 6 and 7\n" - "Enter the value: "); - - num = ask_value ("%d", 5); - if (num < 5 || num > 7) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 5; - } - fprintf (stderr, "\nECHO-PSS DMA set to %d\n", num); - printf ("#define PSS_DMA %d\n", num); -#endif - - fprintf (stderr, "\nMSS (MS Sound System) I/O base for the PSS card?\n" - "The factory default is 530\n" - "Other possible values are 604, E80 or F40\n" - "Enter the MSS I/O base: "); - - num = ask_value ("%x", 0x530); - fprintf (stderr, "PSS/MSS I/O base set to %03x\n", num); - printf ("#define PSS_MSS_BASE 0x%03x\n", num); - - fprintf (stderr, "\nIRQ number for the MSS mode of PSS ?\n" - "Valid numbers are: 7, 9(=2), 10 and 11.\n" - "The default value is 11.\n" - "Enter the value: "); - - num = ask_value ("%d", 11); - if (num == 6 || num < 3 || num > 15) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 11; - } - fprintf (stderr, "PSS/MSS IRQ set to %d\n", num); - printf ("#define PSS_MSS_IRQ %d\n", num); - - fprintf (stderr, "\nMSS DMA number for PSS?\n" - "Valid values are 0, 1 and 3.\n" - "The default value is 3\n" - "Enter the value: "); - - num = ask_value ("%d", 3); - if (num == 4 || num < 0 || num > 7) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 3; - } - fprintf (stderr, "\nPSS/MSS DMA set to %d\n", num); - printf ("#define PSS_MSS_DMA %d\n", num); - - fprintf (stderr, "\nMIDI I/O base for PSS?\n" - "The factory default is 330\n" - "Enter the PSS MIDI I/O base: "); - - num = ask_value ("%x", 0x330); - fprintf (stderr, "PSS/MIDI I/O base set to %03x\n", num); - printf ("#define PSS_MPU_BASE 0x%03x\n", num); - - fprintf (stderr, "\nIRQ number for PSS MIDI?\n" - "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n" - "The default value is 9.\n" - "Enter the value: "); - - num = ask_value ("%d", 9); - if (num == 6 || num < 3 || num > 15) - { - - fprintf (stderr, "*** Illegal input! ***\n"); - num = 5; - } - fprintf (stderr, "PSS MIDI IRQ set to %d\n", num); - printf ("#define PSS_MPU_IRQ %d\n", num); - } - - if (selected_options & B (OPT_MSS)) - { - fprintf (stderr, "\nI/O base for MSS (MS Sound System)?\n" - "The factory default is 530\n" - "Other possible values are 604, E80 or F40\n" - "Enter the MSS I/O base: "); - - num = ask_value ("%x", 0x530); - fprintf (stderr, "MSS I/O base set to %03x\n", num); - printf ("#define MSS_BASE 0x%03x\n", num); - - fprintf (stderr, "\nIRQ number for MSS?\n" - "Valid numbers are: 7, 9(=2), 10 and 11.\n" - "The default value is 10.\n" - "Enter the value: "); - - num = ask_value ("%d", 10); - if (num == 6 || num < 3 || num > 15) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 7; - } - fprintf (stderr, "MSS IRQ set to %d\n", num); - printf ("#define MSS_IRQ %d\n", num); - - fprintf (stderr, "\nDMA number for MSS?\n" - "Valid values are 0, 1 and 3.\n" - "The default value is 3\n" - "Enter the value: "); - - num = ask_value ("%d", 3); - if (num == 4 || num < 0 || num > 7) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 3; - } - fprintf (stderr, "\nMSS DMA set to %d\n", num); - printf ("#define MSS_DMA %d\n", num); - } - - if (selected_options & B (OPT_SSCAPE)) - { - int reveal_spea; - - fprintf (stderr, "\n(MIDI) I/O base for Ensoniq Soundscape?\n" - "The factory default is 330\n" - "Other possible values are 320, 340 or 350\n" - "Enter the Soundscape I/O base: "); - - num = ask_value ("%x", 0x330); - fprintf (stderr, "Soundscape I/O base set to %03x\n", num); - printf ("#define SSCAPE_BASE 0x%03x\n", num); - - fprintf (stderr, "Is your SoundScape card made/marketed by Reveal or Spea? "); - reveal_spea = think_positively (0); - if (reveal_spea) - printf ("#define REVEAL_SPEA\n"); - - fprintf (stderr, "\nIRQ number for Soundscape?\n"); - - if (reveal_spea) - fprintf (stderr, "Check valid interrupts from the manual of your card.\n"); - else - fprintf (stderr, "Valid numbers are: 5, 7, 9(=2) and 10.\n"); - - fprintf (stderr, "The default value is 9.\n" - "Enter the value: "); - - num = ask_value ("%d", 9); - if (num == 6 || num < 3 || num > 15) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 9; - } - fprintf (stderr, "Soundscape IRQ set to %d\n", num); - printf ("#define SSCAPE_IRQ %d\n", num); - - fprintf (stderr, "\nDMA number for Soundscape?\n" - "Valid values are 1 and 3 (sometimes 0)" - "The default value is 3\n" - "Enter the value: "); - - num = ask_value ("%d", 3); - if (num == 4 || num < 0 || num > 7) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 3; - } - fprintf (stderr, "\nSoundscape DMA set to %d\n", num); - printf ("#define SSCAPE_DMA %d\n", num); - - fprintf (stderr, "\nMSS (MS Sound System) I/O base for the SSCAPE card?\n" - "The factory default is 534\n" - "Other possible values are 608, E84 or F44\n" - "Enter the MSS I/O base: "); - - num = ask_value ("%x", 0x534); - fprintf (stderr, "SSCAPE/MSS I/O base set to %03x\n", num); - printf ("#define SSCAPE_MSS_BASE 0x%03x\n", num); - - fprintf (stderr, "\nIRQ number for the MSS mode of SSCAPE ?\n"); - if (reveal_spea) - fprintf (stderr, "Valid numbers are: 5, 7, 9(=2) and 15.\n"); - else - fprintf (stderr, "Valid numbers are: 5, 7, 9(=2) and 10.\n"); - fprintf (stderr, "The default value is 5.\n" - "Enter the value: "); - - num = ask_value ("%d", 5); - if (num == 6 || num < 3 || num > 15) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 10; - } - fprintf (stderr, "SSCAPE/MSS IRQ set to %d\n", num); - printf ("#define SSCAPE_MSS_IRQ %d\n", num); - - fprintf (stderr, "\nMSS DMA number for SSCAPE?\n" - "Valid values are 0, 1 and 3.\n" - "The default value is 3\n" - "Enter the value: "); - - num = ask_value ("%d", 3); - if (num == 4 || num < 0 || num > 7) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 3; - } - fprintf (stderr, "\nSSCAPE/MSS DMA set to %d\n", num); - printf ("#define SSCAPE_MSS_DMA %d\n", num); - } - if (selected_options & B (OPT_TRIX)) - { - - fprintf (stderr, "\nWindows Sound System I/O base for the AudioTriX card?\n" - "The factory default is 530\n" - "Other possible values are 604, E80 or F40\n" - "Enter the MSS I/O base: "); - - num = ask_value ("%x", 0x530); - fprintf (stderr, "AudioTriX MSS I/O base set to %03x\n", num); - printf ("#define TRIX_BASE 0x%03x\n", num); - - fprintf (stderr, "\nIRQ number for the WSS mode of AudioTriX ?\n" - "Valid numbers are: 5, 7, 9(=2), 10 and 11.\n" - "The default value is 11.\n" - "Enter the value: "); - - num = ask_value ("%d", 11); - if (num != 5 && num != 7 && num != 9 && num != 10 && num != 11) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 11; - } - fprintf (stderr, " AudioTriX WSS IRQ set to %d\n", num); - printf ("#define TRIX_IRQ %d\n", num); - - fprintf (stderr, "\nWSS DMA number for AudioTriX?\n" - "Valid values are 0, 1 and 3.\n" - "The default value is 3\n" - "Enter the value: "); - - num = ask_value ("%d", 3); - if (num != 0 && num != 1 && num != 3) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 3; - } - fprintf (stderr, "\nAudioTriX/WSS DMA set to %d\n", num); - printf ("#define TRIX_DMA %d\n", num); - - fprintf (stderr, "\nSecond (capture) DMA number for AudioTriX?\n" - "Valid values are 0, 1 and 3.\n" - "The default value is 0\n" - "(-1 disables the second DMA)\n" - "Enter the value: "); - - num = ask_value ("%d", 0); - if (num != 0 && num != 1 && num != 3 || num != -1) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 0; - } - fprintf (stderr, "\nAudioTriX/WSS DMA2 set to %d\n", num); - printf ("#define TRIX_DMA2 %d\n", num); - - fprintf (stderr, "\nSoundBlaster I/O address for the AudioTriX card?\n" - "The factory default is 220\n" - "Other possible values are 200, 210, 230, 240, 250, 260 and 270\n" - "Enter the MSS I/O base: "); - - num = ask_value ("%x", 0x220); - fprintf (stderr, "AudioTriX SB I/O base set to %03x\n", num); - printf ("#define TRIX_SB_BASE 0x%03x\n", num); - - fprintf (stderr, "\nIRQ number for the SB mode of AudioTriX ?\n" - "Valid numbers are: 3, 4, 5 and 7.\n" - "The default value is 7.\n" - "Enter the value: "); - - num = ask_value ("%d", 7); - if (num != 3 && num != 4 && num != 5 && num != 7) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 7; - } - fprintf (stderr, " AudioTriX SB IRQ set to %d\n", num); - printf ("#define TRIX_SB_IRQ %d\n", num); - - fprintf (stderr, "\nSB DMA number for AudioTriX?\n" - "Valid values are 1 and 3.\n" - "The default value is 1\n" - "Enter the value: "); - - num = ask_value ("%d", 1); - if (num != 1 && num != 3) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 1; - } - fprintf (stderr, "\nAudioTriX/SB DMA set to %d\n", num); - printf ("#define TRIX_SB_DMA %d\n", num); - - fprintf (stderr, "\nMIDI (MPU-401) I/O address for the AudioTriX card?\n" - "The factory default is 330\n" - "Other possible values are 330, 370, 3B0 and 3F0\n" - "Enter the MPU I/O base: "); - - num = ask_value ("%x", 0x330); - fprintf (stderr, "AudioTriX MIDI I/O base set to %03x\n", num); - printf ("#define TRIX_MPU_BASE 0x%03x\n", num); - - fprintf (stderr, "\nMIDI IRQ number for the AudioTriX ?\n" - "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n" - "The default value is 5.\n" - "Enter the value: "); - - num = ask_value ("%d", 5); - if (num != 3 && num != 4 && num != 5 && num != 7 && num != 9) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 5; - } - fprintf (stderr, " AudioTriX MIDI IRQ set to %d\n", num); - printf ("#define TRIX_MPU_IRQ %d\n", num); - } - - if (selected_options & B (OPT_CS4232)) - { - int dma1; - - fprintf (stderr, "\nWindows Sound System I/O base for CS4232?\n" - "The factory default is 534\n" - "Other possible values are 608, E84 or F44\n" - "Enter the MSS I/O base: "); - - num = ask_value ("%x", 0x534); - fprintf (stderr, "CS4232 MSS I/O base set to %03x\n", num); - printf ("#define CS4232_BASE 0x%03x\n", num); - - fprintf (stderr, "\nIRQ number for the WSS mode of CS4232 ?\n" - "Valid numbers are: 5, 7, 9(=2), 11, 12 or 15.\n" - "The default value is 11.\n" - "Enter the value: "); - - num = ask_value ("%d", 11); - if (num != 5 && num != 7 && num != 9 && num != 11 && num != 12 || num != 15) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 11; - } - fprintf (stderr, " CS4232 WSS IRQ set to %d\n", num); - printf ("#define CS4232_IRQ %d\n", num); - - fprintf (stderr, "\nWSS DMA number for CS4232?\n" - "Valid values are 0, 1 and 3.\n" - "The default value is 0\n" - "(select the lowes possible one if you want to\n" - "use full duplex mode)\n" - "Enter the value: "); - - num = ask_value ("%d", 0); - if (num != 0 && num != 1 && num != 3) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 0; - } - fprintf (stderr, "\nCS4232/WSS DMA set to %d\n", num); - printf ("#define CS4232_DMA %d\n", num); - dma1 = num; - - fprintf (stderr, "\n Second WSS DMA number for CS4232?\n" - "Valid values are 0, 1 and 3.\n" - "The default value is 3\n" - "Enter the value (-1 disables duplex mode): "); - - num = ask_value ("%d", 3); - if (num == dma1 || (num != -1 && num != 0 && num != 1 && num != 3)) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 3; - } - fprintf (stderr, "\nCS4232/WSS DMA2 set to %d\n", num); - printf ("#define CS4232_DMA2 %d\n", num); - - fprintf (stderr, "\nMIDI (MPU-401) I/O address for the CS4232 card?\n" - "The factory default is 330\n" - "Other possible values are 330, 370, 3B0 and 3F0\n" - "Enter the MPU I/O base: "); - - num = ask_value ("%x", 0x330); - fprintf (stderr, "CS4232 MIDI I/O base set to %03x\n", num); - printf ("#define CS4232_MPU_BASE 0x%03x\n", num); - - fprintf (stderr, "\nMIDI IRQ number for CS4232?\n" - "Valid numbers are: 5, 7, 9(=2), 11, 12 or 15.\n" - "The default value is 5.\n" - "Enter the value: "); - - num = ask_value ("%d", 5); - if (num != 5 && num != 7 && num != 9 && num != 11 && num != 12 || num != 15) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 5; - } - fprintf (stderr, " CS4232 MIDI IRQ set to %d\n", num); - printf ("#define CS4232_MPU_IRQ %d\n", num); - } - - if (selected_options & B (OPT_MAD16)) - { - fprintf (stderr, "\n*** Options for the MAD16 and Mozart based cards ***\n\n"); - - fprintf (stderr, "\nWindows Sound System I/O base for the MAD16/Mozart card?\n" - "The factory default is 530\n" - "Other possible values are 604, E80 or F40\n" - "(Check which ones are supported by your card!!!!!!)\n" - "Enter the MSS I/O base: "); - - num = ask_value ("%x", 0x530); - fprintf (stderr, "MAD16 MSS I/O base set to %03x\n", num); - printf ("#define MAD16_BASE 0x%03x\n", num); - - if ((sb_base == 0x220 && (num == 0x530 || num == 0x480)) || - (sb_base == 0x240 && (num == 0xf40 || num == 0x604))) - { - fprintf (stderr, "FATAL ERROR!!!!!!!!!!!!!!\n" - "\tThis I/O port selection makes MAD16/Mozart\n" - "\tto use 0x%03x as the SB port.\n" - "\tThis conflicts with the true SB card.\n" - "\tRun the config again and select another I/O base.\n", - sb_base); - printf ("#undef CONFIGURE_SOUNDCARD\n"); - printf ("#undef KERNEL_SOUNDCARD\n"); - exit (-1); - } - - fprintf (stderr, "\nIRQ number for the WSS mode of MAD16/Mozart ?\n" - "Valid numbers are: 7, 9(=2), 10 and 11.\n" - "The default value is 11.\n" - "Enter the value: "); - - num = ask_value ("%d", 11); - if (num != 7 && num != 9 && num != 10 && num != 11) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 11; - } - fprintf (stderr, " MAD16 WSS IRQ set to %d\n", num); - printf ("#define MAD16_IRQ %d\n", num); - - fprintf (stderr, "\nWSS DMA (playback) number for MAD16/Mozart?\n" - "Valid values are 0, 1 and 3.\n" - "The default value is 3\n" - "Enter the value: "); - - num = ask_value ("%d", 3); - if (num != 0 && num != 1 && num != 3) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 3; - } - fprintf (stderr, "\nMAD16/WSS DMA set to %d\n", num); - printf ("#define MAD16_DMA %d\n", num); - - num = (num == 0) ? 1 : 0; - - fprintf (stderr, "\nMAD16/Mozart supports full duplex mode if the\n" - "card has a suitable codec chip (CS423x or AD1845).\n" - "This mode requires another DMA channel (DMA%d)\n" - "Do you want to enable this mode? (n/y)", num); - - if (think_positively (0)) - { - fprintf (stderr, "\nMAD16/WSS capture DMA set to %d\n", num); - printf ("#define MAD16_DMA2 %d\n", num); - } - else - printf ("#define MAD16_DMA2 -1\n"); - - - fprintf (stderr, "\nMIDI (MPU-401/SB) I/O address for the MAD16 card?\n" - "(This is the second MIDI port in TB Tropez)\n" - "Other possible values are 330, 320, 310 and 300\n" - "For 82C928 and Mozart you may use any nonzero value\n" - "since the driver ignores this setting.\n" - "The factory default is 330 (use 0 to disable)\n" - "Enter the MIDI I/O base: "); - - num = ask_value ("%x", 0x330); - if (num == 0) - fprintf (stderr, "MAD16/Mozart MIDI port disabled\n"); - else - { - fprintf (stderr, "MAD16 MIDI I/O base set to %03x\n", num); - printf ("#define MAD16_MPU_BASE 0x%03x\n", num); - - fprintf (stderr, "\nMIDI IRQ number for the MAD16 ?\n" - "Valid numbers are: 5, 7, 9(=2) and 10.\n" - "The default value is 5.\n" - "Enter the value: "); - - num = ask_value ("%d", 5); - if (num != 3 && num != 4 && num != 5 && num != 7 && num != 9) - { - fprintf (stderr, "*** Illegal input! ***\n"); - num = 5; - } - fprintf (stderr, " MAD16 MIDI IRQ set to %d\n", num); - printf ("#define MAD16_MPU_IRQ %d\n", num); - } - } - - if (selected_options & B (OPT_AUDIO)) - { - def_size = 65536; - - fprintf (stderr, "\nSelect the DMA buffer size (4096, 16384, 32768 or 65536 bytes)\n" - "%d is recommended value for this configuration.\n" - "Enter the value: ", def_size); - - num = ask_value ("%d", def_size); - if (num != 4096 && num != 16384 && num != 32768 && num != 65536) - { - - fprintf (stderr, "*** Illegal input! ***\n"); - num = def_size; - } - fprintf (stderr, "The DMA buffer size set to %d\n", num); - printf ("#define DSP_BUFFSIZE %d\n", num); - } + ask_parameters (); printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options); fprintf (stderr, "The sound driver is now configured.\n"); diff --git a/drivers/sound/cs4232.c b/drivers/sound/cs4232.c index e04ca2ca7740..0fa6dd120167 100644 --- a/drivers/sound/cs4232.c +++ b/drivers/sound/cs4232.c @@ -34,7 +34,7 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_CS4232) +#if defined(CONFIG_CS4232) #define KEY_PORT 0x279 /* Same as LPT1 status port */ #define CSN_NUM 0x99 /* Just a random number */ @@ -44,6 +44,7 @@ #define CS_OUT3(a, b, c) {CS_OUT(a);CS_OUT(b);CS_OUT(c);} static int mpu_base = 0, mpu_irq = 0; +static int mpu_detected = 0; int probe_cs4232_mpu (struct address_info *hw_config) @@ -88,6 +89,9 @@ probe_cs4232 (struct address_info *hw_config) return 0; } + if (ad1848_detect (hw_config->io_base, NULL, hw_config->osp)) + return 1; /* The card is already active */ + /* * This version of the driver doesn't use the PnP method when configuring * the card but a simplified method defined by Crystal. This means that @@ -108,14 +112,6 @@ probe_cs4232 (struct address_info *hw_config) CS_OUT2 (0x06, CSN_NUM); -/* - * Ensure that there is no other codec using the same address. - */ - - CS_OUT2 (0x15, 0x00); /* Select logical device 0 (WSS/SB/FM) */ - CS_OUT2 (0x33, 0x00); /* Inactivate logical dev 0 */ - if (ad1848_detect (hw_config->io_base, NULL, hw_config->osp)) - return 0; /* * Then set some config bytes. First logical device 0 @@ -144,7 +140,7 @@ probe_cs4232 (struct address_info *hw_config) * Initialize logical device 3 (MPU) */ -#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) if (mpu_base != 0 && mpu_irq != 0) { CS_OUT2 (0x15, 0x03); /* Select logical device 3 (MPU) */ @@ -182,7 +178,7 @@ attach_cs4232 (long mem_start, struct address_info *hw_config) 0, hw_config->osp); -#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) if (mpu_base != 0 && mpu_irq != 0) { static struct address_info hw_config2 = @@ -201,6 +197,7 @@ attach_cs4232 (long mem_start, struct address_info *hw_config) if (probe_mpu401 (&hw_config2)) { + mpu_detected = 1; mem_start = attach_mpu401 (mem_start, &hw_config2); } else @@ -227,8 +224,8 @@ unload_cs4232 (struct address_info *hw_config) dma2, /* Capture DMA */ 0); -#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) - if (mpu_base != 0 && mpu_irq != 0) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + if (mpu_base != 0 && mpu_irq != 0 && mpu_detected) { static struct address_info hw_config2 = {0}; /* Ensure it's initialized */ diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c index 6b4fd45ceff9..be3a034d3268 100644 --- a/drivers/sound/dev_table.c +++ b/drivers/sound/dev_table.c @@ -30,8 +30,6 @@ #define _DEV_TABLE_C_ #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD - int sound_started = 0; int sndtable_get_cardcount (void); @@ -48,6 +46,33 @@ snd_find_driver (int type) return -1; } +static long +start_services (long mem_start) +{ + int soundcards_installed; + + if (!(soundcards_installed = sndtable_get_cardcount ())) + return mem_start; /* No cards detected */ + +#ifdef CONFIG_AUDIO + if (num_audiodevs) /* Audio devices present */ + { + DMAbuf_init (0); + audio_init (0); + } +#endif + +#ifdef CONFIG_MIDI + if (num_midis) + MIDIbuf_init (0); +#endif + +#ifdef CONFIG_SEQUENCER + if (num_midis + num_synths) + sequencer_init (0); +#endif + return mem_start; +} static long start_cards (long mem_start) @@ -56,7 +81,8 @@ start_cards (long mem_start) int drv; sound_started = 1; - printk ("Sound initialization started\n"); + if (trace_init) + printk ("Sound initialization started\n"); /* * Check the number of cards actually defined in the table @@ -83,27 +109,9 @@ start_cards (long mem_start) if (sound_drivers[drv].probe (&snd_installed_cards[i].config)) { - int tmp; - - printk ("snd%d", - snd_installed_cards[i].card_type); mem_start = sound_drivers[drv].attach (mem_start, &snd_installed_cards[i].config); - printk (" at 0x%x", - snd_installed_cards[i].config.io_base); - - if ((tmp = snd_installed_cards[i].config.irq) != 0) - printk (" irq %d", - (tmp > 0) ? tmp : -tmp); - - if (snd_installed_cards[i].config.dma >= 0) - printk (" drq %d", - snd_installed_cards[i].config.dma); - if (snd_installed_cards[i].config.dma2 != -1) - printk (",%d\n", - snd_installed_cards[i].config.dma2); - else - printk ("\n"); + } else snd_installed_cards[i].enabled = 0; /* @@ -111,7 +119,8 @@ start_cards (long mem_start) */ } - printk ("Sound initialization complete\n"); + if (trace_init) + printk ("Sound initialization complete\n"); return mem_start; } @@ -130,7 +139,8 @@ sound_unload_drivers (void) if (!sound_started) return; - printk ("Sound unload started\n"); + if (trace_init) + printk ("Sound unload started\n"); for (i = 0; i < n && snd_installed_cards[i].card_type; i++) if (snd_installed_cards[i].enabled) @@ -141,7 +151,8 @@ sound_unload_drivers (void) snd_installed_cards[i].enabled = 0; } - printk ("Sound unload complete\n"); + if (trace_init) + printk ("Sound unload complete\n"); } void @@ -182,6 +193,8 @@ sndtable_probe (int unit, struct address_info *hw_config) { int i, sel = -1, n = num_sound_cards; + DDB (printk ("sndtable_probe(%d)\n", unit)); + if (!unit) return TRUE; @@ -221,16 +234,22 @@ sndtable_probe (int unit, struct address_info *hw_config) if ((drv = snd_find_driver (snd_installed_cards[sel].card_type)) == -1) { snd_installed_cards[sel].enabled = 0; + DDB (printk ("Failed to find driver\n")); return FALSE; } + DDB (printk ("Driver name '%s'\n", sound_drivers[drv].name)); - - snd_installed_cards[sel].config.card_subtype = + hw_config->card_subtype = + snd_installed_cards[sel].config.card_subtype = sound_drivers[drv].card_subtype; if (sound_drivers[drv].probe (hw_config)) - return TRUE; + { + return TRUE; + DDB (printk ("Hardware probed OK\n")); + } + DDB (printk ("Failed to find hardware\n")); snd_installed_cards[sel].enabled = 0; /* * Mark as not detected */ @@ -278,26 +297,17 @@ sndtable_init_card (int unit, struct address_info *hw_config) { DDB (printk ("Located card - calling attach routine\n")); - printk ("snd%d", unit); if (sound_drivers[drv].attach (0, hw_config) != 0) panic ("sound: Invalid memory allocation\n"); DDB (printk ("attach routine finished\n")); - printk (" at 0x%x irq %d drq %d", - snd_installed_cards[i].config.io_base, - snd_installed_cards[i].config.irq, - snd_installed_cards[i].config.dma); - if (snd_installed_cards[i].config.dma2 != -1) - printk (",%d\n", - snd_installed_cards[i].config.dma2); - else - printk ("\n"); } + start_services (0); return TRUE; } - printk ("sndtable_init_card: No card defined with type=%d, num cards: %d\n", - unit, num_sound_cards); + DDB (printk ("sndtable_init_card: No card defined with type=%d, num cards: %d\n", + unit, num_sound_cards)); return FALSE; } @@ -413,7 +423,3 @@ sound_getconf (int card_type) return &snd_installed_cards[ptr].config; } - - - -#endif diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h index 7653b6a408b9..74b5e94f3052 100644 --- a/drivers/sound/dev_table.h +++ b/drivers/sound/dev_table.h @@ -26,7 +26,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - */ #ifndef _DEV_TABLE_H_ @@ -77,6 +76,7 @@ typedef struct pnp_sounddev struct dma_buffparms { int dma_mode; /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */ + int closing; /* * Pointers to raw buffers @@ -104,6 +104,7 @@ struct dma_buffparms { int qlen; int qhead; int qtail; + int cfrag; /* Current incomplete fragment (write) */ int nbufs; int counts[MAX_SUB_BUFFERS]; @@ -120,6 +121,9 @@ struct dma_buffparms { int mapping_flags; #define DMA_MAP_MAPPED 0x00000001 char neutral_byte; +#ifdef OS_DMA_PARMS + OS_DMA_PARMS +#endif }; /* @@ -265,7 +269,7 @@ struct sound_timer_operations { struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0; struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0; -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER extern struct sound_timer_operations default_sound_timer; struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {&default_sound_timer, NULL}; @@ -281,66 +285,64 @@ struct sound_timer_operations { */ struct driver_info sound_drivers[] = { -#ifndef EXCLUDE_PSS +#ifdef CONFIG_PSS {"PSSECHO", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss}, {"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu, unload_pss_mpu}, {"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss, unload_pss_mss}, #endif -#ifndef EXCLUDE_MSS +#ifdef CONFIG_MSS {"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound}, /* MSS without IRQ/DMA config registers (for DEC Alphas) */ - {"PCXBJ", 1, SNDCARD_PSEUDO_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound}, + {"PCXBJ", 1, SNDCARD_PSEUDO_MSS, "MS Sound System (AXP)", attach_ms_sound, probe_ms_sound, unload_ms_sound}, #endif -#ifndef EXCLUDE_MAD16 +#ifdef CONFIG_MAD16 {"MAD16", 0, SNDCARD_MAD16, "MAD16/Mozart (MSS)", attach_mad16, probe_mad16, unload_mad16}, {"MAD16MPU", 0, SNDCARD_MAD16_MPU, "MAD16/Mozart (MPU)", attach_mad16_mpu, probe_mad16_mpu, unload_mad16_mpu}, #endif -#ifndef EXCLUDE_CS4232 +#ifdef CONFIG_CS4232 {"CS4232", 0, SNDCARD_CS4232, "CS4232", attach_cs4232, probe_cs4232, unload_cs4232}, {"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI", attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu}, #endif -#ifndef EXCLUDE_YM3812 +#ifdef CONFIG_YM3812 {"OPL3", 0, SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib, unload_adlib}, #endif -#ifndef EXCLUDE_PAS +#ifdef CONFIG_PAS {"PAS16", 0, SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, unload_pas}, #endif -#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI) +#if defined(CONFIG_MPU401) && defined(CONFIG_MIDI) {"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401, unload_mpu401}, #endif -#if !defined(EXCLUDE_MAUI) +#if defined(CONFIG_MAUI) {"MAUI", 0, SNDCARD_MAUI,"TB Maui", attach_maui, probe_maui, unload_maui}, #endif -#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI) +#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) {"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850, unload_uart6850}, #endif -#ifndef EXCLUDE_SB +#ifdef CONFIG_SB {"SBLAST", 0, SNDCARD_SB, "SoundBlaster", attach_sb_card, probe_sb, unload_sb}, +#ifdef CONFIG_AUDIO + {"SBX", 0, SNDCARD_SB16, "SoundBlaster 16bit", sb16_dsp_init, sb16_dsp_detect, unload_sb16}, #endif -#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) -#ifndef EXCLUDE_AUDIO - {"SB16", 0, SNDCARD_SB16, "SoundBlaster16", sb16_dsp_init, sb16_dsp_detect, unload_sb16}, +#ifdef CONFIG_MIDI + {"SBMPU", 0, SNDCARD_SB16MIDI,"SB MPU", attach_sb16midi, probe_sb16midi, unload_sb16midi}, #endif -#ifndef EXCLUDE_MIDI - {"SB16MIDI", 0, SNDCARD_SB16MIDI,"SB16 MIDI", attach_sb16midi, probe_sb16midi, unload_sb16midi}, #endif -#endif -#ifndef EXCLUDE_GUS16 +#ifdef CONFIG_GUS16 {"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16}, #endif -#ifndef EXCLUDE_GUS +#ifdef CONFIG_GUS {"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, unload_gus}, #endif -#ifndef EXCLUDE_SSCAPE +#ifdef CONFIG_SSCAPE {"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq Soundscape", attach_sscape, probe_sscape, unload_sscape}, {"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound, unload_ss_ms_sound}, #endif -#ifndef EXCLUDE_TRIX +#ifdef CONFIG_TRIX {"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTriX AudioTriX Pro", attach_trix_wss, probe_trix_wss, unload_trix_wss}, {"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTriX (SB mode)", attach_trix_sb, probe_trix_sb, unload_trix_sb}, {"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTriX MIDI", attach_trix_mpu, probe_trix_mpu, unload_trix_mpu}, #endif -#ifndef EXCLUDE_PNP +#ifdef CONFIG_PNP {"AD1848", 0, 500, "PnP MSS", attach_pnp_ad1848, probe_pnp_ad1848, unload_pnp_ad1848}, #endif {NULL, 0, 0, "*?*", NULL, NULL, NULL} @@ -360,7 +362,7 @@ struct sound_timer_operations { */ struct card_info snd_installed_cards[] = { -#ifndef EXCLUDE_PSS +#ifdef CONFIG_PSS {SNDCARD_PSS, {PSS_BASE, 0, -1, -1}, SND_DEFAULT_ENABLE}, # ifdef PSS_MPU_BASE {SNDCARD_PSS_MPU, {PSS_MPU_BASE, PSS_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, @@ -369,7 +371,10 @@ struct sound_timer_operations { {SNDCARD_PSS_MSS, {PSS_MSS_BASE, PSS_MSS_IRQ, PSS_MSS_DMA, -1}, SND_DEFAULT_ENABLE}, # endif #endif -#ifndef EXCLUDE_TRIX +#ifdef CONFIG_TRIX +#ifndef TRIX_DMA2 +#define TRIX_DMA2 TRIX_DMA +#endif {SNDCARD_TRXPRO, {TRIX_BASE, TRIX_IRQ, TRIX_DMA, TRIX_DMA2}, SND_DEFAULT_ENABLE}, # ifdef TRIX_SB_BASE {SNDCARD_TRXPRO_SB, {TRIX_SB_BASE, TRIX_SB_IRQ, TRIX_SB_DMA, -1}, SND_DEFAULT_ENABLE}, @@ -378,26 +383,32 @@ struct sound_timer_operations { {SNDCARD_TRXPRO_MPU, {TRIX_MPU_BASE, TRIX_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, # endif #endif -#ifndef EXCLUDE_SSCAPE +#ifdef CONFIG_SSCAPE {SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_MSS_DMA, -1}, SND_DEFAULT_ENABLE}, #endif -#ifndef EXCLUDE_MAD16 +#ifdef CONFIG_MAD16 +#ifndef MAD16_DMA2 +#define MAD16_DMA2 MAD16_DMA +#endif {SNDCARD_MAD16, {MAD16_BASE, MAD16_IRQ, MAD16_DMA, MAD16_DMA2}, SND_DEFAULT_ENABLE}, # ifdef MAD16_MPU_BASE {SNDCARD_MAD16_MPU, {MAD16_MPU_BASE, MAD16_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, # endif #endif -#ifndef EXCLUDE_CS4232 +#ifdef CONFIG_CS4232 +#ifndef CS4232_DMA2 +#define CS4232_DMA2 CS4232_DMA +#endif # ifdef CS4232_MPU_BASE {SNDCARD_CS4232_MPU, {CS4232_MPU_BASE, CS4232_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, # endif {SNDCARD_CS4232, {CS4232_BASE, CS4232_IRQ, CS4232_DMA, CS4232_DMA2}, SND_DEFAULT_ENABLE}, #endif -#ifndef EXCLUDE_MSS -# ifdef PSEUDO_MSS +#ifdef CONFIG_MSS +# ifndef PSEUDO_MSS {SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE}, # else {SNDCARD_PSEUDO_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE}, @@ -407,21 +418,21 @@ struct sound_timer_operations { # endif #endif -#ifndef EXCLUDE_PAS +#ifdef CONFIG_PAS {SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA, -1}, SND_DEFAULT_ENABLE}, #endif -#ifndef EXCLUDE_SB +#ifdef CONFIG_SB # ifndef SBC_DMA # define SBC_DMA 1 # endif {SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA, -1}, SND_DEFAULT_ENABLE}, #endif -#if !defined(EXCLUDE_MAUI) +#if defined(CONFIG_MAUI) {SNDCARD_MAUI, {MAUI_BASE, MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif -#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI) +#if defined(CONFIG_MPU401) && defined(CONFIG_MIDI) {SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #ifdef MPU2_BASE {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, @@ -431,27 +442,30 @@ struct sound_timer_operations { #endif #endif -#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI) +#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) {SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif -#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) -#ifndef EXCLUDE_AUDIO - {SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB16_DMA, -1}, SND_DEFAULT_ENABLE}, +#if defined(CONFIG_SB) +#if defined(CONFIG_AUDIO) && defined(SB_DMA2) + {SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB_DMA2, -1}, SND_DEFAULT_ENABLE}, #endif -#ifndef EXCLUDE_MIDI - {SNDCARD_SB16MIDI,{SB16MIDI_BASE, SBC_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, +#if defined(CONFIG_MIDI) && defined(SB_MPU_BASE) + {SNDCARD_SB16MIDI,{SB_MPU_BASE, SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif #endif -#ifndef EXCLUDE_GUS -#ifndef EXCLUDE_GUS16 +#ifdef CONFIG_GUS +#ifndef GUS_DMA2 +#define GUS_DMA2 GUS_DMA +#endif +#ifdef CONFIG_GUS16 {SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA, -1}, SND_DEFAULT_ENABLE}, #endif {SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA, GUS_DMA2}, SND_DEFAULT_ENABLE}, #endif -#ifndef EXCLUDE_YM3812 +#ifdef CONFIG_YM3812 {SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE}, #endif /* Define some expansion space */ @@ -473,8 +487,13 @@ struct sound_timer_operations { int max_sound_cards = 20; #endif +# ifdef MODULE + int trace_init = 0; +# else + int trace_init = 1; +# endif #else - extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; int num_audiodevs; + extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; extern int num_audiodevs; extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers; extern struct synth_operations * synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_synths; extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis; @@ -487,6 +506,8 @@ struct sound_timer_operations { extern int num_sound_cards; extern int max_sound_cards; + extern int trace_init; + long sndtable_init(long mem_start); int sndtable_get_cardcount (void); struct address_info *sound_getconf(int card_type); diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index a7ce2f31084a..7cacc7f99314 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -29,16 +29,14 @@ #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD +#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS) -#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS) - -static struct wait_queue *in_sleeper[MAX_AUDIO_DEV] = +static wait_handle *in_sleeper[MAX_AUDIO_DEV] = {NULL}; static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] = { {0}}; -static struct wait_queue *out_sleeper[MAX_AUDIO_DEV] = +static wait_handle *out_sleeper[MAX_AUDIO_DEV] = {NULL}; static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] = { @@ -133,6 +131,9 @@ reorganize_buffers (int dev, struct dma_buffparms *dmap) } bsz &= ~0x03; /* Force size which is multiple of 4 bytes */ +#ifdef OS_DMA_ALIGN_CHECK + OS_DMA_ALIGN_CHECK (bsz); +#endif n = dsp_dev->buffsize / bsz; if (n > MAX_SUB_BUFFERS) @@ -158,7 +159,9 @@ dma_init_buffers (int dev, struct dma_buffparms *dmap) out_sleep_flag[dev].mode = WK_NONE; } else - in_sleep_flag[dev].mode = WK_NONE; + { + in_sleep_flag[dev].mode = WK_NONE; + } dmap->flags = DMA_BUSY; /* Other flags off */ dmap->qlen = dmap->qhead = dmap->qtail = 0; @@ -168,6 +171,8 @@ dma_init_buffers (int dev, struct dma_buffparms *dmap) dmap->dma_mode = DMODE_NONE; dmap->mapping_flags = 0; dmap->neutral_byte = 0x00; + dmap->cfrag = -1; + dmap->closing = 0; } static int @@ -262,6 +267,8 @@ DMAbuf_open (int dev, int mode) } audio_devs[dev]->open_mode = mode; audio_devs[dev]->go = 1; + in_sleep_flag[dev].mode = WK_NONE; + out_sleep_flag[dev].mode = WK_NONE; audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, (ioctl_arg) 8, 1); audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, (ioctl_arg) 1, 1); @@ -335,19 +342,19 @@ dma_sync (int dev) save_flags (flags); cli (); - while (!(current->signal & ~current->blocked) - && audio_devs[dev]->dmap_out->qlen) + while (!current_got_fatal_signal () + && audio_devs[dev]->dmap_out->qlen > 1) { { unsigned long tl; - if (10 * HZ) - current->timeout = tl = jiffies + (10 * HZ); + if (HZ) + current_set_timeout (tl = jiffies + (HZ)); else tl = 0xffffffff; out_sleep_flag[dev].mode = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); + module_interruptible_sleep_on (&out_sleeper[dev]); if (!(out_sleep_flag[dev].mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -372,7 +379,7 @@ dma_sync (int dev) cli (); if (audio_devs[dev]->local_qlen) /* Device has hidden buffers */ { - while (!((current->signal & ~current->blocked)) + while (!(current_got_fatal_signal ()) && audio_devs[dev]->local_qlen (dev)) { @@ -380,11 +387,11 @@ dma_sync (int dev) unsigned long tl; if (HZ) - current->timeout = tl = jiffies + (HZ); + current_set_timeout (tl = jiffies + (HZ)); else tl = 0xffffffff; out_sleep_flag[dev].mode = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); + module_interruptible_sleep_on (&out_sleeper[dev]); if (!(out_sleep_flag[dev].mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -404,7 +411,10 @@ DMAbuf_release (int dev, int mode) { unsigned long flags; - if (!((current->signal & ~current->blocked)) + audio_devs[dev]->dmap_out->closing = 1; + audio_devs[dev]->dmap_in->closing = 1; + + if (!(current_got_fatal_signal ()) && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) { dma_sync (dev); @@ -412,7 +422,6 @@ DMAbuf_release (int dev, int mode) save_flags (flags); cli (); - audio_devs[dev]->reset (dev); audio_devs[dev]->close (dev); @@ -485,6 +494,14 @@ DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) save_flags (flags); cli (); +#ifdef ALLOW_BUFFER_MAPPING + if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) + { + printk ("Sound: Can't read from mmapped device (1)\n"); + return -EINVAL; + } + else +#endif if (!dmap->qlen) { int timeout; @@ -520,11 +537,11 @@ DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) unsigned long tl; if (timeout) - current->timeout = tl = jiffies + (timeout); + current_set_timeout (tl = jiffies + (timeout)); else tl = 0xffffffff; in_sleep_flag[dev].mode = WK_SLEEP; - interruptible_sleep_on (&in_sleeper[dev]); + module_interruptible_sleep_on (&in_sleeper[dev]); if (!(in_sleep_flag[dev].mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -536,6 +553,7 @@ DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) { printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); err = EIO; + audio_devs[dev]->reset (dev); ; } else @@ -559,6 +577,14 @@ DMAbuf_rmchars (int dev, int buff_no, int c) int p = dmap->counts[dmap->qhead] + c; +#ifdef ALLOW_BUFFER_MAPPING + if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) + { + printk ("Sound: Can't read from mmapped device (2)\n"); + return -EINVAL; + } + else +#endif if (p >= dmap->fragment_size) { /* This buffer is completely empty */ dmap->counts[dmap->qhead] = 0; @@ -623,6 +649,11 @@ dma_set_fragment (int dev, struct dma_buffparms *dmap, ioctl_arg arg, int fact) if (count < 2) return -EINVAL; +#ifdef OS_DMA_MINBITS + if (bytes < OS_DMA_MINBITS) + bytes = OS_DMA_MINBITS; +#endif + dmap->fragment_size = (1 << bytes); dmap->max_fragments = count; @@ -739,6 +770,10 @@ DMAbuf_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local) if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) dmap = dmap_in; +#ifdef ALLOW_BUFFER_MAPPING + if (dmap->mapping_flags & DMA_MAP_MAPPED) + return -EINVAL; +#endif if (!(dmap->flags & DMA_ALLOC_DONE)) reorganize_buffers (dev, dmap); @@ -758,7 +793,7 @@ DMAbuf_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local) { int tmp = audio_devs[dev]->local_qlen (dev); - if (tmp & info->fragments) + if (tmp && info->fragments) tmp--; /* * This buffer has been counted twice */ @@ -809,6 +844,18 @@ DMAbuf_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local) activate_recording (dev, dmap_in); } +#ifdef ALLOW_BUFFER_MAPPING + if ((changed & bits) & PCM_ENABLE_OUTPUT && + dmap_out->mapping_flags & DMA_MAP_MAPPED && + audio_devs[dev]->go) + { + if (!(dmap_out->flags & DMA_ALLOC_DONE)) + reorganize_buffers (dev, dmap_out); + + dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; + DMAbuf_start_output (dev, 0, dmap_out->fragment_size); + } +#endif audio_devs[dev]->enable_bits = bits; if (changed && audio_devs[dev]->trigger) @@ -819,6 +866,16 @@ DMAbuf_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local) return snd_ioctl_return ((int *) arg, audio_devs[dev]->enable_bits); break; + case SNDCTL_DSP_SETSYNCRO: + + if (!audio_devs[dev]->trigger) + return -EINVAL; + + audio_devs[dev]->trigger (dev, 0); + audio_devs[dev]->go = 0; + return 0; + break; + case SNDCTL_DSP_GETIPTR: { count_info info; @@ -832,6 +889,10 @@ DMAbuf_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local) info.bytes += info.ptr; memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info)); +#ifdef ALLOW_BUFFER_MAPPING + if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) + audio_devs[dev]->dmap_in->qlen = 0; /* Acknowledge interrupts */ +#endif restore_flags (flags); return 0; } @@ -850,6 +911,10 @@ DMAbuf_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local) info.bytes += info.ptr; memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info)); +#ifdef ALLOW_BUFFER_MAPPING + if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) + audio_devs[dev]->dmap_out->qlen = 0; /* Acknowledge interrupts */ +#endif restore_flags (flags); return 0; } @@ -879,6 +944,10 @@ DMAbuf_start_devices (unsigned int devmask) { /* OK to start the device */ audio_devs[dev]->go = 1; + + if (audio_devs[dev]->trigger) + audio_devs[dev]->trigger (dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); } } @@ -902,7 +971,7 @@ space_in_queue (int dev) if (audio_devs[dev]->local_qlen) { tmp = audio_devs[dev]->local_qlen (dev); - if (tmp & len) + if (tmp && len) tmp--; /* * This buffer has been counted twice */ @@ -921,6 +990,13 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) int abort, err = EIO; struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; +#ifdef ALLOW_BUFFER_MAPPING + if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) + { + printk ("Sound: Can't write to mmapped device (3)\n"); + return -EINVAL; + } +#endif if (dmap->dma_mode == DMODE_INPUT) /* Direction change */ { @@ -983,11 +1059,11 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) unsigned long tl; if (timeout) - current->timeout = tl = jiffies + (timeout); + current_set_timeout (tl = jiffies + (timeout)); else tl = 0xffffffff; out_sleep_flag[dev].mode = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); + module_interruptible_sleep_on (&out_sleeper[dev]); if (!(out_sleep_flag[dev].mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -1001,8 +1077,9 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) err = EIO; abort = 1; ; + audio_devs[dev]->reset (dev); } - else if ((current->signal & ~current->blocked)) + else if (current_got_fatal_signal ()) { err = EINTR; abort = 1; @@ -1022,20 +1099,59 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) return dmap->qtail; } +int +DMAbuf_get_curr_buffer (int dev, int *buf_no, char **dma_buf, int *buf_ptr, int *buf_size) +{ + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + + if (dmap->cfrag < 0) + return -1; + + *dma_buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size; + *buf_ptr = dmap->counts[dmap->qtail]; + *buf_size = dmap->fragment_size; + return *buf_no = dmap->cfrag; +} + +int +DMAbuf_set_count (int dev, int buff_no, int l) +{ + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + + if (buff_no == dmap->qtail) + { + dmap->cfrag = buff_no; + dmap->counts[buff_no] = l; + } + else + dmap->cfrag = -1; + return 0; +} + int DMAbuf_start_output (int dev, int buff_no, int l) { struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + dmap->cfrag = -1; /* * Bypass buffering if using mmaped access */ +#ifdef ALLOW_BUFFER_MAPPING + if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) + { + l = dmap->fragment_size; + dmap->counts[dmap->qtail] = l; + dmap->flags &= ~DMA_RESTART; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + } + else +#else if (dmap != NULL) +#endif { - if (buff_no != dmap->qtail) - printk ("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail); dmap->qlen++; if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) @@ -1165,12 +1281,43 @@ DMAbuf_outputintr (int dev, int event_type) unsigned long flags; struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + int p; + dmap->byte_counter += dmap->counts[dmap->qhead]; #ifdef OS_DMA_INTR sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); #endif +#ifdef ALLOW_BUFFER_MAPPING + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + /* mmapped access */ + + p = dmap->fragment_size * dmap->qhead; + memset (dmap->raw_buf + p, + dmap->neutral_byte, + dmap->fragment_size); + + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + dmap->qlen++; /* Yes increment it (don't decrement) */ + dmap->flags &= ~DMA_ACTIVE; + dmap->counts[dmap->qhead] = dmap->fragment_size; + + if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + { + audio_devs[dev]->output_block (dev, dmap->raw_buf_phys + + dmap->qhead * dmap->fragment_size, + dmap->counts[dmap->qhead], 1, + !(audio_devs[dev]->flags & DMA_AUTOMODE)); + if (audio_devs[dev]->trigger) + audio_devs[dev]->trigger (dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } + dmap->flags |= DMA_ACTIVE; + } + else +#endif if (event_type != 2) { if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) @@ -1184,6 +1331,27 @@ DMAbuf_outputintr (int dev, int event_type) dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; dmap->flags &= ~DMA_ACTIVE; + if (event_type == 1 && dmap->qlen < 1) + { + dmap->underrun_count++; + /* Ignore underrun. Just move the tail pointer forward and go */ + if (dmap->closing) + { + audio_devs[dev]->halt_xfer (dev); + } + else + { + dmap->qlen++; + dmap->cfrag = -1; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + + p = dmap->fragment_size * dmap->qhead; + memset (dmap->raw_buf + p, + dmap->neutral_byte, + dmap->fragment_size); + } + } + if (dmap->qlen) { if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) @@ -1198,21 +1366,6 @@ DMAbuf_outputintr (int dev, int event_type) } dmap->flags |= DMA_ACTIVE; } - else if (event_type == 1) - { - dmap->underrun_count++; - if ((audio_devs[dev]->flags & DMA_DUPLEX) && - audio_devs[dev]->halt_output) - audio_devs[dev]->halt_output (dev); - else - audio_devs[dev]->halt_xfer (dev); - - if ((audio_devs[dev]->flags & DMA_AUTOMODE) && - audio_devs[dev]->flags & NEEDS_RESTART) - dmap->flags |= DMA_RESTART; - else - dmap->flags &= ~DMA_RESTART; - } } /* event_type != 2 */ save_flags (flags); @@ -1221,7 +1374,7 @@ DMAbuf_outputintr (int dev, int event_type) { { out_sleep_flag[dev].mode = WK_WAKEUP; - wake_up (&out_sleeper[dev]); + module_wake_up (&out_sleeper[dev]); }; } restore_flags (flags); @@ -1239,21 +1392,47 @@ DMAbuf_inputintr (int dev) sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2); #endif +#ifdef ALLOW_BUFFER_MAPPING + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + dmap->qlen++; + + if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + { + audio_devs[dev]->start_input (dev, dmap->raw_buf_phys + + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 1, + !(audio_devs[dev]->flags & DMA_AUTOMODE)); + if (audio_devs[dev]->trigger) + audio_devs[dev]->trigger (dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } + + dmap->flags |= DMA_ACTIVE; + } + else +#endif if (dmap->qlen == (dmap->nbufs - 1)) { printk ("Sound: Recording overrun\n"); dmap->underrun_count++; - if ((audio_devs[dev]->flags & DMA_DUPLEX) && - audio_devs[dev]->halt_input) - audio_devs[dev]->halt_input (dev); - else - audio_devs[dev]->halt_xfer (dev); - dmap->flags &= ~DMA_ACTIVE; if (audio_devs[dev]->flags & DMA_AUTOMODE) - dmap->flags |= DMA_RESTART; - else - dmap->flags &= ~DMA_RESTART; + { + /* Force restart on next write */ + if ((audio_devs[dev]->flags & DMA_DUPLEX) && + audio_devs[dev]->halt_input) + audio_devs[dev]->halt_input (dev); + else + audio_devs[dev]->halt_xfer (dev); + + dmap->flags &= ~DMA_ACTIVE; + if (audio_devs[dev]->flags & DMA_AUTOMODE) + dmap->flags |= DMA_RESTART; + else + dmap->flags &= ~DMA_RESTART; + } } else { @@ -1262,28 +1441,28 @@ DMAbuf_inputintr (int dev) printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n", dev, dmap->qlen, dmap->nbufs); dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + } - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - { - audio_devs[dev]->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1, + if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + { + audio_devs[dev]->start_input (dev, dmap->raw_buf_phys + + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->trigger) + audio_devs[dev]->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - - dmap->flags |= DMA_ACTIVE; } + dmap->flags |= DMA_ACTIVE; + save_flags (flags); cli (); if ((in_sleep_flag[dev].mode & WK_SLEEP)) { { in_sleep_flag[dev].mode = WK_WAKEUP; - wake_up (&in_sleeper[dev]); + module_wake_up (&in_sleeper[dev]); }; } restore_flags (flags); @@ -1352,7 +1531,7 @@ DMAbuf_reset_dma (int dev) } int -DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) +DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait) { struct dma_buffparms *dmap; unsigned long flags; @@ -1362,6 +1541,20 @@ DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait case SEL_IN: dmap = audio_devs[dev]->dmap_in; +#ifdef ALLOW_BUFFER_MAPPING + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + if (dmap->qlen) + return 1; + + save_flags (flags); + cli (); + in_sleep_flag[dev].mode = WK_SLEEP; + module_select_wait (&in_sleeper[dev], wait); + restore_flags (flags); + return 0; + } +#endif if (dmap->dma_mode != DMODE_INPUT) { @@ -1384,7 +1577,7 @@ DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait save_flags (flags); cli (); in_sleep_flag[dev].mode = WK_SLEEP; - select_wait (&in_sleeper[dev], wait); + module_select_wait (&in_sleeper[dev], wait); restore_flags (flags); return 0; } @@ -1394,6 +1587,20 @@ DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait case SEL_OUT: dmap = audio_devs[dev]->dmap_out; +#ifdef ALLOW_BUFFER_MAPPING + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + if (dmap->qlen) + return 1; + + save_flags (flags); + cli (); + out_sleep_flag[dev].mode = WK_SLEEP; + module_select_wait (&out_sleeper[dev], wait); + restore_flags (flags); + return 0; + } +#endif if (dmap->dma_mode == DMODE_INPUT) { @@ -1410,7 +1617,7 @@ DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait save_flags (flags); cli (); out_sleep_flag[dev].mode = WK_SLEEP; - select_wait (&out_sleeper[dev], wait); + module_select_wait (&out_sleeper[dev], wait); restore_flags (flags); return 0; } @@ -1425,7 +1632,7 @@ DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait } -#else /* EXCLUDE_AUDIO */ +#else /* CONFIG_AUDIO */ /* * Stub versions if audio services not included */ @@ -1514,5 +1721,3 @@ DMAbuf_outputintr (int dev, int underrun_flag) return; } #endif - -#endif diff --git a/drivers/sound/experimental.txt b/drivers/sound/experimental.txt deleted file mode 100644 index 456de53fd189..000000000000 --- a/drivers/sound/experimental.txt +++ /dev/null @@ -1,165 +0,0 @@ -This version contains some features which is may NOT be enabled by default. -I'm trying to release an official/reliable version soon so that the -Linux version of Doom (and other games) becomes possible. For that reason -I have disabled some features which are not reliable enough to be -released for wide public. If you are interested to try them, please -read this file carefully. - -1) ECHO PSS (Personal Sound System support) - -This version contains support for soundcards based on the AD20msp614 -chipset made by Analog Devices. This chipset consist of the -AD1848 codec, ADSP-21xx DSP chip and a ESC614 ASIC and is used in some -soundcards made by Orchid, Cardinal, Echo Speech Corporation, Western -Digital and Wearnes Technology. The PSS support is by Marc M. Hoffman -(marc.hoffman@analog.com). I received this stuff about a week ago and -have not been able to test it yet. -If you are interested, remove the B(OPT_PSS) from the DISABLED_OPTIONS -(see above). -You have also to enable the MSS support since I have not integrated -the AD1848 driver with the PSS one yet. - -2) /dev/music (/dev/sequencer2) - -This version has a new device file called /dev/music. I have not -implemented all parts of it but it's there. It's only interesting if -you are writing a sequencer program yourself. Enable by creating -the device file /dev/music. Use the script at the end of linux/Readme - -3) /dev/midi## - -These are tty like raw devices for MIDI ports. Since there is a minor -incompatibility between different versions of Linux, I have disabled -this feature by default. You just need to create the device files yourself. - -4) Support for hardware based u-Law/A-Law and ADPCM formats. - -The AD1848 (and compatibles) are able to do compression and -decompression by hardware. This version has experimental support -for some of them. Currently they are implemented just in the -AD1848 driver. The GUS MAX (and the 16 bit daughtercard) support -also 16->4 bit ADPCM (the IMA one) but it don't work yet. -The argument ioctl(SNDCTL_DSP_SAMPLESIZE) can have some new values -in addition to the 8 and 16 supported earlier. Look at soundcard.h -for more info. -(In case somebody dares to ask: The ASP chip of SB16 is not supported -so the hardware compression/decompression doesn't work with it. Also -the ADPCM format is different than the standard (IMA) one (I guess). -This feature is enabled by default. - -5) Real time fix to /dev/dsp and /dev/audio drivers - -The following feature should help game writers. This stuff is enabled -by default. ----------------- cut here --------------------- -There is a new ioctl called SNDCTL_DSP_SETFRAGMENT. It accepts a -int parameter which has format 0x00nn00ss where the nn is max number of -buffer fragments (between 0x02 and 0xff) and the ss gives indirectly the -size of a buffer fragment (fragment_size = (1 << ss)). Valid sizes are -between (ss=0x07 -> 128 bytes and ss=0x11 (17 dec) -> 128k). - -This ioctl must be used ONCE between open() and first call to -read()/write() or ioctl(SNDCTL_DSP_GETBLKSIZE). - -You need just to force the fragment size to a value which is sufficiently -short (gives the 1/20th of sec with the speed/#channels/#bits you are using). - -Using a small number of fragments offers (I guess) a significant advantage. -For example with 2 fragments the driver works as the following (at least -I hope so). Assuming that the process writes exactly 'fragment_size' of -bytes each time (this is really important). - - 1) When the process writes the first fragment, it will be copied to - the DMA buffer area and the playback begins. The write() returns - immediately and the process is free to continue. - - - 2a) If the fragment gets played before the application writes a new - one, the device will be stoppen and restarted which causes a click. - When the process calls write next time, it will be processes as - in step 1. - - 2b) If the process calls write before the buffer underflows, the - data will be queued and the process is free to continue. (There - is now one full and one partially played fragment in the kernel - buffers. This gives average delay of 1.5*fragment_time (for - example 1/20th sec) before the last byte in the buffer gets played. - - - 3a) If the device gets both fragments played before the next write - (underflow), there will be a click. The write will be processed as - in step 1. - - 3b) If the 1st fragment gets played before next write (the process - calls write during playback of the second fragment), it will be - processed as step 2b. - - 3c) If the process writes 3rd fragment when there is already 2 - fragments in the queue (1 playing and 1 waiting), the process - will block until the 1st fragment gets played. It will then be - woken up and it continues as in step 2b. This means that - the process blocks for at most the time required to play a - buffer fragment. - -This method syncronizes the process and the audio device together -automaticly. The process will block at most the 'fragment_time'. Usually -less, depending on how much it needs time to do other things. The maximum -delay between writing a byte and the time when it finally plays is -at most 3 times the 'fragment_time'. - -The delay depends on how much time the program needs to do it's -computations for the next sample (updating screen etc). If it's about -80% of the 'fragment_time' the game will run almost without delays. If it -uses more time, there is a risk that the audio buffer gets empty. - -The application code should be something like the following: - -int frag = 0x00020008; /* 2 fragments of 2^8=256 bytes */ -int frag_size; - -int fd=open("/dev/dsp"); -ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag); -ioctl(NDCTL_DSP_SPEED); /* And #channels & #bits if required */ - -/* - * Query the actual fragment sice since the driver may refuse - * the requested one (unlikely but possible?) - */ - -ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size); - -while(True) -{ - do_computations(); - write(fd, buf, frag_size); /* Always the same size!!!!!!! */ -} - -I have tested this with a modified version of str.c. The algorithm works -as long as the playing program gets enough time to run. Hitting ENTER on -another virtual console causes a pause/click (with 2 frags of 64 bytes). - -NOTE! It's important to know that this call may be called just once and -it must be done immediately after open(). The fragment size will remain -in effect until the device is closed. -------------------- cut here --------------------- - -6) Detection and initialization code for Ensoniq Soundscape - -This version is able to initialize SoundScape (almost). However -PCM recording and playback don't work. Also MIDI playback sounds wierd -since the driver is not able to set volume controls properly. -The soundscape support is disabled. You need to enable it by editing -beginning of configure.c. Also read comments in sndscape/README. - -7) select() support for /dev/audio and /dev/dsp. (/dev/midi## and - /dev/sequencer had it already in v2.90). - -There is now select() support in the audio/dsp driver (for Linux only). -However I have not tried this feature yet. -There are also some new ioctl() calls (please look at soundcard.h). - -8) MIDI recording in /dev/music (/dev/sequencer2) - -MIDI recording was earlier implemented only with full MPU-401 devices. -This version has it also for dumb MIDI ports. However I have not tested it -yet. diff --git a/drivers/sound/gus_card.c b/drivers/sound/gus_card.c index 41dd9e466838..85ffdd18075f 100644 --- a/drivers/sound/gus_card.c +++ b/drivers/sound/gus_card.c @@ -29,7 +29,7 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS) +#if defined(CONFIG_GUS) #include "gus_hw.h" @@ -64,7 +64,7 @@ attach_gus_card (long mem_start, struct address_info *hw_config) if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) if (sound_alloc_dma (hw_config->dma2, "GUS(2)")) printk ("gus_card.c: Can't allocate DMA channel2\n"); -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI mem_start = gus_midi_init (mem_start); #endif return mem_start; @@ -93,7 +93,7 @@ attach_gus_card (long mem_start, struct address_info *hw_config) if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) if (sound_alloc_dma (hw_config->dma2, "GUS")) printk ("gus_card.c: Can't allocate DMA channel2\n"); -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI mem_start = gus_midi_init (mem_start); #endif return mem_start; @@ -166,7 +166,7 @@ gusintr (int irq, struct pt_regs *dummy) sti (); -#ifndef EXCLUDE_GUSMAX +#ifdef CONFIG_GUSMAX if (have_gus_max) ad1848_interrupt (irq, NULL); #endif @@ -183,16 +183,19 @@ gusintr (int irq, struct pt_regs *dummy) if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) { -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI gus_midi_interrupt (0); #endif } if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) { -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER if (gus_timer_enabled) - sound_timer_interrupt (); + { + sound_timer_interrupt (); + } + gus_write8 (0x45, 0); /* Ack IRQ */ gus_timer_command (4, 0x80); /* Reset IRQ flags */ @@ -213,7 +216,7 @@ gusintr (int irq, struct pt_regs *dummy) /* * Some extra code for the 16 bit sampling option */ -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS16) +#if defined(CONFIG_GUS16) int probe_gus_db16 (struct address_info *hw_config) @@ -224,8 +227,10 @@ probe_gus_db16 (struct address_info *hw_config) long attach_gus_db16 (long mem_start, struct address_info *hw_config) { +#ifdef CONFIG_GUS gus_pcm_volume = 100; gus_wave_volume = 90; +#endif ad1848_init ("GUS 16 bit sampling", hw_config->io_base, hw_config->irq, diff --git a/drivers/sound/gus_midi.c b/drivers/sound/gus_midi.c index 10c8cc2c4582..b5879a90d5dc 100644 --- a/drivers/sound/gus_midi.c +++ b/drivers/sound/gus_midi.c @@ -29,11 +29,9 @@ #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD - #include "gus_hw.h" -#if !defined(EXCLUDE_GUS) && !defined(EXCLUDE_MIDI) +#if defined(CONFIG_GUS) && defined(CONFIG_MIDI) static int midi_busy = 0, input_opened = 0; static int my_dev; @@ -75,14 +73,8 @@ gus_midi_open (int dev, int mode, input_opened = 1; } - if (mode == OPEN_WRITE || mode == OPEN_READWRITE) - { - gus_midi_control |= MIDI_ENABLE_XMIT; - } - outb (gus_midi_control, u_MidiControl); /* - * Enable - */ + outb (gus_midi_control, u_MidiControl); /* Enable */ midi_busy = 1; qlen = qhead = qtail = output_used = 0; @@ -276,37 +268,37 @@ gus_midi_interrupt (int dummy) save_flags (flags); cli (); - stat = GUS_MIDI_STATUS (); - - if (stat & MIDI_RCV_FULL) - { - data = inb (u_MidiData); - if (input_opened) - midi_input_intr (my_dev, data); - } - - if (stat & MIDI_XMIT_EMPTY) + while ((stat = GUS_MIDI_STATUS ()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY)) { - while (qlen && dump_to_midi (tmp_queue[qhead])) + if (stat & MIDI_RCV_FULL) { - qlen--; - qhead++; + data = inb (u_MidiData); + if (input_opened) + midi_input_intr (my_dev, data); } - if (!qlen) + if (stat & MIDI_XMIT_EMPTY) { - /* - * Disable Midi output interrupts, since no data in the buffer - */ - gus_midi_control &= ~MIDI_ENABLE_XMIT; - outb (gus_midi_control, u_MidiControl); + while (qlen && dump_to_midi (tmp_queue[qhead])) + { + qlen--; + qhead++; + } + + if (!qlen) + { + /* + * Disable Midi output interrupts, since no data in the buffer + */ + gus_midi_control &= ~MIDI_ENABLE_XMIT; + outb (gus_midi_control, u_MidiControl); + outb (gus_midi_control, u_MidiControl); + } } - } + } restore_flags (flags); } #endif - -#endif diff --git a/drivers/sound/gus_vol.c b/drivers/sound/gus_vol.c index bddaad75bc03..f817da59fa7c 100644 --- a/drivers/sound/gus_vol.c +++ b/drivers/sound/gus_vol.c @@ -4,7 +4,7 @@ * Greg Lee 1993. */ #include "sound_config.h" -#ifndef EXCLUDE_GUS +#ifdef CONFIG_GUS #include "gus_linearvol.h" #define GUS_VOLUME gus_wave_volume diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c index 944bc9124c53..7ba2698efcb0 100644 --- a/drivers/sound/gus_wave.c +++ b/drivers/sound/gus_wave.c @@ -31,7 +31,7 @@ #include #include "gus_hw.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS) +#if defined(CONFIG_GUS) #define MAX_SAMPLE 150 #define MAX_PATCH 256 @@ -112,7 +112,7 @@ static int gus_sampling_speed; static int gus_sampling_channels; static int gus_sampling_bits; -static struct wait_queue *dram_sleeper = NULL; +static wait_handle *dram_sleeper = NULL; static volatile struct snd_wait dram_sleep_flag = {0}; @@ -1734,11 +1734,11 @@ guswave_load_patch (int dev, int format, const snd_rw_buf * addr, unsigned long tl; if (HZ) - current->timeout = tl = jiffies + (HZ); + current_set_timeout (tl = jiffies + (HZ)); else tl = 0xffffffff; dram_sleep_flag.mode = WK_SLEEP; - interruptible_sleep_on (&dram_sleeper); + module_interruptible_sleep_on (&dram_sleeper); if (!(dram_sleep_flag.mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -2829,7 +2829,7 @@ gus_default_mixer_ioctl (int dev, unsigned int cmd, ioctl_arg arg) SOUND_MASK_SYNTH|SOUND_MASK_PCM) if (((cmd >> 8) & 0xff) == 'M') { - if (cmd & IOC_IN) + if (_IOC_DIR (cmd) & _IOC_WRITE) switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: @@ -3052,7 +3052,7 @@ gus_wave_init (long mem_start, struct address_info *hw_config) model_num = "MAX"; gus_type = 0x40; mixer_type = CS4231; -#ifndef EXCLUDE_GUSMAX +#ifdef CONFIG_GUSMAX { unsigned char max_config = 0x40; /* Codec enable */ @@ -3098,10 +3098,8 @@ gus_wave_init (long mem_start, struct address_info *hw_config) */ } - - printk (" ", model_num, (int) gus_mem_size / 1024); - sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024); + conf_printf (gus_info.name, hw_config); if (num_synths >= MAX_SYNTH_DEV) printk ("GUS Error: Too many synthesizers\n"); @@ -3109,7 +3107,7 @@ gus_wave_init (long mem_start, struct address_info *hw_config) { voice_alloc = &guswave_operations.alloc; synth_devs[num_synths++] = &guswave_operations; -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER gus_tmr_install (gus_base + 8); #endif } @@ -3157,7 +3155,7 @@ gus_wave_init (long mem_start, struct address_info *hw_config) void gus_wave_unload (void) { -#ifndef EXCLUDE_GUSMAX +#ifdef CONFIG_GUSMAX if (have_gus_max) { ad1848_unload (gus_base + 0x10c, @@ -3389,7 +3387,7 @@ guswave_dma_irq (void) if ((dram_sleep_flag.mode & WK_SLEEP)) { dram_sleep_flag.mode = WK_WAKEUP; - wake_up (&dram_sleeper); + module_wake_up (&dram_sleeper); }; break; @@ -3426,7 +3424,7 @@ guswave_dma_irq (void) } -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER /* * Timer stuff */ @@ -3469,7 +3467,7 @@ arm_timer (int timer, unsigned int interval) gus_timer_command (0x04, 0x02); /* Start timer 2 */ } - gus_timer_enabled = 0; + gus_timer_enabled = 1; } static unsigned int @@ -3510,6 +3508,7 @@ gus_tmr_restart (int dev) gus_write8 (0x45, 0x04); /* Start timer 1 again */ else gus_write8 (0x45, 0x08); /* Start timer 2 again */ + gus_timer_enabled = 1; } static struct sound_lowlev_timer gus_tmr = diff --git a/drivers/sound/ics2101.c b/drivers/sound/ics2101.c index 1c11a43d8e8c..6b0992c95ef4 100644 --- a/drivers/sound/ics2101.c +++ b/drivers/sound/ics2101.c @@ -28,7 +28,7 @@ */ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS) +#if defined(CONFIG_GUS) #include #include "gus_hw.h" @@ -134,7 +134,7 @@ ics2101_mixer_ioctl (int dev, unsigned int cmd, ioctl_arg arg) { if (((cmd >> 8) & 0xff) == 'M') { - if (cmd & IOC_IN) + if (_IOC_DIR (cmd) & _IOC_WRITE) switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c index ed89d909d17d..80bfb2e4bebe 100644 --- a/drivers/sound/mad16.c +++ b/drivers/sound/mad16.c @@ -72,7 +72,7 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MAD16) +#if defined(CONFIG_MAD16) static int already_initialized = 0; @@ -451,7 +451,7 @@ attach_mad16_mpu (long mem_start, struct address_info *hw_config) { if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ { -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI if (mad_read (MC1_PORT) & 0x20) hw_config->io_base = 0x240; @@ -464,7 +464,7 @@ attach_mad16_mpu (long mem_start, struct address_info *hw_config) #endif } -#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) if (!already_initialized) return mem_start; @@ -477,7 +477,7 @@ attach_mad16_mpu (long mem_start, struct address_info *hw_config) int probe_mad16_mpu (struct address_info *hw_config) { -#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) static int mpu_attached = 0; static int valid_ports[] = {0x330, 0x320, 0x310, 0x300}; @@ -497,7 +497,7 @@ probe_mad16_mpu (struct address_info *hw_config) if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ { -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI unsigned char tmp; tmp = mad_read (MC3_PORT); @@ -597,7 +597,15 @@ unload_mad16 (struct address_info *hw_config) void unload_mad16_mpu (struct address_info *hw_config) { -#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) +#ifdef CONFIG_MIDI + if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ + { + mad16_sb_dsp_unload (hw_config); + return; + } +#endif + +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) unload_mpu401 (hw_config); #endif } diff --git a/drivers/sound/mad16_sb_midi.c b/drivers/sound/mad16_sb_midi.c index d6b66f8db7bb..565b8ed8047a 100644 --- a/drivers/sound/mad16_sb_midi.c +++ b/drivers/sound/mad16_sb_midi.c @@ -29,7 +29,7 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MAD16) && !defined(EXCLUDE_MIDI) +#if defined(CONFIG_MAD16) && defined(CONFIG_MIDI) #define sbc_base mad16_sb_base #include "sb.h" @@ -39,6 +39,7 @@ static int my_dev; static int mad16_sb_base = 0x220; static int mad16_sb_irq = 0; static int mad16_sb_dsp_ok = 0; +static int mad16_sb_dsp_attached = 0; static sound_os_info *midi_osp; int mad16_sb_midi_mode = NORMAL_MIDI; @@ -111,11 +112,11 @@ mad16_sb_reset_dsp (void) int loopc; outb (1, DSP_RESET); - tenmicrosec (); + tenmicrosec (midi_osp); outb (0, DSP_RESET); - tenmicrosec (); - tenmicrosec (); - tenmicrosec (); + tenmicrosec (midi_osp); + tenmicrosec (midi_osp); + tenmicrosec (midi_osp); for (loopc = 0; loopc < 1000 && !(inb (DSP_DATA_AVAIL) & 0x80); loopc++); /* * Wait @@ -165,6 +166,7 @@ mad16_sb_dsp_init (long mem_start, struct address_info *hw_config) * mad16_sb_midi_init -- everything else is done elsewhere */ { + mad16_sb_dsp_attached = 1; midi_osp = hw_config->osp; if (snd_set_irq_handler (mad16_sb_irq, mad16_sbintr, "MAD16 SB MIDI", midi_osp) < 0) { @@ -174,13 +176,23 @@ mad16_sb_dsp_init (long mem_start, struct address_info *hw_config) request_region (hw_config->io_base, 16, "mad16/Mozart MIDI"); - printk (" "); + conf_printf ("MAD16 MIDI (SB mode)", hw_config); mad16_sb_midi_init (2); mad16_sb_dsp_ok = 1; return mem_start; } +void +mad16_sb_dsp_unload (struct address_info *hw_config) +{ + if (!mad16_sb_dsp_attached) + return; + + release_region (hw_config->io_base, 16); + snd_release_irq (hw_config->irq); +} + static int mad16_sb_midi_open (int dev, int mode, void (*input) (int dev, unsigned char data), diff --git a/drivers/sound/maui.c b/drivers/sound/maui.c index 45ec04283ec8..4b1096ee51db 100644 --- a/drivers/sound/maui.c +++ b/drivers/sound/maui.c @@ -32,7 +32,7 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MAUI) +#if defined(CONFIG_MAUI) static int maui_base = 0x330; @@ -191,13 +191,16 @@ probe_maui (struct address_info *hw_config) return 0; } - printk ("WaveFront hardware version %d.%d\n", tmp1, tmp2); + if (trace_init) + printk ("WaveFront hardware version %d.%d\n", tmp1, tmp2); if (!maui_write (0x9F)) /* Report firmware version */ return 0; if ((tmp1 = maui_read ()) == -1 || (tmp2 = maui_read ()) == -1) return 0; - printk ("WaveFront firmware version %d.%d\n", tmp1, tmp2); + + if (trace_init) + printk ("WaveFront firmware version %d.%d\n", tmp1, tmp2); if (!maui_write (0x85)) /* Report free DRAM */ return 0; @@ -206,7 +209,8 @@ probe_maui (struct address_info *hw_config) { tmp1 |= maui_read () << (7 * i); } - printk ("Available DRAM %dk\n", tmp1 / 1024); + if (trace_init) + printk ("Available DRAM %dk\n", tmp1 / 1024); request_region (hw_config->io_base + 2, 6, "Maui"); @@ -222,7 +226,7 @@ attach_maui (long mem_start, struct address_info *hw_config) { int this_dev = num_midis; - printk (" "); + conf_printf ("Maui", hw_config); hw_config->irq *= -1; mem_start = attach_mpu401 (mem_start, hw_config); diff --git a/drivers/sound/midi_synth.c b/drivers/sound/midi_synth.c index 39680e28c46e..b396af8860b7 100644 --- a/drivers/sound/midi_synth.c +++ b/drivers/sound/midi_synth.c @@ -32,11 +32,11 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI) +#if defined(CONFIG_MIDI) #define _MIDI_SYNTH_C_ -static struct wait_queue *sysex_sleeper = NULL; +static wait_handle *sysex_sleeper = NULL; static volatile struct snd_wait sysex_sleep_flag = {0}; @@ -47,7 +47,7 @@ static int sysex_state[MAX_MIDI_DEV] = {0}; static unsigned char prev_out_status[MAX_MIDI_DEV]; -#ifdef EXCLUDE_SEQUENCER +#ifndef CONFIG_SEQUENCER #define STORE(cmd) #else #define STORE(cmd) \ @@ -472,6 +472,8 @@ midi_synth_open (int dev, int mode) inc->m_prev_status = 0x00; restore_flags (flags); + sysex_sleep_flag.mode = WK_NONE; + return 1; } @@ -545,7 +547,7 @@ midi_synth_load_patch (int dev, int format, const snd_rw_buf * addr, sysex_sleep_flag.mode = WK_NONE; - for (i = 0; i < left && !(current->signal & ~current->blocked); i++) + for (i = 0; i < left && !current_got_fatal_signal (); i++) { unsigned char data; @@ -566,17 +568,17 @@ midi_synth_load_patch (int dev, int format, const snd_rw_buf * addr, } while (!midi_devs[orig_dev]->putc (orig_dev, (unsigned char) (data & 0xff)) && - !(current->signal & ~current->blocked)) + !current_got_fatal_signal ()) { unsigned long tl; if (1) - current->timeout = tl = jiffies + (1); + current_set_timeout (tl = jiffies + (1)); else tl = 0xffffffff; sysex_sleep_flag.mode = WK_SLEEP; - interruptible_sleep_on (&sysex_sleeper); + module_interruptible_sleep_on (&sysex_sleeper); if (!(sysex_sleep_flag.mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -638,8 +640,8 @@ midi_synth_controller (int dev, int channel, int ctrl_num, int value) int orig_dev = synth_devs[dev]->midi_dev; int chn, msg; - if (ctrl_num < 1 || ctrl_num > 127) - return; /* NOTE! Controller # 0 ignored */ + if (ctrl_num < 0 || ctrl_num > 127) + return; if (channel < 0 || channel > 15) return; diff --git a/drivers/sound/midi_synth.h b/drivers/sound/midi_synth.h index 6256ea41ee6f..55386c455677 100644 --- a/drivers/sound/midi_synth.h +++ b/drivers/sound/midi_synth.h @@ -15,7 +15,6 @@ void midi_synth_controller (int dev, int channel, int ctrl_num, int value); int midi_synth_patchmgr (int dev, struct patmgr_info *rec); void midi_synth_bender (int dev, int chn, int value); void midi_synth_setup_voice (int dev, int voice, int chn); -void do_midi_msg (int synthno, unsigned char *msg, int mlen); int midi_synth_send_sysex(int dev, unsigned char *bytes,int len); #ifndef _MIDI_SYNTH_C_ diff --git a/drivers/sound/midibuf.c b/drivers/sound/midibuf.c index c1618a12c1d2..9270cafff930 100644 --- a/drivers/sound/midibuf.c +++ b/drivers/sound/midibuf.c @@ -29,7 +29,7 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI) +#if defined(CONFIG_MIDI) /* * Don't make MAX_QUEUE_SIZE larger than 4000 @@ -37,12 +37,12 @@ #define MAX_QUEUE_SIZE 4000 -static struct wait_queue *midi_sleeper[MAX_MIDI_DEV] = +static wait_handle *midi_sleeper[MAX_MIDI_DEV] = {NULL}; static volatile struct snd_wait midi_sleep_flag[MAX_MIDI_DEV] = { {0}}; -static struct wait_queue *input_sleeper[MAX_MIDI_DEV] = +static wait_handle *input_sleeper[MAX_MIDI_DEV] = {NULL}; static volatile struct snd_wait input_sleep_flag[MAX_MIDI_DEV] = { @@ -106,18 +106,18 @@ drain_midi_queue (int dev) */ if (midi_devs[dev]->buffer_status != NULL) - while (!(current->signal & ~current->blocked) && + while (!current_got_fatal_signal () && midi_devs[dev]->buffer_status (dev)) { unsigned long tl; if (HZ / 10) - current->timeout = tl = jiffies + (HZ / 10); + current_set_timeout (tl = jiffies + (HZ / 10)); else tl = 0xffffffff; midi_sleep_flag[dev].mode = WK_SLEEP; - interruptible_sleep_on (&midi_sleeper[dev]); + module_interruptible_sleep_on (&midi_sleeper[dev]); if (!(midi_sleep_flag[dev].mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -146,7 +146,7 @@ midi_input_intr (int dev, unsigned char data) if ((input_sleep_flag[dev].mode & WK_SLEEP)) { input_sleep_flag[dev].mode = WK_WAKEUP; - wake_up (&input_sleeper[dev]); + module_wake_up (&input_sleeper[dev]); }; } @@ -185,7 +185,7 @@ midi_poll (unsigned long dummy) (midi_sleep_flag[dev].mode & WK_SLEEP)) { midi_sleep_flag[dev].mode = WK_WAKEUP; - wake_up (&midi_sleeper[dev]); + module_wake_up (&midi_sleeper[dev]); }; } @@ -203,7 +203,6 @@ int MIDIbuf_open (int dev, struct fileinfo *file) { int mode, err; - unsigned long flags; dev = dev >> 4; mode = file->mode & O_ACCMODE; @@ -224,27 +223,20 @@ MIDIbuf_open (int dev, struct fileinfo *file) * Interrupts disabled. Be careful */ - save_flags (flags); - cli (); if ((err = midi_devs[dev]->open (dev, mode, midi_input_intr, midi_output_intr)) < 0) { - restore_flags (flags); return err; } parms[dev].prech_timeout = 0; - midi_sleep_flag[dev].mode = WK_NONE; - input_sleep_flag[dev].mode = WK_NONE; - midi_in_buf[dev] = (struct midi_buf *) kmalloc (sizeof (struct midi_buf), GFP_KERNEL); if (midi_in_buf[dev] == NULL) { printk ("midi: Can't allocate buffer\n"); midi_devs[dev]->close (dev); - restore_flags (flags); return -EIO; } midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0; @@ -257,20 +249,23 @@ MIDIbuf_open (int dev, struct fileinfo *file) midi_devs[dev]->close (dev); kfree (midi_in_buf[dev]); midi_in_buf[dev] = NULL; - restore_flags (flags); return -EIO; } midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0; - if (!open_devs) + open_devs++; + midi_sleep_flag[dev].mode = WK_NONE; + input_sleep_flag[dev].mode = WK_NONE; + + if (open_devs < 2) /* This was first open */ { - poll_timer.expires = (1) + jiffies; - add_timer (&poll_timer); - }; /* - * Come back later - */ - open_devs++; - restore_flags (flags); + ; + + { + poll_timer.expires = (1) + jiffies; + add_timer (&poll_timer); + }; /* Start polling */ + } return err; } @@ -284,6 +279,9 @@ MIDIbuf_release (int dev, struct fileinfo *file) dev = dev >> 4; mode = file->mode & O_ACCMODE; + if (dev < 0 || dev >= num_midis) + return; + save_flags (flags); cli (); @@ -298,18 +296,18 @@ MIDIbuf_release (int dev, struct fileinfo *file) * devices */ - while (!(current->signal & ~current->blocked) && + while (!current_got_fatal_signal () && DATA_AVAIL (midi_out_buf[dev])) { unsigned long tl; if (0) - current->timeout = tl = jiffies + (0); + current_set_timeout (tl = jiffies + (0)); else tl = 0xffffffff; midi_sleep_flag[dev].mode = WK_SLEEP; - interruptible_sleep_on (&midi_sleeper[dev]); + module_interruptible_sleep_on (&midi_sleeper[dev]); if (!(midi_sleep_flag[dev].mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -325,14 +323,17 @@ MIDIbuf_release (int dev, struct fileinfo *file) */ } + restore_flags (flags); + midi_devs[dev]->close (dev); + kfree (midi_in_buf[dev]); kfree (midi_out_buf[dev]); midi_in_buf[dev] = NULL; midi_out_buf[dev] = NULL; + if (open_devs < 2) + del_timer (&poll_timer);; open_devs--; - del_timer (&poll_timer);; - restore_flags (flags); } int @@ -365,11 +366,11 @@ MIDIbuf_write (int dev, struct fileinfo *file, const snd_rw_buf * buf, int count unsigned long tl; if (0) - current->timeout = tl = jiffies + (0); + current_set_timeout (tl = jiffies + (0)); else tl = 0xffffffff; midi_sleep_flag[dev].mode = WK_SLEEP; - interruptible_sleep_on (&midi_sleeper[dev]); + module_interruptible_sleep_on (&midi_sleeper[dev]); if (!(midi_sleep_flag[dev].mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -377,7 +378,7 @@ MIDIbuf_write (int dev, struct fileinfo *file, const snd_rw_buf * buf, int count } midi_sleep_flag[dev].mode &= ~WK_SLEEP; }; - if ((current->signal & ~current->blocked)) + if (current_got_fatal_signal ()) { restore_flags (flags); return -EINTR; @@ -424,11 +425,11 @@ MIDIbuf_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) unsigned long tl; if (parms[dev].prech_timeout) - current->timeout = tl = jiffies + (parms[dev].prech_timeout); + current_set_timeout (tl = jiffies + (parms[dev].prech_timeout)); else tl = 0xffffffff; input_sleep_flag[dev].mode = WK_SLEEP; - interruptible_sleep_on (&input_sleeper[dev]); + module_interruptible_sleep_on (&input_sleeper[dev]); if (!(input_sleep_flag[dev].mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -436,7 +437,7 @@ MIDIbuf_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) } input_sleep_flag[dev].mode &= ~WK_SLEEP; }; - if ((current->signal & ~current->blocked)) + if (current_got_fatal_signal ()) c = -EINTR; /* * The user is getting restless */ @@ -501,7 +502,7 @@ MIDIbuf_ioctl (int dev, struct fileinfo *file, } int -MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) +MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait) { dev = dev >> 4; @@ -511,7 +512,7 @@ MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wai if (!DATA_AVAIL (midi_in_buf[dev])) { input_sleep_flag[dev].mode = WK_SLEEP; - select_wait (&input_sleeper[dev], wait); + module_select_wait (&input_sleeper[dev], wait); return 0; } return 1; @@ -521,7 +522,7 @@ MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wai if (SPACE_AVAIL (midi_out_buf[dev])) { midi_sleep_flag[dev].mode = WK_SLEEP; - select_wait (&midi_sleeper[dev], wait); + module_select_wait (&midi_sleeper[dev], wait); return 0; } return 1; diff --git a/drivers/sound/mpu401.c b/drivers/sound/mpu401.c index df9fa738df80..d4507ee266d1 100644 --- a/drivers/sound/mpu401.c +++ b/drivers/sound/mpu401.c @@ -35,14 +35,12 @@ #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD - -#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) #include "coproc.h" static int init_sequence[20]; /* NOTE! pos 0 = len, start pos 1. */ -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL; #endif @@ -122,7 +120,7 @@ static void mpu_timer_interrupt (void); static void timer_ext_event (struct mpu_config *devc, int event, int parm); static struct synth_info mpu_synth_info_proto = -{"MPU-401 MIDI interface", 0, SYNTH_TYPE_MIDI, 0, 0, 128, 0, 128, SYNTH_CAP_INPUT}; +{"MPU-401 MIDI interface", 0, SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT}; static struct synth_info mpu_synth_info[MAX_MIDI_DEV]; @@ -153,7 +151,7 @@ static unsigned char len_tab[] = /* # of data bytes following a status 0 /* Fx */ }; -#ifdef EXCLUDE_SEQUENCER +#ifndef CONFIG_SEQUENCER #define STORE(cmd) #else #define STORE(cmd) \ @@ -576,11 +574,11 @@ mpu401_out (int dev, unsigned char midi_byte) devc = &dev_conf[dev]; /* - * Sometimes it takes about 13000 loops before the output becomes ready + * Sometimes it takes about 30000 loops before the output becomes ready * (After reset). Normally it takes just about 10 loops. */ - for (timeout = 3000; timeout > 0 && !output_ready (devc); timeout--); + for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--); save_flags (flags); cli (); @@ -919,6 +917,7 @@ mpu_synth_open (int dev, int mode) { mpu_cmd (midi_dev, 0x8B, 0); /* Enable data in stop mode */ mpu_cmd (midi_dev, 0x34, 0); /* Return timing bytes in stop mode */ + mpu_cmd (midi_dev, 0x87, 0); /* Enable pitch & controller */ } return 0; @@ -1129,9 +1128,6 @@ attach_mpu401 (long mem_start, struct address_info *hw_config) MPU_CAP_CLS | MPU_CAP_2PORT; revision_char = (devc->revision == 0x7f) ? 'M' : ' '; - printk (" ", - ports, - revision_char); sprintf (mpu_synth_info[num_midis].name, "MQX-%d%c MIDI Interface #%d", ports, @@ -1147,10 +1143,6 @@ attach_mpu401 (long mem_start, struct address_info *hw_config) devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK; - printk (" ", - (int) (devc->version & 0xf0) >> 4, - devc->version & 0x0f, - revision_char); sprintf (mpu_synth_info[num_midis].name, "MPU-401 %d.%d%c Midi interface #%d", (int) (devc->version & 0xf0) >> 4, @@ -1162,6 +1154,8 @@ attach_mpu401 (long mem_start, struct address_info *hw_config) strcpy (mpu401_midi_operations[num_midis].info.name, mpu_synth_info[num_midis].name); + conf_printf (mpu_synth_info[num_midis].name, hw_config); + mpu401_synth_operations[num_midis]->midi_dev = devc->devno = num_midis; mpu401_synth_operations[devc->devno]->info = &mpu_synth_info[devc->devno]; @@ -1273,7 +1267,7 @@ probe_mpu401 (struct address_info *hw_config) tmp_devc.opened = 0; tmp_devc.osp = hw_config->osp; -#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_MPU401) +#if defined(CONFIG_AEDSP16) && defined(AEDSP16_MPU401) /* * Initialize Audio Excel DSP 16 to MPU-401, before any operation. */ @@ -1311,7 +1305,7 @@ unload_mpu401 (struct address_info *hw_config) * Timer stuff ****************************************************/ -#if !defined(EXCLUDE_SEQUENCER) +#if defined(CONFIG_SEQUENCER) static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0; static volatile int curr_tempo, curr_timebase, hw_timebase; @@ -1828,6 +1822,4 @@ mpu_timer_init (int midi_dev) -#endif - #endif diff --git a/drivers/sound/opl3.c b/drivers/sound/opl3.c index ec47ef6597c3..0a1de665db0e 100644 --- a/drivers/sound/opl3.c +++ b/drivers/sound/opl3.c @@ -36,7 +36,7 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_YM3812) +#if defined(CONFIG_YM3812) #include "opl3.h" @@ -226,7 +226,7 @@ opl3_detect (int ioaddr, sound_os_info * osp) */ for (i = 0; i < 50; i++) - tenmicrosec (); + tenmicrosec (devc->osp); stat2 = inb (ioaddr); /* * Read status after timers have expired @@ -281,18 +281,18 @@ opl3_detect (int ioaddr, sound_os_info * osp) int tmp; outb (0x02, ioaddr - 8); /* Select OPL4 ID register */ - tenmicrosec (); + tenmicrosec (devc->osp); tmp = inb (ioaddr - 7); /* Read it */ - tenmicrosec (); + tenmicrosec (devc->osp); if (tmp == 0x20) /* OPL4 should return 0x20 here */ { detected_model = 4; outb (0xF8, ioaddr - 8); /* Select OPL4 FM mixer control */ - tenmicrosec (); + tenmicrosec (devc->osp); outb (0x1B, ioaddr - 7); /* Write value */ - tenmicrosec (); + tenmicrosec (devc->osp); } else detected_model = 3; @@ -775,7 +775,7 @@ opl3_command (int io_addr, unsigned int addr, unsigned int val) outb ((unsigned char) (addr & 0xff), io_addr); if (!devc->model != 2) - tenmicrosec (); + tenmicrosec (devc->osp); else for (i = 0; i < 2; i++) inb (io_addr); @@ -784,9 +784,9 @@ opl3_command (int io_addr, unsigned int addr, unsigned int val) if (devc->model != 2) { - tenmicrosec (); - tenmicrosec (); - tenmicrosec (); + tenmicrosec (devc->osp); + tenmicrosec (devc->osp); + tenmicrosec (devc->osp); } else for (i = 0; i < 2; i++) @@ -1222,9 +1222,9 @@ opl3_init (long mem_start, int ioaddr, sound_os_info * osp) if (devc->model == 2) { if (devc->is_opl4) - printk (" "); + conf_printf2 ("Yamaha OPL4/OPL3 FM", ioaddr, 0, -1, -1); else - printk (" "); + conf_printf2 ("Yamaha OPL3 FM", ioaddr, 0, -1, -1); devc->v_alloc->max_voice = devc->nr_voice = 18; devc->fm_info.nr_drums = 0; @@ -1242,7 +1242,7 @@ opl3_init (long mem_start, int ioaddr, sound_os_info * osp) } else { - printk (" "); + conf_printf2 ("Yamaha OPL2 FM", ioaddr, 0, -1, -1); devc->v_alloc->max_voice = devc->nr_voice = 9; devc->fm_info.nr_drums = 0; diff --git a/drivers/sound/os.h b/drivers/sound/os.h index b8de01c29b45..07e39c66e1eb 100644 --- a/drivers/sound/os.h +++ b/drivers/sound/os.h @@ -1,7 +1,18 @@ + #define ALLOW_SELECT -#undef ALLOW_BUFFER_MAPPING #undef NO_INLINE_ASM -#undef SHORT_BANNERS +#define SHORT_BANNERS + +#include + +#ifdef MODULE +#define __NO_VERSION__ +#include +#include +#ifdef MODVERSIONS +#include +#endif +#endif #include #include @@ -22,6 +33,7 @@ #include #include +#include #include @@ -46,3 +58,5 @@ extern caddr_t sound_mem_blocks[1024]; extern int sound_num_blocks; typedef int sound_os_info; + +#undef PSEUDO_DMA_AUTOINIT diff --git a/drivers/sound/pas2_card.c b/drivers/sound/pas2_card.c index 2d05dd422924..c9917052cf65 100644 --- a/drivers/sound/pas2_card.c +++ b/drivers/sound/pas2_card.c @@ -30,7 +30,7 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PAS) +#if defined(CONFIG_PAS) #define DEFINE_TRANSLATIONS #include "pas.h" @@ -93,14 +93,14 @@ pasintr (int irq, struct pt_regs *dummy) if (status & I_S_PCM_SAMPLE_BUFFER_IRQ) { -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO pas_pcm_interrupt (status, 1); #endif status &= ~I_S_PCM_SAMPLE_BUFFER_IRQ; } if (status & I_S_MIDI_IRQ) { -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI pas_midi_interrupt (); #endif status &= ~I_S_MIDI_IRQ; @@ -259,7 +259,7 @@ config_pas_hw (struct address_info *hw_config) mix_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER); mix_write (5, PARALLEL_MIXER); -#if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB) +#if defined(CONFIG_SB_EMULATION) && defined(CONFIG_SB) { struct address_info *sb_config; @@ -369,17 +369,22 @@ attach_pas_card (long mem_start, struct address_info *hw_config) if ((pas_model = pas_read (CHIP_REV))) { - printk (" <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID)); + char temp[100]; + + sprintf (temp, + "%s rev %d", pas_model_names[(int) pas_model], + pas_read (BOARD_REV_ID)); + conf_printf (temp, hw_config); } if (config_pas_hw (hw_config)) { -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO mem_start = pas_pcm_init (mem_start, hw_config); #endif -#if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB) +#if defined(CONFIG_SB_EMULATION) && defined(CONFIG_SB) sb_dsp_disable_midi (); /* * The SB emulation don't support * @@ -388,7 +393,7 @@ attach_pas_card (long mem_start, struct address_info *hw_config) #endif -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI mem_start = pas_midi_init (mem_start); #endif diff --git a/drivers/sound/pas2_midi.c b/drivers/sound/pas2_midi.c index 6ed91a83cad7..690773d395a7 100644 --- a/drivers/sound/pas2_midi.c +++ b/drivers/sound/pas2_midi.c @@ -29,11 +29,9 @@ #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD - #include "pas.h" -#if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_MIDI) +#if defined(CONFIG_PAS) && defined(CONFIG_MIDI) static int midi_busy = 0, input_opened = 0; static int my_dev; @@ -337,5 +335,3 @@ pas_midi_interrupt (void) } #endif - -#endif diff --git a/drivers/sound/pas2_mixer.c b/drivers/sound/pas2_mixer.c index d186f69d3f18..851091da3844 100644 --- a/drivers/sound/pas2_mixer.c +++ b/drivers/sound/pas2_mixer.c @@ -31,7 +31,7 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PAS) +#if defined(CONFIG_PAS) #include "pas.h" @@ -264,7 +264,7 @@ pas_mixer_ioctl (int dev, unsigned int cmd, ioctl_arg arg) if (((cmd >> 8) & 0xff) == 'M') { - if (cmd & IOC_IN) + if (_IOC_DIR (cmd) & _IOC_WRITE) return snd_ioctl_return ((int *) arg, pas_mixer_set (cmd & 0xff, get_fs_long ((long *) arg))); else { /* diff --git a/drivers/sound/pas2_pcm.c b/drivers/sound/pas2_pcm.c index cfe3eb6e9363..b4a185843680 100644 --- a/drivers/sound/pas2_pcm.c +++ b/drivers/sound/pas2_pcm.c @@ -30,11 +30,9 @@ #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD - #include "pas.h" -#if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_AUDIO) +#if defined(CONFIG_PAS) && defined(CONFIG_AUDIO) #define TRACE(WHAT) /* * * * (WHAT) */ @@ -446,5 +444,3 @@ pas_pcm_interrupt (unsigned char status, int cause) } #endif - -#endif diff --git a/drivers/sound/patmgr.c b/drivers/sound/patmgr.c index fd0568a2934d..7456d31d07e0 100644 --- a/drivers/sound/patmgr.c +++ b/drivers/sound/patmgr.c @@ -30,9 +30,9 @@ #define PATMGR_C #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SEQUENCER) +#if defined(CONFIG_SEQUENCER) -static struct wait_queue *server_procs[MAX_SYNTH_DEV] = +static wait_handle *server_procs[MAX_SYNTH_DEV] = {NULL}; static volatile struct snd_wait server_wait_flag[MAX_SYNTH_DEV] = { @@ -49,7 +49,7 @@ static int pmgr_opened[MAX_SYNTH_DEV] = #define A_TO_S 1 #define S_TO_A 2 -static struct wait_queue *appl_proc = NULL; +static wait_handle *appl_proc = NULL; static volatile struct snd_wait appl_wait_flag = {0}; @@ -83,7 +83,7 @@ pmgr_release (int dev) if ((appl_wait_flag.mode & WK_SLEEP)) { appl_wait_flag.mode = WK_WAKEUP; - wake_up (&appl_proc); + module_wake_up (&appl_proc); }; } @@ -102,31 +102,18 @@ pmgr_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) return -EIO; } - while (!ok && !(current->signal & ~current->blocked)) + while (!ok && !current_got_fatal_signal ()) { save_flags (flags); cli (); while (!(mbox[dev] && msg_direction[dev] == A_TO_S) && - !(current->signal & ~current->blocked)) + !current_got_fatal_signal ()) { - { - unsigned long tl; - - if (0) - current->timeout = tl = jiffies + (0); - else - tl = 0xffffffff; - server_wait_flag[dev].mode = WK_SLEEP; - interruptible_sleep_on (&server_procs[dev]); - if (!(server_wait_flag[dev].mode & WK_WAKEUP)) - { - if (jiffies >= tl) - server_wait_flag[dev].mode |= WK_TIMEOUT; - } - server_wait_flag[dev].mode &= ~WK_SLEEP; - }; + server_wait_flag[dev].mode = WK_SLEEP; + module_interruptible_sleep_on (&server_procs[dev]); + server_wait_flag[dev].mode &= ~WK_SLEEP;; } if (mbox[dev] && msg_direction[dev] == A_TO_S) @@ -193,7 +180,7 @@ pmgr_write (int dev, struct fileinfo *file, const snd_rw_buf * buf, int count) { { appl_wait_flag.mode = WK_WAKEUP; - wake_up (&appl_proc); + module_wake_up (&appl_proc); }; } } @@ -224,27 +211,14 @@ pmgr_access (int dev, struct patmgr_info *rec) { { server_wait_flag[dev].mode = WK_WAKEUP; - wake_up (&server_procs[dev]); + module_wake_up (&server_procs[dev]); }; } - { - unsigned long tl; - - if (0) - current->timeout = tl = jiffies + (0); - else - tl = 0xffffffff; - appl_wait_flag.mode = WK_SLEEP; - interruptible_sleep_on (&appl_proc); - if (!(appl_wait_flag.mode & WK_WAKEUP)) - { - if (jiffies >= tl) - appl_wait_flag.mode |= WK_TIMEOUT; - } - appl_wait_flag.mode &= ~WK_SLEEP; - }; + appl_wait_flag.mode = WK_SLEEP; + module_interruptible_sleep_on (&appl_proc); + appl_wait_flag.mode &= ~WK_SLEEP;; if (msg_direction[dev] != S_TO_A) { @@ -274,9 +248,19 @@ pmgr_inform (int dev, int event, unsigned long p1, unsigned long p2, unsigned long flags; int err = 0; + struct patmgr_info *tmp_mbox; + if (!pmgr_opened[dev]) return 0; + tmp_mbox = (struct patmgr_info *) kmalloc (sizeof (struct patmgr_info), GFP_KERNEL); + + if (tmp_mbox == NULL) + { + printk ("pmgr: Couldn't allocate memory for a message\n"); + return 0; + } + save_flags (flags); cli (); @@ -284,13 +268,8 @@ pmgr_inform (int dev, int event, unsigned long p1, unsigned long p2, printk (" PATMGR: Server %d mbox full. Why?\n", dev); else { - if ((mbox[dev] = - (struct patmgr_info *) kmalloc (sizeof (struct patmgr_info), GFP_KERNEL)) == NULL) - { - printk ("pmgr: Couldn't allocate memory for a message\n"); - return 0; - } + mbox[dev] = tmp_mbox; mbox[dev]->key = PM_K_EVENT; mbox[dev]->command = event; mbox[dev]->parm1 = p1; @@ -302,34 +281,20 @@ pmgr_inform (int dev, int event, unsigned long p1, unsigned long p2, { { server_wait_flag[dev].mode = WK_WAKEUP; - wake_up (&server_procs[dev]); + module_wake_up (&server_procs[dev]); }; } - { - unsigned long tl; - - if (0) - current->timeout = tl = jiffies + (0); - else - tl = 0xffffffff; - appl_wait_flag.mode = WK_SLEEP; - interruptible_sleep_on (&appl_proc); - if (!(appl_wait_flag.mode & WK_WAKEUP)) - { - if (jiffies >= tl) - appl_wait_flag.mode |= WK_TIMEOUT; - } - appl_wait_flag.mode &= ~WK_SLEEP; - }; - if (mbox[dev]) - kfree (mbox[dev]); + appl_wait_flag.mode = WK_SLEEP; + module_interruptible_sleep_on (&appl_proc); + appl_wait_flag.mode &= ~WK_SLEEP;; mbox[dev] = NULL; msg_direction[dev] = 0; } restore_flags (flags); + kfree (tmp_mbox); return err; } diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c index 384bc4b07943..4f365fb4a8a8 100644 --- a/drivers/sound/pss.c +++ b/drivers/sound/pss.c @@ -29,7 +29,7 @@ #include "sound_config.h" -#if defined (CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PSS) && !defined(EXCLUDE_AUDIO) +#if defined(CONFIG_PSS) && defined(CONFIG_AUDIO) /* * PSS registers. @@ -109,13 +109,6 @@ probe_pss (struct address_info *hw_config) return 0; } - if (irq != 3 && irq != 5 && irq != 7 && irq != 9 && - irq != 10 && irq != 11 && irq != 12) - return 0; - - if (dma != 5 && dma != 6 && dma != 7) - return 0; - id = inw (REG (PSS_ID)); if ((id >> 8) != 'E') { @@ -329,6 +322,7 @@ long attach_pss (long mem_start, struct address_info *hw_config) { unsigned short id; + char tmp[100]; devc->base = hw_config->io_base; devc->irq = hw_config->irq; @@ -370,7 +364,8 @@ attach_pss (long mem_start, struct address_info *hw_config) #endif pss_initialized = 1; - printk (" ", id); + sprintf (tmp, "ECHO-PSS Rev. %d", id); + conf_printf (tmp, hw_config); return mem_start; } @@ -426,7 +421,7 @@ probe_pss_mpu (struct address_info *hw_config) break; /* No more input */ } -#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) return probe_mpu401 (hw_config); #else return 0 @@ -700,7 +695,7 @@ attach_pss_mpu (long mem_start, struct address_info *hw_config) int prev_devs; long ret; -#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) prev_devs = num_midis; ret = attach_mpu401 (mem_start, hw_config); diff --git a/drivers/sound/sb16_dsp.c b/drivers/sound/sb16_dsp.c index 85e582469d44..34d8edc3657a 100644 --- a/drivers/sound/sb16_dsp.c +++ b/drivers/sound/sb16_dsp.c @@ -38,7 +38,7 @@ #include "sb.h" #include "sb_mixer.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_AUDIO) && !defined(EXCLUDE_SBPRO) +#if defined(CONFIG_SB) && defined(CONFIG_AUDIO) extern int sbc_base; extern sound_os_info *sb_osp; @@ -157,7 +157,7 @@ sb16_dsp_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local) { case SOUND_PCM_WRITE_RATE: if (local) - return dsp_set_speed ((long) arg); + return dsp_set_speed ((int) arg); return snd_ioctl_return ((int *) arg, dsp_set_speed (get_fs_long ((long *) arg))); case SOUND_PCM_READ_RATE: @@ -167,12 +167,12 @@ sb16_dsp_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local) case SNDCTL_DSP_STEREO: if (local) - return dsp_set_stereo ((long) arg); + return dsp_set_stereo ((int) arg); return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg))); case SOUND_PCM_WRITE_CHANNELS: if (local) - return dsp_set_stereo ((long) arg - 1) + 1; + return dsp_set_stereo ((int) arg - 1) + 1; return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg) - 1) + 1); case SOUND_PCM_READ_CHANNELS: @@ -182,7 +182,7 @@ sb16_dsp_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local) case SNDCTL_DSP_SETFMT: if (local) - return dsp_set_bits ((long) arg); + return dsp_set_bits ((int) arg); return snd_ioctl_return ((int *) arg, dsp_set_bits (get_fs_long ((long *) arg))); case SOUND_PCM_READ_BITS: @@ -260,8 +260,23 @@ sb16_dsp_close (int dev) restore_flags (flags); } +static unsigned long trg_buf; +static int trg_bytes; +static int trg_intrflag; +static int trg_restart; + static void sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart) +{ + trg_buf = buf; + trg_bytes = count; + trg_intrflag = intrflag; + trg_restart = dma_restart; + irq_mode = IMODE_OUTPUT; +} + +static void +actually_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart) { unsigned long flags, cnt; @@ -321,6 +336,16 @@ sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int static void sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart) +{ + trg_buf = buf; + trg_bytes = count; + trg_intrflag = intrflag; + trg_restart = dma_restart; + irq_mode = IMODE_INPUT; +} + +static void +actually_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart) { unsigned long flags, cnt; @@ -415,7 +440,18 @@ sb16_dsp_trigger (int dev, int bits) if (!bits) sb_dsp_command (0xd0); /* Halt DMA */ else if (bits & irq_mode) - sb_dsp_command (0xd4); /* Continue DMA */ + switch (irq_mode) + { + case IMODE_INPUT: + actually_start_input (my_dev, trg_buf, trg_bytes, + trg_intrflag, trg_restart); + break; + + case IMODE_OUTPUT: + actually_output_block (my_dev, trg_buf, trg_bytes, + trg_intrflag, trg_restart); + break; + } } static void @@ -491,7 +527,7 @@ sb16_dsp_init (long mem_start, struct address_info *hw_config) sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor); - printk (" <%s>", sb16_dsp_operations.name); + conf_printf (sb16_dsp_operations.name, hw_config); if (num_audiodevs < MAX_AUDIO_DEV) { @@ -520,11 +556,19 @@ int sb16_dsp_detect (struct address_info *hw_config) { struct address_info *sb_config; - extern int sbc_major; + extern int sbc_major, Jazz16_detected; + + extern void Jazz16_set_dma16 (int dma); if (sb16_dsp_ok) return 1; /* Can't drive two cards */ + if (Jazz16_detected) + { + Jazz16_set_dma16 (hw_config->dma); + return 0; + } + if (!(sb_config = sound_getconf (SNDCARD_SB))) { printk ("SB16 Error: Plain SB not configured\n"); diff --git a/drivers/sound/sb16_midi.c b/drivers/sound/sb16_midi.c index 79de8d056c50..cc553e7d951a 100644 --- a/drivers/sound/sb16_midi.c +++ b/drivers/sound/sb16_midi.c @@ -29,9 +29,7 @@ #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD - -#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_MIDI) +#if defined(CONFIG_SB) && defined(CONFIG_MIDI) #include "sb.h" @@ -60,8 +58,12 @@ static int sb16midi_detected = 0; static int my_dev; extern int sbc_base; +extern int Jazz16_detected; +extern int AudioDrive; + static int reset_sb16midi (void); static void (*midi_input_intr) (int dev, unsigned char data); +static volatile unsigned char input_byte; static void sb16midi_input_loop (void) @@ -70,7 +72,9 @@ sb16midi_input_loop (void) { unsigned char c = sb16midi_read (); - if (sb16midi_opened & OPEN_READ) + if (c == MPU_ACK) + input_byte = c; + else if (sb16midi_opened & OPEN_READ && midi_input_intr) midi_input_intr (my_dev, c); } } @@ -82,6 +86,13 @@ sb16midiintr (int unit) sb16midi_input_loop (); } +void +sbmidiintr (int irq, struct pt_regs *dummy) +{ + if (input_avail ()) + sb16midi_input_loop (); +} + static int sb16midi_open (int dev, int mode, void (*input) (int dev, unsigned char data), @@ -175,13 +186,13 @@ sb16midi_buffer_status (int dev) */ } -#define MIDI_SYNTH_NAME "SoundBlaster 16 Midi" +#define MIDI_SYNTH_NAME "SoundBlaster MPU" #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT #include "midi_synth.h" static struct midi_operations sb16midi_operations = { - {"SoundBlaster 16 Midi", 0, 0, SNDCARD_SB16MIDI}, + {"SoundBlaster MPU", 0, 0, SNDCARD_SB16MIDI}, &std_midi_synth, {0}, sb16midi_open, @@ -196,7 +207,6 @@ static struct midi_operations sb16midi_operations = NULL }; - long attach_sb16midi (long mem_start, struct address_info *hw_config) { @@ -206,18 +216,23 @@ attach_sb16midi (long mem_start, struct address_info *hw_config) sb16midi_base = hw_config->io_base; if (!sb16midi_detected) - return -EIO; + return mem_start; + + request_region (hw_config->io_base, 4, "SB MIDI"); save_flags (flags); cli (); for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* * Wait */ + input_byte = 0; sb16midi_cmd (UART_MODE_ON); ok = 0; for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (input_avail ()) + if (input_byte == MPU_ACK) + ok = 1; + else if (input_avail ()) if (sb16midi_read () == MPU_ACK) ok = 1; @@ -229,7 +244,7 @@ attach_sb16midi (long mem_start, struct address_info *hw_config) return mem_start; } - printk (" "); + conf_printf ("SoundBlaster MPU-401", hw_config); std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &sb16midi_operations; @@ -239,23 +254,25 @@ attach_sb16midi (long mem_start, struct address_info *hw_config) static int reset_sb16midi (void) { - unsigned long flags; int ok, timeout, n; /* * Send the RESET command. Try again if no success at the first time. */ + if (inb (STATPORT) == 0xff) + return 0; + ok = 0; - save_flags (flags); - cli (); + /*save_flags(flags);cli(); */ for (n = 0; n < 2 && !ok; n++) { for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* * Wait */ + input_byte = 0; sb16midi_cmd (MPU_RESET); /* * Send MPU-401 RESET Command */ @@ -266,7 +283,9 @@ reset_sb16midi (void) */ for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (input_avail ()) + if (input_byte == MPU_ACK) /* Interrupt */ + ok = 1; + else if (input_avail ()) if (sb16midi_read () == MPU_ACK) ok = 1; @@ -278,19 +297,28 @@ reset_sb16midi (void) * Flush input before enabling interrupts */ - restore_flags (flags); + /* restore_flags(flags); */ return ok; } - int probe_sb16midi (struct address_info *hw_config) { int ok = 0; extern int sbc_major; - if (sbc_major < 4) + extern void ess_midi_init (struct address_info *hw_config); + extern void Jazz16_midi_init (struct address_info *hw_config); + + if (check_region (hw_config->io_base, 4)) + return 0; + + if (AudioDrive) + ess_midi_init (hw_config); + else if (Jazz16_detected) + Jazz16_midi_init (hw_config); + else if (sbc_major < 4) return 0; /* Not a SB16 */ sb16midi_base = hw_config->io_base; @@ -307,8 +335,7 @@ probe_sb16midi (struct address_info *hw_config) void unload_sb16midi (struct address_info *hw_config) { + release_region (hw_config->io_base, 4); } #endif - -#endif diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c index d9e4d1e08cdd..08171e45fba3 100644 --- a/drivers/sound/sb_card.c +++ b/drivers/sound/sb_card.c @@ -32,18 +32,18 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) +#if defined(CONFIG_SB) #include "sb.h" long attach_sb_card (long mem_start, struct address_info *hw_config) { -#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_MIDI) +#if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI) if (!sb_dsp_detect (hw_config)) return mem_start; mem_start = sb_dsp_init (mem_start, hw_config); - request_region (hw_config->io_base, 16, "SB"); + request_region (hw_config->io_base, 16, "SoundBlaster"); #endif return mem_start; @@ -59,7 +59,7 @@ probe_sb (struct address_info *hw_config) return 0; } -#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_SBPRO) +#if defined(CONFIG_AEDSP16) && defined(AEDSP16_SBPRO) /* * Initialize Audio Excel DSP 16 to SBPRO. */ diff --git a/drivers/sound/sb_dsp.c b/drivers/sound/sb_dsp.c index 465e1bcf79ad..26286e1ce403 100644 --- a/drivers/sound/sb_dsp.c +++ b/drivers/sound/sb_dsp.c @@ -35,23 +35,22 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) - -#ifdef SM_WAVE -#define JAZZ16 -#endif +#if defined(CONFIG_SB) #include "sb.h" #include "sb_mixer.h" #undef SB_TEST_IRQ int sbc_base = 0; -static int sbc_irq = 0; +static int sbc_irq = 0, sbc_dma; static int open_mode = 0; /* Read, write or both */ int Jazz16_detected = 0; +int AudioDrive = 0; /* 1=ES1688 detected */ +static int ess_mpu_irq = 0; int sb_no_recording = 0; static int dsp_count = 0; static int trigger_bits; +static int mpu_base = 0, mpu_irq = 0; /* * The DSP channel can be used either for input or output. Variable @@ -68,46 +67,32 @@ int sb_dsp_ok = 0; /* * initialization * */ static int midi_disabled = 0; int sb_dsp_highspeed = 0; -int sbc_major = 1, sbc_minor = 0; /* - - - * * * * DSP version */ +int sbc_major = 1, sbc_minor = 0; static int dsp_stereo = 0; static int dsp_current_speed = DSP_DEFAULT_SPEED; static int sb16 = 0; static int irq_verified = 0; int sb_midi_mode = NORMAL_MIDI; -int sb_midi_busy = 0; /* - - - * * * * 1 if the process has output - * to * * MIDI */ +int sb_midi_busy = 0; int sb_dsp_busy = 0; -volatile int sb_irq_mode = IMODE_NONE; /* - - - * * * * IMODE_INPUT, * - * IMODE_OUTPUT * * or * - * IMODE_NONE */ +volatile int sb_irq_mode = IMODE_NONE; static volatile int irq_ok = 0; static int dma8 = 1; +static int dsp_16bit = 0; -#ifdef JAZZ16 /* 16 bit support */ -static int dsp_16bit = 0; -static int dma16 = 5; +static int dma16 = 1; static int dsp_set_bits (int arg); static int initialize_ProSonic16 (void); /* end of 16 bit support */ -#endif int sb_duplex_midi = 0; static int my_dev = 0; @@ -116,11 +101,12 @@ volatile int sb_intr_active = 0; static int dsp_speed (int); static int dsp_set_stereo (int mode); -int sb_dsp_command (unsigned char val); static void sb_dsp_reset (int dev); sound_os_info *sb_osp = NULL; -#if !defined(EXCLUDE_MIDI) || !defined(EXCLUDE_AUDIO) +static void ess_init (void); + +#if defined(CONFIG_MIDI) || defined(CONFIG_AUDIO) /* * Common code for the midi and pcm functions @@ -154,31 +140,59 @@ sb_dsp_command (unsigned char val) } printk ("SoundBlaster: DSP Command(%x) Timeout.\n", val); - printk ("IRQ conflict???\n"); return 0; } +static int +ess_write (unsigned char reg, unsigned char data) +{ + /* Write a byte to an extended mode register of ES1688 */ + + if (!sb_dsp_command (reg)) + return 0; + + return sb_dsp_command (data); +} + +static int +ess_read (unsigned char reg) +{ +/* Read a byte from an extended mode register of ES1688 */ + + int i; + + if (!sb_dsp_command (0xc0)) /* Read register command */ + return -1; + + if (!sb_dsp_command (reg)) + return -1; + + for (i = 1000; i; i--) + { + if (inb (DSP_DATA_AVAIL) & 0x80) + return inb (DSP_READ); + } + + return -1; +} + void sbintr (int irq, struct pt_regs *dummy) { int status; -#ifndef EXCLUDE_SBPRO - if (sb16) + if (sb16 && !AudioDrive) { unsigned char src = sb_getmixer (IRQ_STAT); /* Interrupt source register */ -#ifndef EXCLUDE_SB16 if (src & 3) sb16_dsp_interrupt (irq); -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI if (src & 4) sb16midiintr (irq); /* * SB MPU401 interrupt */ -#endif - #endif if (!(src & 1)) @@ -186,26 +200,23 @@ sbintr (int irq, struct pt_regs *dummy) * Not a DSP interupt */ } -#endif status = inb (DSP_DATA_AVAIL); /* * Clear interrupt */ - if (sb_intr_active) switch (sb_irq_mode) { case IMODE_OUTPUT: - sb_intr_active = 0; + if (!AudioDrive) + sb_intr_active = 0; DMAbuf_outputintr (my_dev, 1); break; case IMODE_INPUT: - sb_intr_active = 0; + if (!AudioDrive) + sb_intr_active = 0; DMAbuf_inputintr (my_dev); - /* - * A complete buffer has been input. Let's start new one - */ break; case IMODE_INIT: @@ -214,7 +225,7 @@ sbintr (int irq, struct pt_regs *dummy) break; case IMODE_MIDI: -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI sb_midi_interrupt (irq); #endif break; @@ -240,24 +251,31 @@ sb_reset_dsp (void) { int loopc; - outb (1, DSP_RESET); - tenmicrosec (); + if (AudioDrive) + outb (3, DSP_RESET); /* Reset FIFO too */ + else + outb (1, DSP_RESET); + + tenmicrosec (sb_osp); outb (0, DSP_RESET); - tenmicrosec (); - tenmicrosec (); - tenmicrosec (); + tenmicrosec (sb_osp); + tenmicrosec (sb_osp); + tenmicrosec (sb_osp); for (loopc = 0; loopc < 1000 && !(inb (DSP_DATA_AVAIL) & 0x80); loopc++); if (inb (DSP_READ) != 0xAA) return 0; /* Sorry */ + if (AudioDrive) + sb_dsp_command (0xc6); /* Enable extended mode */ + return 1; } #endif -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO static void dsp_speaker (char state) @@ -268,6 +286,36 @@ dsp_speaker (char state) sb_dsp_command (DSP_CMD_SPKOFF); } +static int +ess_speed (int speed) +{ + int rate; + unsigned char bits = 0; + + if (speed < 4000) + speed = 4000; + else if (speed > 48000) + speed = 48000; + + if (speed > 22000) + { + bits = 0x80; + rate = 256 - (795500 + speed / 2) / speed; + speed = 795500 / (256 - rate); + } + else + { + rate = 128 - (397700 + speed / 2) / speed; + speed = 397700 / (128 - rate); + } + + bits |= (unsigned char) rate; + ess_write (0xa1, bits); + + dsp_current_speed = speed; + return speed; +} + static int dsp_speed (int speed) { @@ -275,6 +323,9 @@ dsp_speed (int speed) unsigned long flags; int max_speed = 44100; + if (AudioDrive) + return ess_speed (speed); + if (speed < 4000) speed = 4000; @@ -306,7 +357,7 @@ dsp_speed (int speed) /* * Max. stereo speed is 22050 */ - if (dsp_stereo && speed > 22050 && Jazz16_detected == 0) + if (dsp_stereo && speed > 22050 && Jazz16_detected == 0 && AudioDrive == 0) speed = 22050; #endif @@ -373,9 +424,6 @@ dsp_set_stereo (int mode) { dsp_stereo = 0; -#ifdef EXCLUDE_SBPRO - return 0; -#else if (sbc_major < 3 || sb16) return 0; /* * Sorry no stereo @@ -389,14 +437,30 @@ dsp_set_stereo (int mode) dsp_stereo = !!mode; return dsp_stereo; -#endif } +static unsigned long trg_buf; +static int trg_bytes; +static int trg_intrflag; +static int trg_restart; + static void -sb_dsp_output_block (int dev, unsigned long buf, int count, +sb_dsp_output_block (int dev, unsigned long buf, int nr_bytes, int intrflag, int restart_dma) +{ + trg_buf = buf; + trg_bytes = nr_bytes; + trg_intrflag = intrflag; + trg_restart = restart_dma; + sb_irq_mode = IMODE_OUTPUT; +} + +static void +actually_output_block (int dev, unsigned long buf, int nr_bytes, + int intrflag, int restart_dma) { unsigned long flags; + int count = nr_bytes; if (!sb_irq_mode) dsp_speaker (ON); @@ -411,7 +475,17 @@ sb_dsp_output_block (int dev, unsigned long buf, int count, dsp_count = count; sb_irq_mode = IMODE_OUTPUT; - if (sb_dsp_highspeed) + + if (AudioDrive) + { + int c = 0x10000 - count; /* ES1688 increments the count */ + + ess_write (0xa4, (unsigned char) (c & 0xff)); + ess_write (0xa5, (unsigned char) ((c >> 8) & 0xff)); + + ess_write (0xb8, ess_read (0xb8) | 0x01); /* Go */ + } + else if (sb_dsp_highspeed) { save_flags (flags); cli (); @@ -450,6 +524,17 @@ sb_dsp_output_block (int dev, unsigned long buf, int count, static void sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int restart_dma) +{ + trg_buf = buf; + trg_bytes = count; + trg_intrflag = intrflag; + trg_restart = restart_dma; + sb_irq_mode = IMODE_INPUT; +} + +static void +actually_start_input (int dev, unsigned long buf, int count, int intrflag, + int restart_dma) { unsigned long flags; @@ -475,7 +560,17 @@ sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, dsp_count = count; sb_irq_mode = IMODE_INPUT; - if (sb_dsp_highspeed) + + if (AudioDrive) + { + int c = 0x10000 - count; /* ES1688 increments the count */ + + ess_write (0xa4, (unsigned char) (c & 0xff)); + ess_write (0xa5, (unsigned char) ((c >> 8) & 0xff)); + + ess_write (0xb8, ess_read (0xb8) | 0x01); /* Go */ + } + else if (sb_dsp_highspeed) { save_flags (flags); cli (); @@ -515,13 +610,24 @@ sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, static void sb_dsp_trigger (int dev, int bits) { - if (bits == trigger_bits) - return; if (!bits) sb_dsp_command (0xd0); /* Halt DMA */ else if (bits & sb_irq_mode) - sb_dsp_command (0xd4); /* Continue DMA */ + { + switch (sb_irq_mode) + { + case IMODE_INPUT: + actually_start_input (my_dev, trg_buf, trg_bytes, + trg_intrflag, trg_restart); + break; + + case IMODE_OUTPUT: + actually_output_block (my_dev, trg_buf, trg_bytes, + trg_intrflag, trg_restart); + break; + } + } trigger_bits = bits; } @@ -542,30 +648,61 @@ sb_dsp_prepare_for_input (int dev, int bsize, int bcount) * SB Pro */ { -#ifdef JAZZ16 - /* Select correct dma channel - * for 16/8 bit acccess - */ - audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8; - if (dsp_stereo) - sb_dsp_command (dsp_16bit ? 0xac : 0xa8); - else - sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0); -#else - /* 8 bit only cards use this - */ - if (dsp_stereo) - sb_dsp_command (0xa8); + if (AudioDrive) + { + + /* ess_init(); */ + ess_write (0xb8, 0x0e); /* Auto init DMA mode */ + ess_write (0xa8, (ess_read (0xa8) & ~0x04) | + (2 - dsp_stereo)); /* Mono/stereo */ + ess_write (0xb9, 2); /* Demand mode (2 bytes/xfer) */ + + if (!dsp_stereo) + { + if (dsp_16bit == 0) + { /* 8 bit mono */ + ess_write (0xb7, 0x51); + ess_write (0xb7, 0xd0); + } + else + { /* 16 bit mono */ + ess_write (0xb7, 0x71); + ess_write (0xb7, 0xf4); + } + } + else + { /* Stereo */ + if (!dsp_16bit) + { /* 8 bit stereo */ + ess_write (0xb7, 0x51); + ess_write (0xb7, 0x98); + } + else + { /* 16 bit stereo */ + ess_write (0xb7, 0x71); + ess_write (0xb7, 0xbc); + } + } + + ess_write (0xb1, (ess_read (0xb1) & 0x0f) | 0x50); + ess_write (0xb2, (ess_read (0xb2) & 0x0f) | 0x50); + } else - sb_dsp_command (0xa0); -#endif - dsp_speed (dsp_current_speed); /* - * Speed must be recalculated if - * #channels * changes - */ + { /* !AudioDrive */ + + /* Select correct dma channel + * for 16/8 bit acccess + */ + audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8; + if (dsp_stereo) + sb_dsp_command (dsp_16bit ? 0xac : 0xa8); + else + sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0); + + dsp_speed (dsp_current_speed); + } /* !AudioDrive */ } trigger_bits = 0; - sb_dsp_command (0xd0); /* Halt DMA */ return 0; } @@ -573,34 +710,72 @@ static int sb_dsp_prepare_for_output (int dev, int bsize, int bcount) { dsp_cleanup (); - dsp_speaker (ON); + dsp_speaker (OFF); -#ifndef EXCLUDE_SBPRO - if (sbc_major == 3) /* - * SB Pro - */ + if (sbc_major == 3) /* SB Pro (at least ) */ { -#ifdef JAZZ16 - /* 16 bit specific instructions - */ - audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8; - if (Jazz16_detected != 2) /* SM Wave */ - sb_mixer_set_stereo (dsp_stereo); - if (dsp_stereo) - sb_dsp_command (dsp_16bit ? 0xac : 0xa8); + + if (AudioDrive) + { + + /* ess_init(); */ + ess_write (0xb8, 4); /* Auto init DMA mode */ + ess_write (0xa8, ess_read (0xa8) | + (2 - dsp_stereo)); /* Mono/stereo */ + ess_write (0xb9, 2); /* Demand mode (2 bytes/xfer) */ + + if (!dsp_stereo) + { + if (dsp_16bit == 0) + { /* 8 bit mono */ + ess_write (0xb6, 0x80); + ess_write (0xb7, 0x51); + ess_write (0xb7, 0xd0); + } + else + { /* 16 bit mono */ + ess_write (0xb6, 0x00); + ess_write (0xb7, 0x71); + ess_write (0xb7, 0xf4); + } + } + else + { /* Stereo */ + if (!dsp_16bit) + { /* 8 bit stereo */ + ess_write (0xb6, 0x80); + ess_write (0xb7, 0x51); + ess_write (0xb7, 0x98); + } + else + { /* 16 bit stereo */ + ess_write (0xb6, 0x00); + ess_write (0xb7, 0x71); + ess_write (0xb7, 0xbc); + } + } + + ess_write (0xb1, (ess_read (0xb1) & 0x0f) | 0x50); + ess_write (0xb2, (ess_read (0xb2) & 0x0f) | 0x50); + } else - sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0); -#else - sb_mixer_set_stereo (dsp_stereo); -#endif - dsp_speed (dsp_current_speed); /* - * Speed must be recalculated if - * #channels * changes - */ + { /* !AudioDrive */ + + /* 16 bit specific instructions (Jazz16) + */ + audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8; + if (Jazz16_detected != 2) /* SM Wave */ + sb_mixer_set_stereo (dsp_stereo); + if (dsp_stereo) + sb_dsp_command (dsp_16bit ? 0xac : 0xa8); + else + sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0); + } /* !AudioDrive */ + } -#endif + trigger_bits = 0; - sb_dsp_command (0xd0); /* Halt DMA */ + dsp_speaker (ON); return 0; } @@ -653,11 +828,9 @@ sb_dsp_open (int dev, int mode) /* Allocate 8 bit dma */ -#ifdef JAZZ16 audio_devs[my_dev]->dmachan1 = dma8; -#endif -#ifdef JAZZ16 - /* Allocate 16 bit dma + + /* Allocate 16 bit dma (jazz16) */ if (Jazz16_detected != 0) if (dma16 != dma8) @@ -669,7 +842,6 @@ sb_dsp_open (int dev, int mode) return -EBUSY; } } -#endif sb_irq_mode = IMODE_NONE; @@ -682,7 +854,6 @@ sb_dsp_open (int dev, int mode) static void sb_dsp_close (int dev) { -#ifdef JAZZ16 /* Release 16 bit dma channel */ if (Jazz16_detected) @@ -692,7 +863,6 @@ sb_dsp_close (int dev) if (dma16 != dma8) sound_close_dma (dma16); } -#endif /* DMAbuf_close_dma (dev); */ sb_free_irq (); @@ -704,14 +874,11 @@ sb_dsp_close (int dev) open_mode = 0; } -#ifdef JAZZ16 -/* Function dsp_set_bits() only required for 16 bit cards - */ static int dsp_set_bits (int arg) { if (arg) - if (Jazz16_detected == 0) + if (Jazz16_detected == 0 && AudioDrive == 0) dsp_16bit = 0; else switch (arg) @@ -725,11 +892,10 @@ dsp_set_bits (int arg) default: dsp_16bit = 0; } + return dsp_16bit ? 16 : 8; } -#endif /* ifdef JAZZ16 */ - static int sb_dsp_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local) { @@ -737,7 +903,7 @@ sb_dsp_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local) { case SOUND_PCM_WRITE_RATE: if (local) - return dsp_speed ((long) arg); + return dsp_speed ((int) arg); return snd_ioctl_return ((int *) arg, dsp_speed (get_fs_long ((long *) arg))); break; @@ -749,7 +915,7 @@ sb_dsp_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local) case SOUND_PCM_WRITE_CHANNELS: if (local) - return dsp_set_stereo ((long) arg - 1) + 1; + return dsp_set_stereo ((int) arg - 1) + 1; return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg) - 1) + 1); break; @@ -761,11 +927,10 @@ sb_dsp_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local) case SNDCTL_DSP_STEREO: if (local) - return dsp_set_stereo ((long) arg); + return dsp_set_stereo ((int) arg); return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg))); break; -#ifdef JAZZ16 /* Word size specific cases here. * SNDCTL_DSP_SETFMT=SOUND_PCM_WRITE_BITS */ @@ -780,14 +945,6 @@ sb_dsp_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local) return dsp_16bit ? 16 : 8; return snd_ioctl_return ((int *) arg, dsp_16bit ? 16 : 8); break; -#else - case SOUND_PCM_WRITE_BITS: - case SOUND_PCM_READ_BITS: - if (local) - return 8; - return snd_ioctl_return ((int *) arg, 8); /* Only 8 bits/sample supported */ - break; -#endif /* ifdef JAZZ16 */ case SOUND_PCM_WRITE_FILTER: case SOUND_PCM_READ_FILTER: @@ -818,8 +975,6 @@ sb_dsp_reset (int dev) #endif -#ifdef JAZZ16 - /* * Initialization of a Media Vision ProSonic 16 Soundcard. * The function initializes a ProSonic 16 like PROS.EXE does for DOS. It sets @@ -845,7 +1000,6 @@ get_sb_byte (void) return 0xffff; } -#ifdef SM_WAVE /* * Logitech Soundman Wave detection and initialization by Hannu Savolainen. * @@ -914,7 +1068,7 @@ initialize_smw (int mpu_base) outb ((control & 0xfe) | 2, mpu_base + 7); /* xxxxxxx0 resets the mc */ for (i = 0; i < 300; i++) /* Wait at least 1ms */ - tenmicrosec (); + tenmicrosec (sb_osp); outb (control & 0xfc, mpu_base + 7); /* xxxxxx00 enables RAM */ @@ -923,7 +1077,7 @@ initialize_smw (int mpu_base) */ smw_putmem (mp_base, 0, 0x00); smw_putmem (mp_base, 1, 0xff); - tenmicrosec (); + tenmicrosec (sb_osp); if (smw_getmem (mp_base, 0) != 0x00 || smw_getmem (mp_base, 1) != 0xff) { @@ -995,8 +1149,6 @@ initialize_smw (int mpu_base) return 1; } -#endif - static int initialize_ProSonic16 (void) { @@ -1005,23 +1157,9 @@ initialize_ProSonic16 (void) {0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6}, dma_translat[8] = {0, 1, 0, 2, 0, 3, 0, 4}; - struct address_info *mpu_config; - - int mpu_base, mpu_irq; - - if ((mpu_config = sound_getconf (SNDCARD_MPU401))) - { - mpu_base = mpu_config->io_base; - mpu_irq = mpu_config->irq; - } - else - { - mpu_base = mpu_irq = 0; - } - outb (0xAF, 0x201); /* ProSonic/Jazz16 wakeup */ for (x = 0; x < 1000; ++x) /* wait 10 milliseconds */ - tenmicrosec (); + tenmicrosec (sb_osp); outb (0x50, 0x201); outb ((sbc_base & 0x70) | ((mpu_base & 0x30) >> 4), 0x201); @@ -1036,18 +1174,15 @@ initialize_ProSonic16 (void) return 1; if (sb_dsp_command (0xFB) && /* set DMA-channels and Interrupts */ - sb_dsp_command ((dma_translat[JAZZ_DMA16] << 4) | dma_translat[dma8]) && + sb_dsp_command ((dma_translat[dma16] << 4) | dma_translat[dma8]) && sb_dsp_command ((int_translat[mpu_irq] << 4) | int_translat[sbc_irq])) { Jazz16_detected = 1; - if (mpu_base == 0) - printk ("Jazz16: No MPU401 devices configured - MIDI port not initialized\n"); -#ifdef SM_WAVE if (mpu_base != 0) if (initialize_smw (mpu_base)) Jazz16_detected = 2; -#endif + sb_dsp_disable_midi (); } @@ -1056,37 +1191,29 @@ initialize_ProSonic16 (void) return 0; /* No SB or ProSonic16 detected */ } -#endif /* ifdef JAZZ16 */ - int sb_dsp_detect (struct address_info *hw_config) { sbc_base = hw_config->io_base; sbc_irq = hw_config->irq; + sbc_dma = hw_config->dma; sb_osp = hw_config->osp; if (sb_dsp_ok) return 0; /* * Already initialized */ - dma8 = hw_config->dma; - -#ifdef JAZZ16 - dma16 = JAZZ_DMA16; + dma8 = dma16 = hw_config->dma; if (!initialize_ProSonic16 ()) return 0; -#else - if (!sb_reset_dsp ()) - return 0; -#endif return 1; /* * Detected */ } -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO static struct audio_operations sb_dsp_operations = { "SoundBlaster", @@ -1111,16 +1238,154 @@ static struct audio_operations sb_dsp_operations = #endif +static void +ess_init (void) /* ESS1688 Initialization */ +{ + unsigned char cfg, irq_bits = 0, dma_bits = 0; + + AudioDrive = 1; + midi_disabled = 1; + + sb_reset_dsp (); /* Turn on extended mode */ + +/* + * Set IRQ configuration register + */ + + cfg = 0x50; /* Enable only DMA counter interrupt */ + + switch (sbc_irq) + { + case 2: + case 9: + irq_bits = 0; + break; + + case 5: + irq_bits = 1; + break; + + case 7: + irq_bits = 2; + break; + + case 10: + irq_bits = 3; + break; + + default: + irq_bits = 0; + cfg = 0x10; /* Disable all interrupts */ + printk ("\nESS1688: Invalid IRQ %d\n", sbc_irq); + } + + if (!ess_write (0xb1, cfg | (irq_bits << 2))) + printk ("\nESS1688: Failed to write to IRQ config register\n"); + +/* + * Set DMA configuration register + */ + + cfg = 0x50; /* Extended mode DMA ebable */ + + if (sbc_dma > 3 || sbc_dma < 0 || sbc_dma == 2) + { + dma_bits = 0; + cfg = 0x00; /* Disable all DMA */ + printk ("\nESS1688: Invalid DMA %d\n", sbc_dma); + } + else + { + if (sbc_dma == 3) + dma_bits = 3; + else + dma_bits = sbc_dma + 1; + } + + if (!ess_write (0xb2, cfg | (dma_bits << 2))) + printk ("\nESS1688: Failed to write to DMA config register\n"); + +/* + * Enable joystick and OPL3 + */ + + cfg = sb_getmixer (0x40); + sb_setmixer (0x40, cfg | 0x03); +} + +void +ess_midi_init (struct address_info *hw_config) /* called from sb16_midi.c */ +{ + unsigned char cfg, tmp; + + cfg = sb_getmixer (0x40) & 0x03; + + tmp = (hw_config->io_base & 0x0f0) >> 4; + + if (tmp > 3) + { + sb_setmixer (0x40, cfg); + return; + } + + cfg |= tmp << 3; + + tmp = 1; /* MPU enabled without interrupts */ + + switch (hw_config->irq) + { + case 9: + tmp = 0x4; + break; + case 5: + tmp = 0x5; + break; + case 7: + tmp = 0x6; + break; + case 10: + tmp = 0x7; + break; + } + + cfg |= tmp << 5; + + if (tmp != 1) + { + ess_mpu_irq = hw_config->irq; + + if (snd_set_irq_handler (ess_mpu_irq, sbmidiintr, "ES1688 MIDI", sb_osp) < 0) + printk ("ES1688: Can't allocate IRQ%d\n", ess_mpu_irq); + } + + sb_setmixer (0x40, cfg); +} + +void +Jazz16_midi_init (struct address_info *hw_config) +{ + mpu_base = hw_config->io_base; + mpu_irq = hw_config->irq; + + initialize_ProSonic16 (); +} + +void +Jazz16_set_dma16 (int dma) +{ + dma16 = dma; + + initialize_ProSonic16 (); +} + long sb_dsp_init (long mem_start, struct address_info *hw_config) { int i; + int ess_major = 0, ess_minor = 0; -#ifndef EXCLUDE_SBPRO int mixer_type = 0; -#endif - sb_osp = hw_config->osp; sbc_major = sbc_minor = 0; sb_dsp_command (0xe1); /* @@ -1158,7 +1423,6 @@ sb_dsp_init (long mem_start, struct address_info *hw_config) if (sbc_major == 3 && sbc_minor == 1) { - int ess_major = 0, ess_minor = 0; /* * Try to detect ESS chips. @@ -1183,28 +1447,12 @@ sb_dsp_init (long mem_start, struct address_info *hw_config) } } } - - if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) - printk ("Hmm... Could this be an ESS488 based card (rev %d)\n", - ess_minor & 0x0f); - else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) - printk ("Hmm... Could this be an ESS688 based card (rev %d)\n", - ess_minor & 0x0f); } if (snd_set_irq_handler (sbc_irq, sbintr, "SoundBlaster", sb_osp) < 0) printk ("sb_dsp: Can't allocate IRQ\n");; -#ifndef EXCLUDE_SBPRO - if (sbc_major >= 3) - mixer_type = sb_mixer_init (sbc_major); -#else - if (sbc_major >= 3) - printk ("\n\n\n\nNOTE! SB Pro support is required with your soundcard!\n\n\n"); -#endif - - -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO if (sbc_major >= 3) { if (Jazz16_detected) @@ -1228,6 +1476,20 @@ sb_dsp_init (long mem_start, struct address_info *hw_config) { sprintf (sb_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor); } + else if (ess_major != 0) + { + if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) + sprintf (sb_dsp_operations.name, "ESS ES488 AudioDrive (rev %d)", + ess_minor & 0x0f); + else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) + { + sprintf (sb_dsp_operations.name, + "ESS ES1688 AudioDrive (rev %d)", + ess_minor & 0x0f); + sb_dsp_operations.format_mask |= AFMT_S16_LE; + ess_init (); + } + } else { sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor); @@ -1238,23 +1500,26 @@ sb_dsp_init (long mem_start, struct address_info *hw_config) sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", sbc_major, sbc_minor); } - printk (" <%s>", sb_dsp_operations.name); + conf_printf (sb_dsp_operations.name, hw_config); -#if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO) - if (!sb16) /* - * There is a better driver for SB16 - */ -#endif + if (sbc_major >= 3) + mixer_type = sb_mixer_init (sbc_major); + + if (!sb16) if (num_audiodevs < MAX_AUDIO_DEV) { audio_devs[my_dev = num_audiodevs++] = &sb_dsp_operations; + + if (AudioDrive) + audio_devs[my_dev]->flags |= DMA_AUTOMODE; + audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; dma8 = audio_devs[my_dev]->dmachan1 = hw_config->dma; audio_devs[my_dev]->dmachan2 = -1; - if (sound_alloc_dma (hw_config->dma, "soundblaster")) + if (sound_alloc_dma (hw_config->dma, "SoundBlaster")) printk ("sb_dsp.c: Can't allocate DMA channel\n"); -#ifdef JAZZ16 - /* Allocate 16 bit dma + + /* Allocate 16 bit dma (Jazz16) */ if (Jazz16_detected != 0) if (dma16 != dma8) @@ -1264,15 +1529,14 @@ sb_dsp_init (long mem_start, struct address_info *hw_config) printk ("Jazz16: Can't allocate 16 bit DMA channel\n"); } } -#endif } else printk ("SB: Too many DSP devices available\n"); #else - printk (" "); + conf_printf ("SoundBlaster (configured without audio support)", hw_config); #endif -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI if (!midi_disabled && !sb16) /* * Midi don't work in the SB emulation mode * * of PAS, SB16 has better midi interface @@ -1288,16 +1552,20 @@ void sb_dsp_unload (void) { sound_free_dma (dma8); -#ifdef JAZZ16 - /* Allocate 16 bit dma + + /* Free 16 bit dma (Jazz16) */ if (Jazz16_detected != 0) if (dma16 != dma8) { sound_free_dma (dma16); } -#endif snd_release_irq (sbc_irq); + + if (AudioDrive && ess_mpu_irq) + { + snd_release_irq (ess_mpu_irq); + } } void diff --git a/drivers/sound/sb_midi.c b/drivers/sound/sb_midi.c index 32fa376060bb..9e92383daf25 100644 --- a/drivers/sound/sb_midi.c +++ b/drivers/sound/sb_midi.c @@ -29,7 +29,7 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_MIDI) +#if defined(CONFIG_SB) && defined(CONFIG_MIDI) #include "sb.h" #undef SB_TEST_IRQ diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c index bd5603d9eb73..0b951e627f69 100644 --- a/drivers/sound/sb_mixer.c +++ b/drivers/sound/sb_mixer.c @@ -34,7 +34,7 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_SBPRO) +#if defined(CONFIG_SB) #define __SB_MIXER_C__ #include "sb.h" @@ -44,6 +44,7 @@ extern int sbc_base; extern int Jazz16_detected; extern sound_os_info *sb_osp; +extern int AudioDrive; static int mixer_initialized = 0; @@ -64,9 +65,9 @@ sb_setmixer (unsigned int port, unsigned int value) outb ((unsigned char) (port & 0xff), MIXER_ADDR); /* * Select register */ - tenmicrosec (); + tenmicrosec (sb_osp); outb ((unsigned char) (value & 0xff), MIXER_DATA); - tenmicrosec (); + tenmicrosec (sb_osp); restore_flags (flags); } @@ -81,9 +82,9 @@ sb_getmixer (unsigned int port) outb ((unsigned char) (port & 0xff), MIXER_ADDR); /* * Select register */ - tenmicrosec (); + tenmicrosec (sb_osp); val = inb (MIXER_DATA); - tenmicrosec (); + tenmicrosec (sb_osp); restore_flags (flags); return val; @@ -201,7 +202,6 @@ sb_mixer_get (int dev) return levels[dev]; } -#ifdef JAZZ16 static char smw_mix_regs[] = /* Left mixer registers */ { 0x0b, /* SOUND_MIXER_VOLUME */ @@ -293,8 +293,6 @@ smw_mixer_set (int dev, int value) return left | (right << 8); } -#endif - static int sb_mixer_set (int dev, int value) { @@ -304,10 +302,8 @@ sb_mixer_set (int dev, int value) int regoffs; unsigned char val; -#ifdef JAZZ16 if (Jazz16_detected == 2) return smw_mixer_set (dev, value); -#endif if (left > 100) left = 100; @@ -449,7 +445,7 @@ sb_mixer_ioctl (int dev, unsigned int cmd, ioctl_arg arg) { if (((cmd >> 8) & 0xff) == 'M') { - if (cmd & IOC_IN) + if (_IOC_DIR (cmd) & _IOC_WRITE) switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: @@ -539,8 +535,13 @@ sb_mixer_init (int major_model) case 3: mixer_caps = SOUND_CAP_EXCL_INPUT; -#ifdef JAZZ16 - if (Jazz16_detected == 2) /* SM Wave */ + if (AudioDrive) + { + supported_devices = ES688_MIXER_DEVICES; + supported_rec_devices = ES688_RECORDING_DEVICES; + iomap = &es688_mix; + } + else if (Jazz16_detected == 2) /* SM Wave */ { supported_devices = 0; supported_rec_devices = 0; @@ -549,7 +550,6 @@ sb_mixer_init (int major_model) mixer_type = 1; } else -#endif #ifdef __SGNXPRO__ if (mixer_type == 2) /* A SGNXPRO was detected */ { diff --git a/drivers/sound/sb_mixer.h b/drivers/sound/sb_mixer.h index cd103a7248de..0a92e5e33d67 100644 --- a/drivers/sound/sb_mixer.h +++ b/drivers/sound/sb_mixer.h @@ -50,6 +50,9 @@ #define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ SOUND_MASK_CD) +#define ES688_RECORDING_DEVICES SBPRO_RECORDING_DEVICES +#define ES688_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_LINE2|SOUND_MASK_SPEAKER) + #define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ SOUND_MASK_CD | \ SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \ @@ -131,6 +134,25 @@ MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0) }; +mixer_tab es688_mix = { +MIX_ENT(SOUND_MIXER_VOLUME, 0x32, 7, 4, 0x32, 3, 4), +MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4), +MIX_ENT(SOUND_MIXER_PCM, 0x14, 7, 4, 0x14, 3, 4), +MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4), +MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4), +MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4), +MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4), +MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0) +}; #ifdef __SGNXPRO__ mixer_tab sgnxpro_mix = { @@ -187,7 +209,10 @@ static unsigned short levels[SOUND_MIXER_NRDEVICES] = 0x4b4b, /* SB PCM */ 0x4b4b, /* Recording level */ 0x4b4b, /* Input gain */ - 0x4b4b}; /* Output gain */ + 0x4b4b, /* Output gain */ + 0x4040, /* Line1 */ + 0x4040, /* Line2 */ + 0x1515 /* Line3 */ #else /* If the user selected just plain SB Pro */ @@ -206,7 +231,11 @@ static unsigned short levels[SOUND_MIXER_NRDEVICES] = 0x4b4b, /* SB PCM */ 0x4b4b, /* Recording level */ 0x4b4b, /* Input gain */ - 0x4b4b}; /* Output gain */ + 0x4b4b, /* Output gain */ + 0x4040, /* Line1 */ + 0x4040, /* Line2 */ + 0x1515 /* Line3 */ +}; #endif /* SM_GAMES */ static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] = diff --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c index c838c277a972..be651ae1bbf2 100644 --- a/drivers/sound/sequencer.c +++ b/drivers/sound/sequencer.c @@ -30,9 +30,7 @@ #define SEQUENCER_C #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD - -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER #include "midi_ctrl.h" @@ -58,10 +56,10 @@ static int max_synthdev = 0; #define SEQ_2 2 static int seq_mode = SEQ_1; -static struct wait_queue *seq_sleeper = NULL; +static wait_handle *seq_sleeper = NULL; static volatile struct snd_wait seq_sleep_flag = {0}; -static struct wait_queue *midi_sleeper = NULL; +static wait_handle *midi_sleeper = NULL; static volatile struct snd_wait midi_sleep_flag = {0}; @@ -84,7 +82,7 @@ static unsigned char *iqueue = NULL; static volatile int qhead = 0, qtail = 0, qlen = 0; static volatile int iqhead = 0, iqtail = 0, iqlen = 0; static volatile int seq_playing = 0; -static int sequencer_busy = 0; +static volatile int sequencer_busy = 0; static int output_treshold; static int pre_event_timeout; static unsigned synth_open_mask; @@ -132,11 +130,11 @@ sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) unsigned long tl; if (pre_event_timeout) - current->timeout = tl = jiffies + (pre_event_timeout); + current_set_timeout (tl = jiffies + (pre_event_timeout)); else tl = 0xffffffff; midi_sleep_flag.mode = WK_SLEEP; - interruptible_sleep_on (&midi_sleeper); + module_interruptible_sleep_on (&midi_sleeper); if (!(midi_sleep_flag.mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -202,7 +200,7 @@ seq_copy_to_input (unsigned char *event, int len) { { midi_sleep_flag.mode = WK_WAKEUP; - wake_up (&midi_sleeper); + module_wake_up (&midi_sleeper); }; } restore_flags (flags); @@ -276,9 +274,7 @@ sequencer_write (int dev, struct fileinfo *file, const snd_rw_buf * buf, int cou if (mode == OPEN_READ) return -EIO; - if (dev) /* - * Patch manager device - */ + if (dev) return pmgr_write (dev - 1, file, buf, count); c = count; @@ -412,22 +408,9 @@ seq_queue (unsigned char *note, char nonblock) * Sleep until there is enough space on the queue */ - { - unsigned long tl; - - if (0) - current->timeout = tl = jiffies + (0); - else - tl = 0xffffffff; - seq_sleep_flag.mode = WK_SLEEP; - interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.mode & WK_WAKEUP)) - { - if (jiffies >= tl) - seq_sleep_flag.mode |= WK_TIMEOUT; - } - seq_sleep_flag.mode &= ~WK_SLEEP; - }; + seq_sleep_flag.mode = WK_SLEEP; + module_interruptible_sleep_on (&seq_sleeper); + seq_sleep_flag.mode &= ~WK_SLEEP;; } if (qlen >= SEQ_MAX_QUEUE) @@ -729,7 +712,7 @@ seq_timing_event (unsigned char *event) { { seq_sleep_flag.mode = WK_WAKEUP; - wake_up (&seq_sleeper); + module_wake_up (&seq_sleeper); }; } restore_flags (flags); @@ -769,7 +752,7 @@ seq_timing_event (unsigned char *event) { { seq_sleep_flag.mode = WK_WAKEUP; - wake_up (&seq_sleeper); + module_wake_up (&seq_sleeper); }; } restore_flags (flags); @@ -819,7 +802,7 @@ seq_local_event (unsigned char *event) switch (cmd) { case LOCL_STARTAUDIO: -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO DMAbuf_start_devices (parm); #endif break; @@ -905,7 +888,7 @@ play_event (unsigned char *q) { { seq_sleep_flag.mode = WK_WAKEUP; - wake_up (&seq_sleeper); + module_wake_up (&seq_sleeper); }; } restore_flags (flags); @@ -1041,7 +1024,7 @@ seq_startplay (void) { { seq_sleep_flag.mode = WK_WAKEUP; - wake_up (&seq_sleeper); + module_wake_up (&seq_sleeper); }; } restore_flags (flags); @@ -1095,6 +1078,7 @@ sequencer_open (int dev, struct fileinfo *file) { int retval, mode, i; int level, tmp; + unsigned long flags; level = ((dev & 0x0f) == SND_DEV_SEQ2) ? 2 : 1; @@ -1109,9 +1093,7 @@ sequencer_open (int dev, struct fileinfo *file) return -ENXIO; } - if (dev) /* - * Patch manager device - */ + if (dev) /* Patch manager device */ { int err; @@ -1125,19 +1107,22 @@ sequencer_open (int dev, struct fileinfo *file) if (pmgr_present[dev]) return -EBUSY; if ((err = pmgr_open (dev)) < 0) - return err; /* - * Failed - */ + return err; pmgr_present[dev] = 1; return err; } + save_flags (flags); + cli (); if (sequencer_busy) { printk ("Sequencer busy\n"); + restore_flags (flags); return -EBUSY; } + sequencer_busy = 1; + restore_flags (flags); max_mididev = num_midis; max_synthdev = num_synths; @@ -1173,6 +1158,7 @@ sequencer_open (int dev, struct fileinfo *file) if (tmr == NULL) { printk ("sequencer: No timer for level 2\n"); + sequencer_busy = 0; return -ENXIO; } setup_mode2 (); @@ -1182,6 +1168,7 @@ sequencer_open (int dev, struct fileinfo *file) if (!max_mididev) { printk ("Sequencer: No Midi devices. Input not possible\n"); + sequencer_busy = 0; return -ENXIO; } @@ -1239,7 +1226,6 @@ sequencer_open (int dev, struct fileinfo *file) tmr->open (tmr_no, seq_mode); } - sequencer_busy = 1; seq_sleep_flag.mode = WK_NONE; midi_sleep_flag.mode = WK_NONE; output_treshold = SEQ_MAX_QUEUE / 2; @@ -1262,7 +1248,7 @@ seq_drain_midi_queues (void) n = 1; - while (!(current->signal & ~current->blocked) && n) + while (!current_got_fatal_signal () && n) { n = 0; @@ -1282,11 +1268,11 @@ seq_drain_midi_queues (void) unsigned long tl; if (HZ / 10) - current->timeout = tl = jiffies + (HZ / 10); + current_set_timeout (tl = jiffies + (HZ / 10)); else tl = 0xffffffff; seq_sleep_flag.mode = WK_SLEEP; - interruptible_sleep_on (&seq_sleeper); + module_interruptible_sleep_on (&seq_sleeper); if (!(seq_sleep_flag.mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -1324,7 +1310,7 @@ sequencer_release (int dev, struct fileinfo *file) if (mode != OPEN_READ && !(file->flags & (O_NONBLOCK) ? 1 : 0)) - while (!(current->signal & ~current->blocked) && qlen) + while (!current_got_fatal_signal () && qlen) { seq_sync (); } @@ -1370,7 +1356,7 @@ seq_sync (void) { unsigned long flags; - if (qlen && !seq_playing && !(current->signal & ~current->blocked)) + if (qlen && !seq_playing && !current_got_fatal_signal ()) seq_startplay (); save_flags (flags); @@ -1381,12 +1367,12 @@ seq_sync (void) { unsigned long tl; - if (0) - current->timeout = tl = jiffies + (0); + if (HZ) + current_set_timeout (tl = jiffies + (HZ)); else tl = 0xffffffff; seq_sleep_flag.mode = WK_SLEEP; - interruptible_sleep_on (&seq_sleeper); + module_interruptible_sleep_on (&seq_sleeper); if (!(seq_sleep_flag.mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -1427,11 +1413,11 @@ midi_outc (int dev, unsigned char data) unsigned long tl; if (4) - current->timeout = tl = jiffies + (4); + current_set_timeout (tl = jiffies + (4)); else tl = 0xffffffff; seq_sleep_flag.mode = WK_SLEEP; - interruptible_sleep_on (&seq_sleeper); + module_interruptible_sleep_on (&seq_sleeper); if (!(seq_sleep_flag.mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -1521,7 +1507,7 @@ seq_reset (void) /* printk ("Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ { seq_sleep_flag.mode = WK_WAKEUP; - wake_up (&seq_sleeper); + module_wake_up (&seq_sleeper); }; } restore_flags (flags); @@ -1605,7 +1591,7 @@ sequencer_ioctl (int dev, struct fileinfo *file, if (mode == OPEN_READ) return 0; - while (qlen && !(current->signal & ~current->blocked)) + while (qlen && !current_got_fatal_signal ()) seq_sync (); if (qlen) return -EINTR; @@ -1921,7 +1907,7 @@ sequencer_ioctl (int dev, struct fileinfo *file, } int -sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) +sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait) { unsigned long flags; @@ -1935,7 +1921,7 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * w if (!iqlen) { midi_sleep_flag.mode = WK_SLEEP; - select_wait (&midi_sleeper, wait); + module_select_wait (&midi_sleeper, wait); restore_flags (flags); return 0; } @@ -1947,10 +1933,10 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * w case SEL_OUT: save_flags (flags); cli (); - if (qlen >= SEQ_MAX_QUEUE) + if ((SEQ_MAX_QUEUE - qlen) < output_treshold) { seq_sleep_flag.mode = WK_SLEEP; - select_wait (&seq_sleeper, wait); + module_select_wait (&seq_sleeper, wait); restore_flags (flags); return 0; } @@ -2076,5 +2062,3 @@ sequencer_init (long mem_start) } #endif - -#endif diff --git a/drivers/sound/sound_calls.h b/drivers/sound/sound_calls.h index b92692c70a89..381cf2aac035 100644 --- a/drivers/sound/sound_calls.h +++ b/drivers/sound/sound_calls.h @@ -5,9 +5,11 @@ int DMAbuf_open(int dev, int mode); int DMAbuf_release(int dev, int mode); int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock); +int DMAbuf_get_curr_buffer(int dev, int *buff_no, char **dma_buf, int *buff_ptr, int *buff_size); int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock); int DMAbuf_rmchars(int dev, int buff_no, int c); int DMAbuf_start_output(int dev, int buff_no, int l); +int DMAbuf_set_count(int dev, int buff_no, int l); int DMAbuf_ioctl(int dev, unsigned int cmd, ioctl_arg arg, int local); long DMAbuf_init(long mem_start); int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); @@ -16,7 +18,7 @@ void DMAbuf_close_dma (int dev); void DMAbuf_reset_dma (int dev); void DMAbuf_inputintr(int dev); void DMAbuf_outputintr(int dev, int underflow_flag); -int DMAbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * wait); +int DMAbuf_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait); void DMAbuf_start_devices(unsigned int devmask); /* @@ -32,7 +34,7 @@ int audio_ioctl (int dev, struct fileinfo *file, int audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig); long audio_init (long mem_start); -int audio_select(int dev, struct fileinfo *file, int sel_type, select_table * wait); +int audio_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait); /* * System calls for the /dev/sequencer @@ -52,7 +54,7 @@ unsigned long compute_finetune(unsigned long base_freq, int bend, int range); void seq_input_event(unsigned char *event, int len); void seq_copy_to_input (unsigned char *event, int len); -int sequencer_select(int dev, struct fileinfo *file, int sel_type, select_table * wait); +int sequencer_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait); /* * System calls for the /dev/midi @@ -68,7 +70,7 @@ int MIDIbuf_lseek (int dev, struct fileinfo *file, off_t offset, int orig); void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count); long MIDIbuf_init(long mem_start); -int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * wait); +int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait); /* * @@ -77,7 +79,7 @@ int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * /* From soundcard.c */ void soundcard_init(void); -void tenmicrosec(void); +void tenmicrosec(sound_os_info *osp); void request_sound_timer (int count); void sound_stop_timer(void); int snd_ioctl_return(int *addr, int value); @@ -85,6 +87,8 @@ int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int, struct pt_regs * void snd_release_irq(int vect); void sound_dma_malloc(int dev); void sound_dma_free(int dev); +void conf_printf(char *name, struct address_info *hw_config); +void conf_printf2(char *name, int base, int irq, int dma, int dma2); /* From sound_switch.c */ int sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); @@ -114,6 +118,7 @@ void sb16midiintr (int unit); long attach_sb16midi(long mem_start, struct address_info * hw_config); int probe_sb16midi(struct address_info *hw_config); void sb_midi_interrupt(int dummy); +void sbmidiintr(int irq, struct pt_regs * dummy); /* From sb_midi.c */ void sb_midi_init(int model); @@ -268,6 +273,7 @@ long attach_mad16_mpu (long mem_start, struct address_info *hw_config); int probe_mad16_mpu (struct address_info *hw_config); int mad16_sb_dsp_detect (struct address_info *hw_config); long mad16_sb_dsp_init (long mem_start, struct address_info *hw_config); +void mad16_sb_dsp_unload(struct address_info *hw_config); /* Unload routines from various source files*/ void unload_pss(struct address_info *hw_info); diff --git a/drivers/sound/sound_config.h b/drivers/sound/sound_config.h index a23a45664e33..2dd122ec6d3d 100644 --- a/drivers/sound/sound_config.h +++ b/drivers/sound/sound_config.h @@ -28,18 +28,8 @@ * */ -#undef CONFIGURE_SOUNDCARD -#undef DYNAMIC_BUFFER - -#include "local.h" - -#ifdef KERNEL_SOUNDCARD -#define CONFIGURE_SOUNDCARD -#define DYNAMIC_BUFFER -#undef LOADABLE_SOUNDCARD -#endif - #include "os.h" +#include "local.h" #include "soundvers.h" #if defined(ISC) || defined(SCO) || defined(SVR42) @@ -51,13 +41,10 @@ - #ifndef SND_DEFAULT_ENABLE #define SND_DEFAULT_ENABLE 1 #endif -#ifdef CONFIGURE_SOUNDCARD - #ifndef MAX_REALTIME_FACTOR #define MAX_REALTIME_FACTOR 4 #endif @@ -89,10 +76,16 @@ #define PAS_BASE 0x388 #endif -#ifdef JAZZ16 -#ifndef JAZZ_DMA16 -#define JAZZ_DMA16 5 +#if defined(SB16_DMA) && !defined(SB_DMA2) +# define SB_DMA2 SB16_DMA +#endif + +#if defined(SB16MIDI_BASE) && !defined(SB_MPU_BASE) +# define SB_MPU_BASE SB16MIDI_BASE #endif + +#ifndef SB_MPU_IRQ +# define SB_MPU_IRQ SBC_IRQ #endif /* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the @@ -198,5 +191,3 @@ struct channel_info { #define TIMER_ARMED 121234 #define TIMER_NOT_ARMED 1 - -#endif diff --git a/drivers/sound/sound_pnp.c b/drivers/sound/sound_pnp.c index 86ea26aec68f..0732235ac608 100644 --- a/drivers/sound/sound_pnp.c +++ b/drivers/sound/sound_pnp.c @@ -28,7 +28,7 @@ */ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PNP) +#if defined(CONFIG_PNP) #include diff --git a/drivers/sound/sound_switch.c b/drivers/sound/sound_switch.c index 4adb689b6039..5405a3cbabd2 100644 --- a/drivers/sound/sound_switch.c +++ b/drivers/sound/sound_switch.c @@ -29,17 +29,11 @@ #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD - struct sbc_device { int usecount; }; -static struct sbc_device sbc_devices[SND_NDEVS] = -{ - {0}}; - static int in_use = 0; /* @@ -210,7 +204,7 @@ init_status (void) return; } -#ifdef EXCLUDE_AUDIO +#ifndef CONFIG_AUDIO if (!put_status ("\nAudio devices: NOT ENABLED IN CONFIG\n")) return; #else @@ -235,7 +229,7 @@ init_status (void) } #endif -#ifdef EXCLUDE_SEQUENCER +#ifndef CONFIG_SEQUENCER if (!put_status ("\nSynth devices: NOT ENABLED IN CONFIG\n")) return; #else @@ -255,7 +249,7 @@ init_status (void) } #endif -#ifdef EXCLUDE_MIDI +#ifndef CONFIG_MIDI if (!put_status ("\nMidi devices: NOT ENABLED IN CONFIG\n")) return; #else @@ -339,7 +333,7 @@ sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) return read_status (buf, count); break; -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -347,14 +341,14 @@ sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) break; #endif -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_read (dev, file, buf, count); break; #endif -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI case SND_DEV_MIDIN: return MIDIbuf_read (dev, file, buf, count); #endif @@ -375,14 +369,14 @@ sound_write_sw (int dev, struct fileinfo *file, const snd_rw_buf * buf, int coun switch (dev & 0x0f) { -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_write (dev, file, buf, count); break; #endif -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -390,7 +384,7 @@ sound_write_sw (int dev, struct fileinfo *file, const snd_rw_buf * buf, int coun break; #endif -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI case SND_DEV_MIDIN: return MIDIbuf_write (dev, file, buf, count); #endif @@ -407,7 +401,7 @@ sound_open_sw (int dev, struct fileinfo *file) { int retval; - DEB (printk ("sound_open_sw(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount)); + DEB (printk ("sound_open_sw(dev=%d)\n", dev)); if ((dev >= SND_NDEVS) || (dev < 0)) { @@ -431,7 +425,7 @@ sound_open_sw (int dev, struct fileinfo *file) return 0; break; -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: if ((retval = sequencer_open (dev, file)) < 0) @@ -439,14 +433,14 @@ sound_open_sw (int dev, struct fileinfo *file) break; #endif -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI case SND_DEV_MIDIN: if ((retval = MIDIbuf_open (dev, file)) < 0) return retval; break; #endif -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -460,7 +454,6 @@ sound_open_sw (int dev, struct fileinfo *file) return -ENXIO; } - sbc_devices[dev].usecount++; in_use++; return 0; @@ -484,20 +477,20 @@ sound_release_sw (int dev, struct fileinfo *file) case SND_DEV_CTL: break; -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: sequencer_release (dev, file); break; #endif -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI case SND_DEV_MIDIN: MIDIbuf_release (dev, file); break; #endif -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -508,8 +501,6 @@ sound_release_sw (int dev, struct fileinfo *file) default: printk ("Sound error: Releasing unknown device 0x%02x\n", dev); } - - sbc_devices[dev].usecount--; in_use--; } @@ -527,7 +518,7 @@ sound_ioctl_sw (int dev, struct fileinfo *file, switch (dtype) { -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -559,14 +550,14 @@ sound_ioctl_sw (int dev, struct fileinfo *file, return mixer_devs[dev]->ioctl (dev, cmd, arg); break; -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_ioctl (dev, file, cmd, arg); break; #endif -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -574,7 +565,7 @@ sound_ioctl_sw (int dev, struct fileinfo *file, break; #endif -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI case SND_DEV_MIDIN: return MIDIbuf_ioctl (dev, file, cmd, arg); break; @@ -587,5 +578,3 @@ sound_ioctl_sw (int dev, struct fileinfo *file, return -EPERM; } - -#endif diff --git a/drivers/sound/sound_timer.c b/drivers/sound/sound_timer.c index fc387a9a3c52..b19e0e2e94b1 100644 --- a/drivers/sound/sound_timer.c +++ b/drivers/sound/sound_timer.c @@ -28,9 +28,7 @@ #define SEQUENCER_C #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD - -#if !defined(EXCLUDE_SEQUENCER) +#if defined(CONFIG_SEQUENCER) static volatile int initialized = 0, opened = 0, tmr_running = 0; static volatile time_t tmr_offs, tmr_ctr; @@ -352,4 +350,3 @@ sound_timer_init (struct sound_lowlev_timer *t, char *name) } #endif -#endif diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index 55cdebbd3892..e4e066780286 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -29,15 +29,12 @@ /* * Created modular version by Peter Trattler (peter@sbox.tu-graz.ac.at) */ -#include #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD - #include -#ifndef EXCLUDE_PNP +#ifdef CONFIG_PNP #include #endif @@ -73,37 +70,37 @@ snd_ioctl_return (int *addr, int value) } static int -sound_read (struct inode *inode, struct file *file, char *buf, int count) +sound_read (inode_handle * inode, file_handle * file, char *buf, int count) { int dev; - dev = inode->i_rdev; + dev = inode_get_rdev (inode); dev = MINOR (dev); - files[dev].flags = file->f_flags; + files[dev].flags = file_get_flags (file); return sound_read_sw (dev, &files[dev], buf, count); } static int -sound_write (struct inode *inode, struct file *file, const char *buf, int count) +sound_write (inode_handle * inode, file_handle * file, const char *buf, int count) { int dev; - dev = inode->i_rdev; + dev = inode_get_rdev (inode); dev = MINOR (dev); - files[dev].flags = file->f_flags; + files[dev].flags = file_get_flags (file); return sound_write_sw (dev, &files[dev], buf, count); } static int -sound_lseek (struct inode *inode, struct file *file, off_t offset, int orig) +sound_lseek (inode_handle * inode, file_handle * file, off_t offset, int orig) { return -EPERM; } static int -sound_open (struct inode *inode, struct file *file) +sound_open (inode_handle * inode, file_handle * file) { int dev, retval; struct fileinfo tmp_file; @@ -114,7 +111,7 @@ sound_open (struct inode *inode, struct file *file) return -EBUSY; } - dev = inode->i_rdev; + dev = inode_get_rdev (inode); dev = MINOR (dev); if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) @@ -124,7 +121,7 @@ sound_open (struct inode *inode, struct file *file) } tmp_file.mode = 0; - tmp_file.flags = file->f_flags; + tmp_file.flags = file_get_flags (file); if ((tmp_file.flags & O_ACCMODE) == O_RDWR) tmp_file.mode = OPEN_READWRITE; @@ -145,13 +142,13 @@ sound_open (struct inode *inode, struct file *file) } static void -sound_release (struct inode *inode, struct file *file) +sound_release (inode_handle * inode, file_handle * file) { int dev; - dev = inode->i_rdev; + dev = inode_get_rdev (inode); dev = MINOR (dev); - files[dev].flags = file->f_flags; + files[dev].flags = file_get_flags (file); sound_release_sw (dev, &files[dev]); #ifdef MODULE @@ -160,31 +157,31 @@ sound_release (struct inode *inode, struct file *file) } static int -sound_ioctl (struct inode *inode, struct file *file, +sound_ioctl (inode_handle * inode, file_handle * file, unsigned int cmd, unsigned long arg) { int dev, err; - dev = inode->i_rdev; + dev = inode_get_rdev (inode); dev = MINOR (dev); - files[dev].flags = file->f_flags; + files[dev].flags = file_get_flags (file); - if (cmd & IOC_INOUT) + if (_IOC_DIR (cmd) != _IOC_NONE) { /* * Have to validate the address given by the process. */ int len; - len = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; + len = _IOC_SIZE (cmd); - if (cmd & IOC_IN) + if (_IOC_DIR (cmd) == _IOC_WRITE) { if ((err = verify_area (VERIFY_READ, (void *) arg, len)) < 0) return err; } - if (cmd & IOC_OUT) + if (_IOC_DIR (cmd) == _IOC_READ) { if ((err = verify_area (VERIFY_WRITE, (void *) arg, len)) < 0) return err; @@ -198,32 +195,32 @@ sound_ioctl (struct inode *inode, struct file *file, } static int -sound_select (struct inode *inode, struct file *file, int sel_type, select_table * wait) +sound_select (inode_handle * inode, file_handle * file, int sel_type, select_table_handle * wait) { int dev; - dev = inode->i_rdev; + dev = inode_get_rdev (inode); dev = MINOR (dev); - files[dev].flags = file->f_flags; + files[dev].flags = file_get_flags (file); DEB (printk ("sound_select(dev=%d, type=0x%x)\n", dev, sel_type)); switch (dev & 0x0f) { -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_select (dev, &files[dev], sel_type, wait); break; #endif -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI case SND_DEV_MIDIN: return MIDIbuf_select (dev, &files[dev], sel_type, wait); break; #endif -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -238,8 +235,98 @@ sound_select (struct inode *inode, struct file *file, int sel_type, select_table return 0; } +#ifdef ALLOW_BUFFER_MAPPING +static int +sound_mmap (inode_handle * inode, file_handle * file, vm_area_handle * vma) +{ + int dev, dev_class; + unsigned long size, i; + struct dma_buffparms *dmap = NULL; + + dev = inode_get_rdev (inode); + dev = MINOR (dev); + files[dev].flags = file_get_flags (file); + + dev_class = dev & 0x0f; + dev >>= 4; + + if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO) + { + printk ("Sound: mmap() not supported for other than audio devices\n"); + return -EINVAL; + } + + if ((vma_get_flags (vma) & (VM_READ | VM_WRITE)) == (VM_READ | VM_WRITE)) + { + printk ("Sound: Cannot do read/write mmap()\n"); + return -EINVAL; + } + + if (vma_get_flags (vma) & VM_READ) + { + dmap = audio_devs[dev]->dmap_in; + } + else if (vma_get_flags (vma) & VM_WRITE) + { + dmap = audio_devs[dev]->dmap_out; + } + else + { + printk ("Sound: Undefined mmap() access\n"); + return -EINVAL; + } + + if (dmap == NULL) + { + printk ("Sound: mmap() error. dmap == NULL\n"); + return -EIO; + } + + if (dmap->raw_buf == NULL) + { + printk ("Sound: mmap() called when raw_buf == NULL\n"); + return -EIO; + } + + if (dmap->mapping_flags) + { + printk ("Sound: mmap() called twice for the same DMA buffer\n"); + return -EIO; + } + + if (vma_get_offset (vma) != 0) + { + printk ("Sound: mmap() offset must be 0.\n"); + return -EINVAL; + } + + size = vma_get_end (vma) - vma_get_start (vma); -static struct file_operations sound_fops = + if (size != dmap->bytes_in_use) + { + printk ("Sound: mmap() size = %ld. Should be %d\n", + size, dmap->bytes_in_use); + } + + + if (remap_page_range (vma_get_start (vma), dmap->raw_buf_phys, + vma_get_end (vma) - vma_get_start (vma), + vma_get_page_prot (vma))) + return -EAGAIN; + + vma_set_inode (vma, inode); + inode_inc_count (inode); + + dmap->mapping_flags |= DMA_MAP_MAPPED; + + memset (dmap->raw_buf, + dmap->neutral_byte, + dmap->bytes_in_use); + return 0; +} +#endif + +static struct file_operation_handle sound_fops = { sound_lseek, sound_read, @@ -247,7 +334,11 @@ static struct file_operations sound_fops = NULL, /* sound_readdir */ sound_select, sound_ioctl, +#ifdef ALLOW_BUFFER_MAPPING + sound_mmap, +#else NULL, +#endif sound_open, sound_release }; @@ -256,7 +347,7 @@ void soundcard_init (void) { #ifndef MODULE - register_chrdev (SOUND_MAJOR, "sound", &sound_fops); + module_register_chrdev (SOUND_MAJOR, "sound", &sound_fops); chrdev_registered = 1; #endif @@ -265,14 +356,14 @@ soundcard_init (void) sndtable_init (0); /* Initialize call tables and * detect cards */ -#ifndef EXCLUDE_PNP +#ifdef CONFIG_PNP sound_pnp_init (); #endif if (sndtable_get_cardcount () == 0) return; /* No cards detected */ -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO if (num_audiodevs) /* Audio devices present */ { DMAbuf_init (0); @@ -280,12 +371,12 @@ soundcard_init (void) } #endif -#ifndef EXCLUDE_MIDI +#ifdef CONFIG_MIDI if (num_midis) MIDIbuf_init (0); #endif -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER if (num_midis + num_synths) sequencer_init (0); #endif @@ -309,6 +400,8 @@ free_all_irqs (void) irqs = 0; } +char kernel_version[] = UTS_RELEASE; + #endif static int debugmem = 0; /* switched off by default */ @@ -323,7 +416,7 @@ init_module (void) int ints[21]; int i; - if (0 < 0) + if (connect_wrapper (WRAPPER_VERSION) < 0) { printk ("Sound: Incompatible kernel (wrapper) version\n"); return -EINVAL; @@ -340,7 +433,7 @@ init_module (void) if (i) sound_setup ("sound=", ints); - err = register_chrdev (SOUND_MAJOR, "sound", &sound_fops); + err = module_register_chrdev (SOUND_MAJOR, "sound", &sound_fops); if (err) { printk ("sound: driver already loaded/included in kernel\n"); @@ -369,9 +462,9 @@ cleanup_module (void) int i; if (chrdev_registered) - unregister_chrdev (SOUND_MAJOR, "sound"); + module_unregister_chrdev (SOUND_MAJOR, "sound"); -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER sound_stop_timer (); #endif sound_unload_drivers (); @@ -388,7 +481,7 @@ cleanup_module (void) sound_free_dma (i); } -#ifndef EXCLUDE_PNP +#ifdef CONFIG_PNP sound_pnp_disconnect (); #endif @@ -397,7 +490,7 @@ cleanup_module (void) #endif void -tenmicrosec (void) +tenmicrosec (sound_os_info * osp) { int i; @@ -466,7 +559,7 @@ sound_free_dma (int chn) { if (dma_alloc_map[chn] != DMA_MAP_FREE) { - printk ("sound_free_dma: Bad access to DMA channel %d\n", chn); + /* printk ("sound_free_dma: Bad access to DMA channel %d\n", chn); */ return; } free_dma (chn); @@ -491,7 +584,7 @@ sound_close_dma (int chn) restore_flags (flags); } -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER static struct timer_list seq_timer = @@ -507,6 +600,7 @@ request_sound_timer (int count) else count += seq_time; + ; { seq_timer.expires = ((count - jiffies)) + jiffies; @@ -521,7 +615,7 @@ sound_stop_timer (void) } #endif -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO #ifdef KMALLOC_DMA_BROKEN fatal_error__This_version_is_not_compatible_with_this_kernel; @@ -535,6 +629,10 @@ sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan) char *start_addr, *end_addr; int i, dma_pagesize; +#ifdef ALLOW_BUFFER_MAPPING + dmap->mapping_flags &= ~DMA_MAP_MAPPED; +#endif + if (dmap->raw_buf != NULL) return 0; /* Already done */ @@ -611,7 +709,7 @@ sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan) for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++) { - mem_map[i].reserved = 1; + mem_map_reserve (i); } return 0; @@ -622,6 +720,12 @@ sound_free_dmap (int dev, struct dma_buffparms *dmap) { if (dmap->raw_buf == NULL) return; + +#ifdef ALLOW_BUFFER_MAPPING + if (dmap->mapping_flags & DMA_MAP_MAPPED) + return; /* Don't free mmapped buffer. Will use it next time */ +#endif + { int sz, size, i; unsigned long start_addr, end_addr; @@ -635,7 +739,7 @@ sound_free_dmap (int dev, struct dma_buffparms *dmap) for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++) { - mem_map[i].reserved = 0; + mem_map_unreserve (i); } free_pages ((unsigned long) dmap->raw_buf, sz); @@ -651,13 +755,45 @@ soud_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc * info) return -EINVAL; } -#else - void -soundcard_init (void) /* Dummy version */ +conf_printf (char *name, struct address_info *hw_config) { + if (!trace_init) + return; + + printk ("<%s> at 0x%03x", name, hw_config->io_base); + + if (hw_config->irq) + printk (" irq %d", hw_config->irq); + + if (hw_config->dma != -1 || hw_config->dma2 != -1) + { + printk (" dma %d", hw_config->dma); + if (hw_config->dma2 != -1) + printk (",%d", hw_config->dma2); + } + + printk ("\n"); } -#endif +void +conf_printf2 (char *name, int base, int irq, int dma, int dma2) +{ + if (!trace_init) + return; + + printk ("<%s> at 0x%03x", name, base); + + if (irq) + printk (" irq %d", irq); + if (dma != -1 || dma2 != -1) + { + printk (" dma %d", dma); + if (dma2 != -1) + printk (",%d", dma2); + } + + printk ("\n"); +} #endif diff --git a/drivers/sound/soundvers.h b/drivers/sound/soundvers.h index 241bef047466..95fca0fee8dd 100644 --- a/drivers/sound/soundvers.h +++ b/drivers/sound/soundvers.h @@ -1,2 +1,2 @@ -#define SOUND_VERSION_STRING "3.5-alpha5-951002" +#define SOUND_VERSION_STRING "3.5-alpha8-960109" #define SOUND_INTERNAL_VERSION 0x030505 diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c index 37dadb931aca..6f9fe07ccd86 100644 --- a/drivers/sound/sscape.c +++ b/drivers/sound/sscape.c @@ -29,7 +29,7 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SSCAPE) +#if defined(CONFIG_SSCAPE) #include "coproc.h" @@ -102,7 +102,7 @@ static struct sscape_info dev_info = {0}; static struct sscape_info *devc = &dev_info; -static struct wait_queue *sscape_sleeper = NULL; +static wait_handle *sscape_sleeper = NULL; static volatile struct snd_wait sscape_sleep_flag = {0}; @@ -309,7 +309,7 @@ sscapeintr (int irq, struct pt_regs *dummy) { { sscape_sleep_flag.mode = WK_WAKEUP; - wake_up (&sscape_sleeper); + module_wake_up (&sscape_sleeper); }; } @@ -318,7 +318,7 @@ sscapeintr (int irq, struct pt_regs *dummy) printk ("SSCAPE: Host interrupt, data=%02x\n", host_read (devc)); } -#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) if (bits & 0x01) { mpuintr (irq, NULL); @@ -338,35 +338,6 @@ sscapeintr (int irq, struct pt_regs *dummy) } -static void -sscape_enable_intr (struct sscape_info *devc, unsigned intr_bits) -{ - unsigned char temp, orig; - - temp = orig = sscape_read (devc, GA_INTENA_REG); - temp |= intr_bits; - temp |= 0x80; /* Master IRQ enable */ - - if (temp == orig) - return; /* No change */ - - sscape_write (devc, GA_INTENA_REG, temp); -} - -static void -sscape_disable_intr (struct sscape_info *devc, unsigned intr_bits) -{ - unsigned char temp, orig; - - temp = orig = sscape_read (devc, GA_INTENA_REG); - temp &= ~intr_bits; - if ((temp & ~0x80) == 0x00) - temp = 0x00; /* Master IRQ disable */ - if (temp == orig) - return; /* No change */ - - sscape_write (devc, GA_INTENA_REG, temp); -} static void do_dma (struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode) @@ -431,6 +402,7 @@ sscape_coproc_open (void *dev_info, int sub_device) return -EIO; } + sscape_sleep_flag.mode = WK_NONE; return 0; } @@ -445,7 +417,7 @@ sscape_coproc_close (void *dev_info, int sub_device) if (devc->dma_allocated) { sscape_write (devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ -#ifndef EXCLUDE_NATIVE_PCM +#ifdef CONFIG_NATIVE_PCM #endif devc->dma_allocated = 0; } @@ -478,7 +450,7 @@ sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, cli (); if (devc->dma_allocated == 0) { -#ifndef EXCLUDE_NATIVE_PCM +#ifdef CONFIG_NATIVE_PCM #endif devc->dma_allocated = 1; @@ -523,11 +495,11 @@ sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, unsigned long tl; if (1) - current->timeout = tl = jiffies + (1); + current_set_timeout (tl = jiffies + (1)); else tl = 0xffffffff; sscape_sleep_flag.mode = WK_SLEEP; - interruptible_sleep_on (&sscape_sleeper); + module_interruptible_sleep_on (&sscape_sleeper); if (!(sscape_sleep_flag.mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -571,11 +543,11 @@ sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, unsigned long tl; if (1) - current->timeout = tl = jiffies + (1); + current_set_timeout (tl = jiffies + (1)); else tl = 0xffffffff; sscape_sleep_flag.mode = WK_SLEEP; - interruptible_sleep_on (&sscape_sleeper); + module_interruptible_sleep_on (&sscape_sleeper); if (!(sscape_sleep_flag.mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -604,11 +576,11 @@ sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, unsigned long tl; if (1) - current->timeout = tl = jiffies + (1); + current_set_timeout (tl = jiffies + (1)); else tl = 0xffffffff; sscape_sleep_flag.mode = WK_SLEEP; - interruptible_sleep_on (&sscape_sleeper); + module_interruptible_sleep_on (&sscape_sleeper); if (!(sscape_sleep_flag.mode & WK_WAKEUP)) { if (jiffies >= tl) @@ -917,10 +889,10 @@ attach_sscape (long mem_start, struct address_info *hw_config) if (old_hardware) { valid_interrupts = valid_interrupts_old; - printk (" "); + conf_printf ("Ensoniq Soundscape (old)", hw_config); } else - printk (" "); + conf_printf ("Ensoniq Soundscape", hw_config); for (i = 0; i < sizeof (valid_interrupts); i++) if (hw_config->irq == valid_interrupts[i]) @@ -964,7 +936,7 @@ attach_sscape (long mem_start, struct address_info *hw_config) case 9: /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */ sscape_write (devc, i, - (sscape_read (devc, i) & 0xf0) | 0x00); + (sscape_read (devc, i) & 0xf0) | 0x08); break; default: @@ -986,7 +958,7 @@ attach_sscape (long mem_start, struct address_info *hw_config) } #endif -#if !defined(EXCLUDE_MIDI) && !defined(EXCLUDE_MPU_EMU) +#if defined(CONFIG_MIDI) && defined(CONFIG_MPU_EMU) if (probe_mpu401 (hw_config)) hw_config->always_detect = 1; { @@ -1003,7 +975,7 @@ attach_sscape (long mem_start, struct address_info *hw_config) #ifndef EXCLUDE_NATIVE_PCM /* Not supported yet */ -#ifndef EXCLUDE_AUDIO +#ifdef CONFIG_AUDIO if (num_audiodevs < MAX_AUDIO_DEV) { audio_devs[my_dev = num_audiodevs++] = &sscape_audio_operations; @@ -1088,7 +1060,6 @@ probe_sscape (struct address_info *hw_config) if (old_hardware) /* Check that it's really an old Spea/Reveal card. */ { - int status = 0; unsigned char tmp; int cc; @@ -1153,7 +1124,7 @@ attach_ss_ms_sound (long mem_start, struct address_info *hw_config) int i, irq_bits = 0xff; -#ifdef EXCLUDE_NATIVE_PCM +#ifndef CONFIG_NATIVE_PCM int prev_devs = num_audiodevs; #endif @@ -1192,7 +1163,7 @@ attach_ss_ms_sound (long mem_start, struct address_info *hw_config) 0, devc->osp); -#ifdef EXCLUDE_NATIVE_PCM +#ifndef CONFIG_NATIVE_PCM if (num_audiodevs == (prev_devs + 1)) /* The AD1848 driver installed itself */ audio_devs[prev_devs]->coproc = &sscape_coproc_operations; #endif diff --git a/drivers/sound/sys_timer.c b/drivers/sound/sys_timer.c index e251ee25cf82..15e0232e3db2 100644 --- a/drivers/sound/sys_timer.c +++ b/drivers/sound/sys_timer.c @@ -31,9 +31,7 @@ #define SEQUENCER_C #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD - -#ifndef EXCLUDE_SEQUENCER +#ifdef CONFIG_SEQUENCER static volatile int opened = 0, tmr_running = 0; static volatile time_t tmr_offs, tmr_ctr; @@ -113,6 +111,7 @@ def_tmr_open (int dev, int mode) curr_timebase = HZ; opened = 1; + ; { def_tmr.expires = (1) + jiffies; @@ -307,4 +306,3 @@ struct sound_timer_operations default_sound_timer = }; #endif -#endif diff --git a/drivers/sound/trix.c b/drivers/sound/trix.c index 3c12d0e1df0d..53a5aae06e8c 100644 --- a/drivers/sound/trix.c +++ b/drivers/sound/trix.c @@ -30,12 +30,13 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_TRIX) +#if defined(CONFIG_TRIX) #ifdef INCLUDE_TRIX_BOOT #include "trix_boot.h" #endif + static int kilroy_was_here = 0; /* Don't detect twice */ static int sb_initialized = 0; static int mpu_initialized = 0; @@ -80,6 +81,7 @@ download_boot (int base) outb (0x00, base + 6); /* Reset */ outb (0x50, 0x390); /* ?????? */ #endif + } static int @@ -324,20 +326,20 @@ probe_trix_sb (struct address_info *hw_config) long attach_trix_sb (long mem_start, struct address_info *hw_config) { -#ifndef EXCLUDE_SB +#ifdef CONFIG_SB extern int sb_no_recording; sb_dsp_disable_midi (); sb_no_recording = 1; #endif - printk (" "); + conf_printf ("AudioTriX (SB)", hw_config); return mem_start; } long attach_trix_mpu (long mem_start, struct address_info *hw_config) { -#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) return attach_mpu401 (mem_start, hw_config); #else return mem_start; @@ -347,7 +349,7 @@ attach_trix_mpu (long mem_start, struct address_info *hw_config) int probe_trix_mpu (struct address_info *hw_config) { -#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) unsigned char conf; static char irq_bits[] = {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5}; @@ -439,7 +441,7 @@ unload_trix_wss (struct address_info *hw_config) void unload_trix_mpu (struct address_info *hw_config) { -#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) unload_mpu401 (hw_config); #endif } diff --git a/drivers/sound/uart6850.c b/drivers/sound/uart6850.c index f4687ac4b293..5b148115eaa1 100644 --- a/drivers/sound/uart6850.c +++ b/drivers/sound/uart6850.c @@ -30,9 +30,7 @@ #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD - -#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI) +#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) #define DATAPORT (uart6850_base) /* * * * Midi6850 Data I/O Port on IBM @@ -117,9 +115,7 @@ poll_uart6850 (unsigned long dummy) unsigned long flags; if (!(uart6850_opened & OPEN_READ)) - return; /* - * No longer required - */ + return; /* Device has been closed */ save_flags (flags); cli (); @@ -150,6 +146,7 @@ uart6850_open (int dev, int mode, return -EBUSY; } + ; uart6850_cmd (UART_RESET); uart6850_input_loop (); @@ -298,7 +295,7 @@ attach_uart6850 (long mem_start, struct address_info *hw_config) restore_flags (flags); - printk (" <6850 Midi Interface>"); + conf_printf ("6850 Midi Interface", hw_config); std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &uart6850_operations; @@ -340,5 +337,3 @@ unload_uart6850 (struct address_info *hw_config) } #endif - -#endif diff --git a/drivers/sound/ulaw.h b/drivers/sound/ulaw.h index 2c783ba67595..be9f92d9984a 100644 --- a/drivers/sound/ulaw.h +++ b/drivers/sound/ulaw.h @@ -1,74 +1,69 @@ - -/* - * This is a new ulaw.h made by Andy Fingerhut - */ - static unsigned char ulaw_dsp[] = { - 2, 6, 10, 14, 18, 22, 26, 30, - 34, 38, 42, 46, 50, 54, 58, 62, - 65, 67, 69, 71, 73, 75, 77, 79, - 81, 83, 85, 87, 89, 91, 93, 95, - 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, - 112, 113, 113, 114, 114, 115, 115, 116, - 116, 117, 117, 118, 118, 119, 119, 120, - 120, 120, 121, 121, 121, 121, 122, 122, - 122, 122, 123, 123, 123, 123, 124, 124, - 124, 124, 124, 124, 125, 125, 125, 125, - 125, 125, 125, 125, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 128, - 253, 249, 245, 241, 237, 233, 229, 225, - 221, 217, 213, 209, 205, 201, 197, 193, - 190, 188, 186, 184, 182, 180, 178, 176, - 174, 172, 170, 168, 166, 164, 162, 160, - 158, 157, 156, 155, 154, 153, 152, 151, - 150, 149, 148, 147, 146, 145, 144, 143, - 143, 142, 142, 141, 141, 140, 140, 139, - 139, 138, 138, 137, 137, 136, 136, 135, - 135, 135, 134, 134, 134, 134, 133, 133, - 133, 133, 132, 132, 132, 132, 131, 131, - 131, 131, 131, 131, 130, 130, 130, 130, - 130, 130, 130, 130, 129, 129, 129, 129, - 129, 129, 129, 129, 129, 129, 129, 129, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128 + 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, 2, + 5, 9, 13, 17, 21, 25, 29, 33, + 37, 41, 45, 49, 53, 57, 61, 65, + 68, 70, 72, 74, 76, 78, 80, 82, + 84, 86, 88, 90, 92, 94, 96, 98, + 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, + 115, 116, 116, 117, 117, 118, 118, 119, + 119, 120, 120, 121, 121, 122, 122, 123, + 123, 123, 124, 124, 124, 124, 125, 125, + 125, 125, 126, 126, 126, 126, 127, 127, + 127, 127, 127, 127, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 252, 248, 244, 240, 236, 232, 228, 224, + 220, 216, 212, 208, 204, 200, 196, 192, + 189, 187, 185, 183, 181, 179, 177, 175, + 173, 171, 169, 167, 165, 163, 161, 159, + 157, 156, 155, 154, 153, 152, 151, 150, + 149, 148, 147, 146, 145, 144, 143, 142, + 142, 141, 141, 140, 140, 139, 139, 138, + 138, 137, 137, 136, 136, 135, 135, 134, + 134, 134, 133, 133, 133, 133, 132, 132, + 132, 132, 131, 131, 131, 131, 130, 130, + 130, 130, 130, 130, 129, 129, 129, 129, + 129, 129, 129, 129, 128, 128, 128, 128, }; static unsigned char dsp_ulaw[] = { - 0, 0, 0, 0, 0, 1, 1, 1, - 1, 2, 2, 2, 2, 3, 3, 3, - 3, 4, 4, 4, 4, 5, 5, 5, - 5, 6, 6, 6, 6, 7, 7, 7, - 7, 8, 8, 8, 8, 9, 9, 9, - 9, 10, 10, 10, 10, 11, 11, 11, - 11, 12, 12, 12, 12, 13, 13, 13, - 13, 14, 14, 14, 14, 15, 15, 15, - 15, 16, 16, 17, 17, 18, 18, 19, - 19, 20, 20, 21, 21, 22, 22, 23, - 23, 24, 24, 25, 25, 26, 26, 27, - 27, 28, 28, 29, 29, 30, 30, 31, - 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 50, 52, 54, 56, 58, 60, - 62, 65, 69, 73, 77, 83, 91, 103, - 255, 231, 219, 211, 205, 201, 197, 193, - 190, 188, 186, 184, 182, 180, 178, 176, - 175, 174, 173, 172, 171, 170, 169, 168, - 167, 166, 165, 164, 163, 162, 161, 160, - 159, 159, 158, 158, 157, 157, 156, 156, - 155, 155, 154, 154, 153, 153, 152, 152, - 151, 151, 150, 150, 149, 149, 148, 148, - 147, 147, 146, 146, 145, 145, 144, 144, - 143, 143, 143, 143, 142, 142, 142, 142, - 141, 141, 141, 141, 140, 140, 140, 140, - 139, 139, 139, 139, 138, 138, 138, 138, - 137, 137, 137, 137, 136, 136, 136, 136, - 135, 135, 135, 135, 134, 134, 134, 134, - 133, 133, 133, 133, 132, 132, 132, 132, - 131, 131, 131, 131, 130, 130, 130, 130, - 129, 129, 129, 129, 128, 128, 128, 128 + 31, 31, 31, 32, 32, 32, 32, 33, + 33, 33, 33, 34, 34, 34, 34, 35, + 35, 35, 35, 36, 36, 36, 36, 37, + 37, 37, 37, 38, 38, 38, 38, 39, + 39, 39, 39, 40, 40, 40, 40, 41, + 41, 41, 41, 42, 42, 42, 42, 43, + 43, 43, 43, 44, 44, 44, 44, 45, + 45, 45, 45, 46, 46, 46, 46, 47, + 47, 47, 47, 48, 48, 49, 49, 50, + 50, 51, 51, 52, 52, 53, 53, 54, + 54, 55, 55, 56, 56, 57, 57, 58, + 58, 59, 59, 60, 60, 61, 61, 62, + 62, 63, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 81, 83, 85, 87, 89, + 91, 93, 95, 99, 103, 107, 111, 119, + 255, 247, 239, 235, 231, 227, 223, 221, + 219, 217, 215, 213, 211, 209, 207, 206, + 205, 204, 203, 202, 201, 200, 199, 198, + 197, 196, 195, 194, 193, 192, 191, 191, + 190, 190, 189, 189, 188, 188, 187, 187, + 186, 186, 185, 185, 184, 184, 183, 183, + 182, 182, 181, 181, 180, 180, 179, 179, + 178, 178, 177, 177, 176, 176, 175, 175, + 175, 175, 174, 174, 174, 174, 173, 173, + 173, 173, 172, 172, 172, 172, 171, 171, + 171, 171, 170, 170, 170, 170, 169, 169, + 169, 169, 168, 168, 168, 168, 167, 167, + 167, 167, 166, 166, 166, 166, 165, 165, + 165, 165, 164, 164, 164, 164, 163, 163, + 163, 163, 162, 162, 162, 162, 161, 161, + 161, 161, 160, 160, 160, 160, 159, 159, }; diff --git a/fs/Config.in b/fs/Config.in index 6b9e063fbbdb..80a253c775bd 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -27,3 +27,4 @@ fi tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS +endmenu diff --git a/fs/buffer.c b/fs/buffer.c index c3f4faf545f5..8f3261ac62a4 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -56,6 +56,7 @@ static struct buffer_head * lru_list[NR_LIST] = {NULL, }; static struct buffer_head * next_to_age[NR_LIST] = {NULL, }; static struct buffer_head * free_list[NR_SIZES] = {NULL, }; static struct buffer_head * unused_list = NULL; +struct buffer_head * reuse_list = NULL; static struct wait_queue * buffer_wait = NULL; int nr_buffers = 0; @@ -459,7 +460,7 @@ static inline struct buffer_head * find_buffer(kdev_t dev, int block, int size) struct buffer_head * tmp; for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next) - if (tmp->b_dev == dev && tmp->b_blocknr == block) + if (tmp->b_blocknr == block && tmp->b_dev == dev) if (tmp->b_size == size) return tmp; else { @@ -980,10 +981,38 @@ static void get_more_buffer_heads(void) } } +/* + * We can't put completed temporary IO buffer_heads directly onto the + * unused_list when they become unlocked, since the device driver + * end_request routines still expect access to the buffer_head's + * fields after the final unlock. So, the device driver puts them on + * the reuse_list instead once IO completes, and we recover these to + * the unused_list here. + * + * The reuse_list receives buffers from interrupt routines, so we need + * to be IRQ-safe here. + */ +static inline void recover_reusable_buffer_heads(void) +{ + struct buffer_head *bh; + unsigned long flags; + + save_flags(flags); + cli(); + while (reuse_list) { + bh = reuse_list; + reuse_list = bh->b_next_free; + restore_flags(flags); + put_unused_buffer_head(bh); + cli(); + } +} + static struct buffer_head * get_unused_buffer_head(void) { struct buffer_head * bh; + recover_reusable_buffer_heads(); get_more_buffer_heads(); if (!unused_list) return NULL; @@ -1033,22 +1062,14 @@ no_grow: return NULL; } -static void read_buffers(struct buffer_head * bh[], int nrbuf) -{ - ll_rw_block(READ, nrbuf, bh); - bh += nrbuf; - do { - nrbuf--; - bh--; - wait_on_buffer(*bh); - } while (nrbuf > 0); -} - static int bread_page(unsigned long address, kdev_t dev, int b[], int size) { - struct buffer_head *bh, *next, *arr[MAX_BUF_PER_PAGE]; + struct buffer_head *bh, *prev, *next, *arr[MAX_BUF_PER_PAGE]; int block, nr; + struct page *page; + page = mem_map + MAP_NR(address); + page->uptodate = 0; bh = create_buffers(address, size); if (!bh) return -ENOMEM; @@ -1057,6 +1078,17 @@ static int bread_page(unsigned long address, kdev_t dev, int b[], int size) do { struct buffer_head * tmp; block = *(b++); + + set_bit(BH_FreeOnIO, &next->b_state); + next->b_list = BUF_CLEAN; + next->b_dev = dev; + next->b_blocknr = block; + next->b_count = 1; + next->b_flushtime = 0; + clear_bit(BH_Dirty, &next->b_state); + clear_bit(BH_Req, &next->b_state); + set_bit(BH_Uptodate, &next->b_state); + if (!block) { memset(next->b_data, 0, size); continue; @@ -1071,32 +1103,47 @@ static int bread_page(unsigned long address, kdev_t dev, int b[], int size) brelse(tmp); continue; } - arr[nr++] = next; - next->b_dev = dev; - next->b_blocknr = block; - next->b_count = 1; - next->b_flushtime = 0; - clear_bit(BH_Dirty, &next->b_state); clear_bit(BH_Uptodate, &next->b_state); - clear_bit(BH_Req, &next->b_state); - next->b_list = BUF_CLEAN; - } while ((next = next->b_this_page) != NULL); - + arr[nr++] = next; + } while (prev = next, (next = next->b_this_page) != NULL); + prev->b_this_page = bh; + if (nr) - read_buffers(arr,nr); - ++current->maj_flt; - - while ((next = bh) != NULL) { - bh = bh->b_this_page; - put_unused_buffer_head(next); + ll_rw_block(READ, nr, arr); + else { + page->locked = 0; + page->uptodate = 1; + wake_up(&page->wait); } + ++current->maj_flt; return 0; } +void mark_buffer_uptodate(struct buffer_head * bh, int on) +{ + if (on) { + struct buffer_head *tmp = bh; + int page_uptodate = 1; + set_bit(BH_Uptodate, &bh->b_state); + do { + if (!test_bit(BH_Uptodate, &tmp->b_state)) { + page_uptodate = 0; + break; + } + tmp=tmp->b_this_page; + } while (tmp && tmp != bh); + if (page_uptodate) + mem_map[MAP_NR(bh->b_data)].uptodate = 1; + } else + clear_bit(BH_Uptodate, &bh->b_state); +} + /* - * Generic "readpage" function for block devices that have the - * normal bmap functionality. This is most of the block device - * filesystems. + * Generic "readpage" function for block devices that have the normal + * bmap functionality. This is most of the block device filesystems. + * Reads the page asynchronously --- the unlock_buffer() and + * mark_buffer_uptodate() functions propogate buffer state into the + * page struct once IO has completed. */ int generic_readpage(struct inode * inode, struct page * page) { @@ -1104,6 +1151,9 @@ int generic_readpage(struct inode * inode, struct page * page) int *p, nr[PAGE_SIZE/512]; int i; + wait_on_page(page); + page->locked = 1; + i = PAGE_SIZE >> inode->i_sb->s_blocksize_bits; block = page->offset >> inode->i_sb->s_blocksize_bits; p = nr; @@ -1114,20 +1164,11 @@ int generic_readpage(struct inode * inode, struct page * page) p++; } while (i > 0); - /* - * We should make this asynchronous, but this is good enough for now.. - */ - /* IO start */ page->count++; address = page_address(page); bread_page(address, inode->i_dev, nr, inode->i_sb->s_blocksize); - - /* IO ready (this part should be in the "page ready callback" function) */ - page->uptodate = 1; - wake_up(&page->wait); free_page(address); - return 0; } diff --git a/fs/ext/inode.c b/fs/ext/inode.c index 52ba655a27b3..f25293449b2a 100644 --- a/fs/ext/inode.c +++ b/fs/ext/inode.c @@ -451,17 +451,26 @@ int ext_sync_inode (struct inode *inode) return err; } -#ifdef MODULE static struct file_system_type ext_fs_type = { ext_read_super, "ext", 1, NULL }; -int init_module(void) +int init_ext_fs(void) { return register_filesystem(&ext_fs_type); } +#ifdef MODULE +int init_module(void) +{ + int status; + + if ((status = init_ext_fs()) == 0) + register_symtab(0); + return status; +} + void cleanup_module(void) { unregister_filesystem(&ext_fs_type); diff --git a/fs/ext2/CHANGES b/fs/ext2/CHANGES index 5cdd72f816a8..aa5aaf0e5911 100644 --- a/fs/ext2/CHANGES +++ b/fs/ext2/CHANGES @@ -1,5 +1,7 @@ Changes from version 0.5a to version 0.5b ========================================= + - Now that we have sysctl(), the immutable flag cannot be changed when + the system is running at security level > 0. - Some cleanups in the code. - More consistency checks on directories. - The ext2.diff patch from Tom May has been diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index e0de8de117ec..4e3f56362bc2 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -33,12 +33,13 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, case EXT2_IOC_SETFLAGS: flags = get_fs_long ((long *) arg); /* - * Only the super-user can change the IMMUTABLE flag + * The IMMUTABLE flag can only be changed by the super user + * when the security level is zero. */ if ((flags & EXT2_IMMUTABLE_FL) ^ (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL)) { /* This test looks nicer. Thanks to Pauline Middelink */ - if (!fsuser()) + if (!fsuser() || securelevel > 0) return -EPERM; } else if ((current->fsuid != inode->i_uid) && !fsuser()) diff --git a/fs/ext2/super.c b/fs/ext2/super.c index c069e49bff19..f05a03baab74 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -685,17 +685,25 @@ int ext2_remount (struct super_block * sb, int * flags, char * data) return 0; } -#ifdef MODULE - static struct file_system_type ext2_fs_type = { ext2_read_super, "ext2", 1, NULL }; -int init_module(void) +int init_ext2_fs(void) { return register_filesystem(&ext2_fs_type); } +#ifdef MODULE +int init_module(void) +{ + int status; + + if ((status = init_ext2_fs()) == 0) + register_symtab(0); + return status; +} + void cleanup_module(void) { unregister_filesystem(&ext2_fs_type); diff --git a/fs/filesystems.c b/fs/filesystems.c index 7606af007767..660eef8edffd 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -44,74 +44,55 @@ asmlinkage int sys_setup(void) device_setup(); #ifdef CONFIG_EXT_FS - register_filesystem(&(struct file_system_type) - {ext_read_super, "ext", 1, NULL}); + init_ext_fs(); #endif #ifdef CONFIG_EXT2_FS - register_filesystem(&(struct file_system_type) - {ext2_read_super, "ext2", 1, NULL}); + init_ext2_fs(); #endif #ifdef CONFIG_XIA_FS - register_filesystem(&(struct file_system_type) - {xiafs_read_super, "xiafs", 1, NULL}); + init_xiafs_fs(); #endif #ifdef CONFIG_MINIX_FS - register_filesystem(&(struct file_system_type) - {minix_read_super, "minix", 1, NULL}); + init_minix_fs(); #endif #ifdef CONFIG_UMSDOS_FS - register_filesystem(&(struct file_system_type) - {UMSDOS_read_super, "umsdos", 1, NULL}); + init_umsdos_fs(); #endif #ifdef CONFIG_MSDOS_FS - register_filesystem(&(struct file_system_type) - {msdos_read_super, "msdos", 1, NULL}); + init_msdos_fs(); #endif #ifdef CONFIG_PROC_FS - register_filesystem(&(struct file_system_type) - {proc_read_super, "proc", 0, NULL}); + init_proc_fs(); #endif #ifdef CONFIG_NFS_FS - register_filesystem(&(struct file_system_type) - {nfs_read_super, "nfs", 0, NULL}); + init_nfs_fs(); #endif #ifdef CONFIG_SMB_FS - register_filesystem(&(struct file_system_type) - {smb_read_super, "smbfs", 0, NULL}); + init_smb_fs(); #endif #ifdef CONFIG_NCP_FS - register_filesystem(&(struct file_system_type) - {ncp_read_super, "ncpfs", 0, NULL}); + init_ncp_fs(); #endif #ifdef CONFIG_ISO9660_FS - register_filesystem(&(struct file_system_type) - {isofs_read_super, "iso9660", 1, NULL}); + init_iso9660_fs(); #endif #ifdef CONFIG_SYSV_FS - register_filesystem(&(struct file_system_type) - {sysv_read_super, "xenix", 1, NULL}); - - register_filesystem(&(struct file_system_type) - {sysv_read_super, "sysv", 1, NULL}); - - register_filesystem(&(struct file_system_type) - {sysv_read_super, "coherent", 1, NULL}); + init_sysv_fs(); #endif #ifdef CONFIG_HPFS_FS - register_filesystem(&(struct file_system_type) - {hpfs_read_super, "hpfs", 1, NULL}); + init_hpfs_fs(); #endif #ifdef CONFIG_ROOT_NFS diff --git a/fs/hpfs/hpfs_fs.c b/fs/hpfs/hpfs_fs.c index 1b2875663384..bb8eedeb3540 100644 --- a/fs/hpfs/hpfs_fs.c +++ b/fs/hpfs/hpfs_fs.c @@ -1744,17 +1744,25 @@ static void brelse4(struct quad_buffer_head *qbh) kfree_s(qbh->data, 2048); } -#ifdef MODULE - static struct file_system_type hpfs_fs_type = { hpfs_read_super, "hpfs", 1, NULL }; -int init_module(void) +int init_hpfs_fs(void) { return register_filesystem(&hpfs_fs_type); } +#ifdef MODULE +int init_module(void) +{ + int status; + + if ((status = init_hpfs_fs()) == 0) + register_symtab(0); + return status; +} + void cleanup_module(void) { unregister_filesystem(&hpfs_fs_type); diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 3c03869e499b..2dc331b04c19 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -801,15 +801,23 @@ void leak_check_brelse(struct buffer_head * bh){ #endif -#ifdef MODULE - static struct file_system_type iso9660_fs_type = { isofs_read_super, "iso9660", 1, NULL }; +int init_iso9660_fs(void) +{ + return register_filesystem(&iso9660_fs_type); +} + +#ifdef MODULE int init_module(void) { - return register_filesystem(&iso9660_fs_type); + int status; + + if ((status = init_iso9660_fs()) == 0) + register_symtab(0); + return status; } void cleanup_module(void) diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 0e61f01dcc86..7b52fbfb4db5 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -873,15 +873,23 @@ int minix_sync_inode(struct inode * inode) return err; } -#ifdef MODULE - static struct file_system_type minix_fs_type = { minix_read_super, "minix", 1, NULL }; +int init_minix_fs(void) +{ + return register_filesystem(&minix_fs_type); +} + +#ifdef MODULE int init_module(void) { - return register_filesystem(&minix_fs_type); + int status; + + if ((status = init_minix_fs()) == 0) + register_symtab(0); + return status; } void cleanup_module(void) diff --git a/fs/msdos/Makefile b/fs/msdos/Makefile index 45e31b66d83b..b0b1bc35bedf 100644 --- a/fs/msdos/Makefile +++ b/fs/msdos/Makefile @@ -8,7 +8,8 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := msdos.o -O_OBJS := buffer.o namei.o inode.o file.o dir.o misc.o fat.o mmap.o +O_OBJS := buffer.o namei.o file.o dir.o misc.o fat.o mmap.o +OX_OBJS := inode.o M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff --git a/fs/msdos/inode.c b/fs/msdos/inode.c index afa784f2b88f..7648f9ea2dbb 100644 --- a/fs/msdos/inode.c +++ b/fs/msdos/inode.c @@ -515,15 +515,55 @@ int msdos_notify_change(struct inode * inode,struct iattr * attr) return 0; } -#ifdef MODULE +static struct symbol_table msdos_syms = { +/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */ +#include + /* + * Support for umsdos fs + * + * These symbols are _always_ exported, in case someone + * wants to install the umsdos module later. + */ + X(msdos_bmap), + X(msdos_create), + X(msdos_file_read), + X(msdos_file_write), + X(msdos_lookup), + X(msdos_mkdir), + X(msdos_mmap), + X(msdos_put_inode), + X(msdos_put_super), + X(msdos_read_inode), + X(msdos_read_super), + X(msdos_readdir), + X(msdos_rename), + X(msdos_rmdir), + X(msdos_smap), + X(msdos_statfs), + X(msdos_truncate), + X(msdos_unlink), + X(msdos_unlink_umsdos), + X(msdos_write_inode), +#include +}; static struct file_system_type msdos_fs_type = { msdos_read_super, "msdos", 1, NULL }; +int init_msdos_fs(void) +{ + int status; + + if ((status = register_filesystem(&msdos_fs_type)) == 0) + status = register_symtab(&msdos_syms); + return status; +} + +#ifdef MODULE int init_module(void) { - return register_filesystem(&msdos_fs_type); + return init_msdos_fs(); } void cleanup_module(void) diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index eadd026b44fb..3aa31ca08543 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -551,6 +551,7 @@ ncp_init_root(struct ncp_server *server) root->finfo.opened = 0; i->attributes = aDIR; i->dataStreamSize = 1024; + i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */ ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate)); ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate)); ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate)); @@ -608,6 +609,7 @@ ncp_find_inode(struct inode *dir, const char *name) do { if ( (result->dir->finfo.i.DosDirNum == dir_info->DosDirNum) + && (result->dir->finfo.i.volNumber == dir_info->volNumber) && (strcmp(result->finfo.i.entryName, name) == 0)) { return result; @@ -626,8 +628,9 @@ ncp_lookup(struct inode *dir, const char *__name, int len, { struct nw_file_info finfo; struct ncp_server *server; - struct ncp_inode_info *result_info; - int found_in_cache; + struct ncp_inode_info *result_info; + int found_in_cache; + char name[len+1]; *result = NULL; @@ -671,7 +674,9 @@ ncp_lookup(struct inode *dir, const char *__name, int len, } } - result_info = ncp_find_inode(dir, __name); + memcpy(name, __name, len); + name[len] = 0; + result_info = ncp_find_inode(dir, name); if (result_info != 0) { @@ -710,7 +715,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len, DDPRINTK("ncp_lookup: trying index: %d, name: %s\n", i, c_entry[i].i.entryName); - if (strcmp(c_entry[i].i.entryName, __name) == 0) + if (strcmp(c_entry[i].i.entryName, name) == 0) { DPRINTK("ncp_lookup: found in cache!\n"); finfo.i = c_entry[i].i; @@ -724,20 +729,15 @@ ncp_lookup(struct inode *dir, const char *__name, int len, if (found_in_cache == 0) { - char this_name[len+1]; - - memcpy(this_name, __name, len); - this_name[len] = 0; - str_upper(this_name); + str_upper(name); DDPRINTK("ncp_lookup: do_lookup on %s/%s\n", - NCP_ISTRUCT(dir)->entryName, this_name); + NCP_ISTRUCT(dir)->entryName, name); if (ncp_do_lookup(server, dir->i_ino == (int)&(NCP_SERVER(dir)->root) ? NULL : NCP_ISTRUCT(dir), - this_name, - &(finfo.i)) != 0) + name, &(finfo.i)) != 0) { iput(dir); return -ENOENT; diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 487efcdfa8da..e86c78ca05e2 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -483,25 +483,31 @@ int ncp_malloced; int ncp_current_malloced; #endif -#ifdef MODULE - static struct file_system_type ncp_fs_type = { ncp_read_super, "ncpfs", 0, NULL }; -int +int init_ncp_fs(void) +{ + return register_filesystem(&ncp_fs_type); +} + +#ifdef MODULE init_module( void) { + int status; + DPRINTK("ncpfs: init_module called\n"); #ifdef DEBUG_NCP_MALLOC ncp_malloced = 0; ncp_current_malloced = 0; #endif - ncp_init_dir_cache(); - register_filesystem(&ncp_fs_type); - return 0; + + if ((status = init_ncp_fs()) == 0) + register_symtab(0); + return status; } void diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index e2e0eb54dd31..9af318dc0bb2 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -288,17 +288,25 @@ int nfs_notify_change(struct inode *inode, struct iattr *attr) return error; } -#ifdef MODULE - /* Every kernel module contains stuff like this. */ static struct file_system_type nfs_fs_type = { nfs_read_super, "nfs", 0, NULL }; +int init_nfs_fs(void) +{ + return register_filesystem(&nfs_fs_type); +} + +#ifdef MODULE int init_module(void) { - return register_filesystem(&nfs_fs_type); + int status; + + if ((status = init_nfs_fs()) == 0) + register_symtab(0); + return status; } void cleanup_module(void) diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index e5d5d6f60246..d975c8504f95 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -15,6 +15,7 @@ * * Alan Cox : Removed get_address name clash with FPU. * Alan Cox : Reformatted a bit. + * Michael Rausch : Fixed recognition of an incoming RARP answer. * */ @@ -317,6 +318,7 @@ static int do_rarp(void) { int retries = 0; unsigned long timeout = 0; + volatile struct device **root_dev_ptr = (volatile struct device **) &root_dev; /* Setup RARP protocol */ root_rarp_open(); @@ -329,16 +331,16 @@ static int do_rarp(void) * [Actually we could now, but the nothing else running note still * applies.. - AC] */ - for (retries = 0; retries < RARP_RETRIES && root_dev == NULL; retries++) { + for (retries = 0; retries < RARP_RETRIES && *root_dev_ptr == NULL; retries++) { if (root_rarp_send() < 0) break; timeout = jiffies + (RARP_TIMEOUT * HZ); - while (jiffies < timeout && root_dev == NULL) - ;; + while (jiffies < timeout && *root_dev_ptr == NULL) + ; } root_rarp_close(); - if (root_dev == NULL && timeout > 0) { + if (*root_dev_ptr == NULL && timeout > 0) { printk(KERN_ERR "NFS: Timed out while waiting for RARP answer\n"); return -1; } diff --git a/fs/proc/Makefile b/fs/proc/Makefile index ba18ed0e94aa..eb3c806616ae 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -8,12 +8,8 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := proc.o -O_OBJS := inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o +O_OBJS := inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o scsi.o +OX_OBJS := procfs_syms.o M_OBJS := $(O_TARGET) -# For either CONFIG_SCSI=y or CONFIG_SCSI=m -ifdef CONFIG_SCSI -O_OBJS += scsi.o -endif - include $(TOPDIR)/Rules.make diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 4125d513ed04..f10768a8829c 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -171,13 +170,11 @@ void proc_read_inode(struct inode * inode) case PROC_NET: inode->i_nlink = 2; break; -#ifdef CONFIG_SCSI case PROC_SCSI: inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; inode->i_nlink = 2; inode->i_op = &proc_scsi_inode_operations; break; -#endif case PROC_KCORE: inode->i_mode = S_IFREG | S_IRUSR; inode->i_op = &proc_kcore_inode_operations; diff --git a/fs/proc/net.c b/fs/proc/net.c index b9b70e1984b2..e3cc7973c888 100644 --- a/fs/proc/net.c +++ b/fs/proc/net.c @@ -24,10 +24,6 @@ * * proc net directory handling functions */ -#include - -#include - #include #include #include @@ -35,6 +31,8 @@ #include #include +#include + #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ static int proc_readnet(struct inode * inode, struct file * file, diff --git a/fs/proc/procfs_syms.c b/fs/proc/procfs_syms.c new file mode 100644 index 000000000000..53639d2e00dc --- /dev/null +++ b/fs/proc/procfs_syms.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +static struct symbol_table procfs_syms = { +/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */ +#include + X(proc_register), + X(proc_unregister), + X(in_group_p), + X(generate_cluster), + X(proc_net_inode_operations), + X(proc_net), +#ifdef CONFIG_SCSI /* Ugh... */ + X(proc_scsi), + X(proc_scsi_inode_operations), + X(dispatch_scsi_info_ptr), +#endif +#include +}; + +static struct file_system_type proc_fs_type = { + proc_read_super, "proc", 0, NULL +}; + +int init_proc_fs(void) +{ + int status; + + if ((status = register_filesystem(&proc_fs_type)) == 0) + status = register_symtab(&procfs_syms); + return status; +} + diff --git a/fs/proc/scsi.c b/fs/proc/scsi.c index d53c9d53b7d4..5091e4052949 100644 --- a/fs/proc/scsi.c +++ b/fs/proc/scsi.c @@ -20,14 +20,14 @@ * TODO: Improve support to write to the driver files * Add some more comments */ -#include -#include #include #include #include #include #include +#include + /* forward references */ static int proc_readscsi(struct inode * inode, struct file * file, char * buf, int count); diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 2bf99fb4c9d4..4782aaf54c0c 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -403,15 +403,20 @@ int smb_malloced; int smb_current_malloced; #endif -#ifdef MODULE - static struct file_system_type smb_fs_type = { smb_read_super, "smbfs", 0, NULL }; -int -init_module( void) +int init_smb_fs(void) { + return register_filesystem(&smb_fs_type); +} + +#ifdef MODULE +int init_module(void) +{ + int status; + DPRINTK("smbfs: init_module called\n"); #ifdef DEBUG_SMB_MALLOC @@ -420,7 +425,10 @@ init_module( void) #endif smb_init_dir_cache(); - return register_filesystem(&smb_fs_type); + + if ((status = init_smb_fs()) == 0) + register_symtab(0); + return status; } void diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index dff51047fca5..a3627d1083dd 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -1664,7 +1664,7 @@ smb_proc_reconnect(struct smb_server *server) } if (server->packet[0] != 0x82) { - printk("smb_proc_connect: Did not recieve positive response " + printk("smb_proc_connect: Did not receive positive response " "(err = %x)\n", server->packet[0]); smb_dont_catch_keepalive(server); diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 645170af1483..e0425c9566fa 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -969,8 +969,6 @@ int sysv_sync_inode(struct inode * inode) return err; } -#ifdef MODULE - /* Every kernel module contains stuff like this. */ static struct file_system_type sysv_fs_type[3] = { @@ -979,7 +977,7 @@ static struct file_system_type sysv_fs_type[3] = { {sysv_read_super, "coherent", 1, NULL} }; -int init_module(void) +int init_sysv_fs(void) { int i; int ouch; @@ -988,7 +986,17 @@ int init_module(void) if ((ouch = register_filesystem(&sysv_fs_type[i])) != 0) return ouch; } - return 0; + return ouch; +} + +#ifdef MODULE +int init_module(void) +{ + int status; + + if ((status = init_sysv_fs()) == 0) + register_symtab(0); + return status; } void cleanup_module(void) diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c index 206929ac2242..205879b648f5 100644 --- a/fs/umsdos/inode.c +++ b/fs/umsdos/inode.c @@ -494,15 +494,23 @@ struct super_block *UMSDOS_read_super( } -#ifdef MODULE - static struct file_system_type umsdos_fs_type = { UMSDOS_read_super, "umsdos", 1, NULL }; +int init_umsdos_fs(void) +{ + return register_filesystem(&umsdos_fs_type); +} + +#ifdef MODULE int init_module(void) { - return register_filesystem(&umsdos_fs_type); + int status; + + if ((status = init_umsdos_fs()) == 0) + register_symtab(0); + return status; } void cleanup_module(void) diff --git a/fs/xiafs/inode.c b/fs/xiafs/inode.c index a31dee748a70..0081a793a87c 100644 --- a/fs/xiafs/inode.c +++ b/fs/xiafs/inode.c @@ -511,17 +511,25 @@ int xiafs_sync_inode (struct inode *inode) return err; } -#ifdef MODULE - /* Every kernel module contains stuff like this. */ static struct file_system_type xiafs_fs_type = { xiafs_read_super, "xiafs", 1, NULL }; +int init_xiafs_fs(void) +{ + return register_filesystem(&xiafs_fs_type); +} + +#ifdef MODULE int init_module(void) { - return register_filesystem(&xiafs_fs_type); + int status; + + if ((status = init_xiafs_fs()) == 0) + register_symtab(0); + return status; } void cleanup_module(void) diff --git a/include/asm-alpha/param.h b/include/asm-alpha/param.h index 845ea9f30be1..3498d77c135d 100644 --- a/include/asm-alpha/param.h +++ b/include/asm-alpha/param.h @@ -4,8 +4,7 @@ #include #ifndef HZ -# if defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB66P) || \ - defined(CONFIG_ALPHA_EB64P) +# if defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB66P) # define HZ 977 /* Evaluation Boards seem to be a little odd */ # else # define HZ 1024 /* normal value for Alpha systems */ diff --git a/include/asm-i386/delay.h b/include/asm-i386/delay.h index 79976f9b036e..e22e8d6b20e4 100644 --- a/include/asm-i386/delay.h +++ b/include/asm-i386/delay.h @@ -13,7 +13,11 @@ extern __inline__ void __delay(int loops) { - __asm__(".align 2,0x90\n1:\tdecl %0\n\tjns 1b": :"a" (loops):"ax"); + __asm__ __volatile__( + ".align 2,0x90\n1:\tdecl %0\n\tjns 1b" + :/* no outputs */ + :"a" (loops) + :"ax"); } /* diff --git a/include/linux/blk.h b/include/linux/blk.h index b3b56f5bedd2..399b5901b687 100644 --- a/include/linux/blk.h +++ b/include/linux/blk.h @@ -340,7 +340,7 @@ static void (DEVICE_REQUEST)(void); #if ! SCSI_MAJOR(MAJOR_NR) -#if defined(_IDE_CD_C) || defined(_TRITON_C) || defined(_IDE_TAPE_C) /* shares copy with ide.c */ +#if defined(IDE_DRIVER) && !defined(_IDE_C) /* shared copy for IDE modules */ void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup); #else @@ -393,7 +393,7 @@ static void end_request(int uptodate) { req->rq_status = RQ_INACTIVE; wake_up(&wait_for_request); } -#endif /* ndef _IDE_CD_C */ +#endif /* defined(IDE_DRIVER) && !defined(_IDE_C) */ #endif /* ! SCSI_MAJOR(MAJOR_NR) */ #endif /* defined(MAJOR_NR) || defined(IDE_DRIVER) */ diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h index fcb5e5f62762..208cf46af363 100644 --- a/include/linux/ext2_fs.h +++ b/include/linux/ext2_fs.h @@ -475,6 +475,7 @@ extern void ext2_put_super (struct super_block *); extern void ext2_write_super (struct super_block *); extern int ext2_remount (struct super_block *, int *, char *); extern struct super_block * ext2_read_super (struct super_block *,void *,int); +extern int init_ext2_fs(void); extern void ext2_statfs (struct super_block *, struct statfs *, int); /* truncate.c */ diff --git a/include/linux/ext2_fs_sb.h b/include/linux/ext2_fs_sb.h index d1a44978d65c..5a33f3c1c189 100644 --- a/include/linux/ext2_fs_sb.h +++ b/include/linux/ext2_fs_sb.h @@ -16,6 +16,8 @@ #ifndef _LINUX_EXT2_FS_SB #define _LINUX_EXT2_FS_SB +#include + /* * The following is not needed anymore since the descriptors buffer * heads are now dynamically allocated diff --git a/include/linux/ext_fs.h b/include/linux/ext_fs.h index 07f689286eb0..55332092e45b 100644 --- a/include/linux/ext_fs.h +++ b/include/linux/ext_fs.h @@ -91,6 +91,7 @@ extern void ext_truncate(struct inode *); extern void ext_put_super(struct super_block *); extern void ext_write_super(struct super_block *); extern struct super_block *ext_read_super(struct super_block *,void *,int); +extern int init_ext_fs(void); extern void ext_read_inode(struct inode *); extern void ext_write_inode(struct inode *); extern void ext_put_inode(struct inode *); diff --git a/include/linux/fs.h b/include/linux/fs.h index 5a7a04442b08..dcc4c6870e25 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -136,14 +136,35 @@ typedef char buffer_block[BLOCK_SIZE]; #define BH_Touched 4 /* 1 if the buffer has been touched (aging) */ #define BH_Has_aged 5 /* 1 if the buffer has been aged (aging) */ #define BH_Protected 6 /* 1 if the buffer is protected */ +#define BH_FreeOnIO 7 /* 1 to discard the buffer_head after IO */ +/* + * Try to keep the most commonly used fields in single cache lines (16 + * bytes) to improve performance. This ordering should be + * particularly beneficial on 32-bit processors. + * + * We use the first 16 bytes for the data which is used in searches + * over the block hash lists (ie. getblk(), find_buffer() and + * friends). + * + * The second 16 bytes we use for lru buffer scans, as used by + * sync_buffers() and refill_freelist(). -- sct + */ struct buffer_head { - char * b_data; /* pointer to data block (1024 bytes) */ - unsigned long b_size; /* block size */ + /* First cache line: */ unsigned long b_blocknr; /* block number */ kdev_t b_dev; /* device (B_FREE = free) */ + struct buffer_head * b_next; /* Hash queue list */ + struct buffer_head * b_this_page; /* circular list of buffers in one page */ + + /* Second cache line: */ unsigned long b_state; /* buffer state bitmap (see above) */ + struct buffer_head * b_next_free; unsigned int b_count; /* users using this block */ + unsigned long b_size; /* block size */ + + /* Non-performance-critical data follows. */ + char * b_data; /* pointer to data block (1024 bytes) */ unsigned int b_list; /* List that this buffer appears */ unsigned long b_flushtime; /* Time when this (dirty) buffer * should be written */ @@ -151,10 +172,7 @@ struct buffer_head { * last used. */ struct wait_queue * b_wait; struct buffer_head * b_prev; /* doubly linked list of hash-queue */ - struct buffer_head * b_next; struct buffer_head * b_prev_free; /* doubly linked list of buffers */ - struct buffer_head * b_next_free; - struct buffer_head * b_this_page; /* circular list of buffers in one page */ struct buffer_head * b_reqnext; /* request queue */ }; @@ -507,13 +525,7 @@ extern int nr_buffer_heads; #define BUF_SHARED 5 /* Buffers shared */ #define NR_LIST 6 -extern inline void mark_buffer_uptodate(struct buffer_head * bh, int on) -{ - if (on) - set_bit(BH_Uptodate, &bh->b_state); - else - clear_bit(BH_Uptodate, &bh->b_state); -} +void mark_buffer_uptodate(struct buffer_head * bh, int on); extern inline void mark_buffer_clean(struct buffer_head * bh) { diff --git a/include/linux/hpfs_fs.h b/include/linux/hpfs_fs.h index 0094c359c7f0..2b7926aba4dc 100644 --- a/include/linux/hpfs_fs.h +++ b/include/linux/hpfs_fs.h @@ -8,5 +8,6 @@ /* The entry point for a VFS */ extern struct super_block *hpfs_read_super (struct super_block *, void *, int); +extern int init_hpfs_fs(void); #endif diff --git a/include/linux/iso_fs.h b/include/linux/iso_fs.h index a89ddca93f7a..3fdd41f6c164 100644 --- a/include/linux/iso_fs.h +++ b/include/linux/iso_fs.h @@ -175,6 +175,7 @@ extern int isofs_bmap(struct inode *,int); extern void isofs_put_super(struct super_block *); extern struct super_block *isofs_read_super(struct super_block *,void *,int); +extern int init_iso9660_fs(void); extern void isofs_read_inode(struct inode *); extern void isofs_put_inode(struct inode *); extern void isofs_statfs(struct super_block *, struct statfs *, int); diff --git a/include/linux/locks.h b/include/linux/locks.h index 640eb4bcc2b9..14fd7113c8c1 100644 --- a/include/linux/locks.h +++ b/include/linux/locks.h @@ -1,6 +1,16 @@ #ifndef _LINUX_LOCKS_H #define _LINUX_LOCKS_H +#ifndef _LINUX_MM_H +#include +#endif + +/* + * Unlocked, temporary IO buffer_heads gets moved to the reuse_list + * once their page becomes unlocked. + */ +extern struct buffer_head *reuse_list; + /* * Buffer cache locking - note that interrupts may only unlock, not * lock buffers. @@ -21,8 +31,36 @@ extern inline void lock_buffer(struct buffer_head * bh) extern inline void unlock_buffer(struct buffer_head * bh) { + struct buffer_head *tmp = bh; + int page_locked = 0; + unsigned long flags; + clear_bit(BH_Lock, &bh->b_state); wake_up(&bh->b_wait); + do { + if (test_bit(BH_Lock, &tmp->b_state)) { + page_locked = 1; + break; + } + tmp=tmp->b_this_page; + } while (tmp && tmp != bh); + save_flags(flags); + if (!page_locked) { + struct page *page = mem_map + MAP_NR(bh->b_data); + page->locked = 0; + wake_up(&page->wait); + tmp = bh; + cli(); + do { + if (test_bit(BH_FreeOnIO, &tmp->b_state)) { + tmp->b_next_free = reuse_list; + reuse_list = tmp; + clear_bit(BH_FreeOnIO, &tmp->b_state); + } + tmp = tmp->b_this_page; + } while (tmp && tmp != bh); + restore_flags(flags); + } } /* diff --git a/include/linux/mcdx.h b/include/linux/mcdx.h index 907ae1b3f919..b5e848482d2a 100644 --- a/include/linux/mcdx.h +++ b/include/linux/mcdx.h @@ -1,7 +1,7 @@ /* * Definitions for the Mitsumi CDROM interface * Copyright (C) 1995 Heiko Schlittermann - * VERSION: 1.5 + * VERSION: 1.5a * * 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 diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h index 137521f59fb6..f0ecdea022cb 100644 --- a/include/linux/minix_fs.h +++ b/include/linux/minix_fs.h @@ -116,6 +116,7 @@ extern struct buffer_head * minix_bread(struct inode *, int, int); extern void minix_truncate(struct inode *); extern void minix_put_super(struct super_block *); extern struct super_block *minix_read_super(struct super_block *,void *,int); +extern int init_minix_fs(void); extern void minix_write_super(struct super_block *); extern int minix_remount (struct super_block * sb, int * flags, char * data); extern void minix_read_inode(struct inode *); diff --git a/include/linux/mm.h b/include/linux/mm.h index 919dc83db4da..7fa8a077b18e 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -105,6 +105,15 @@ struct vm_operations_struct { pte_t (*swapin)(struct vm_area_struct *, unsigned long, unsigned long); }; +/* + * Try to keep the most commonly accessed fields in single cache lines + * here (16 bytes or greater). This ordering should be particularly + * beneficial on 32-bit processors. + * + * The first line is data used in linear searches (eg. clock algorithm + * scans). The second line is data used in page searches through the + * page-cache. -- sct + */ typedef struct page { unsigned int count; unsigned dirty:16, @@ -112,14 +121,19 @@ typedef struct page { uptodate:1, error:1, referenced:1, - unused:4, + locked:1, + unused:3, reserved:1; + struct wait_queue *wait; + struct page *next; + + struct page *next_hash; unsigned long offset; struct inode *inode; - struct wait_queue *wait; struct page *write_list; - struct page *next, *prev; - struct page *next_hash, *prev_hash; + + struct page *prev; + struct page *prev_hash; } mem_map_t; extern mem_map_t * mem_map; diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index 62677673d711..2c022fd532a5 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -164,6 +164,7 @@ extern void msdos_put_inode(struct inode *inode); extern void msdos_put_super(struct super_block *sb); extern struct super_block *msdos_read_super(struct super_block *s, void *data,int); +extern int init_msdos_fs(void); extern void msdos_statfs(struct super_block *sb,struct statfs *buf, int); extern int msdos_bmap(struct inode *inode,int block); extern void msdos_read_inode(struct inode *inode); diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h index fb2cd44fc266..1d8235b17117 100644 --- a/include/linux/ncp_fs.h +++ b/include/linux/ncp_fs.h @@ -142,6 +142,7 @@ int ncp_ioctl (struct inode * inode, struct file * filp, /* linux/fs/ncpfs/inode.c */ struct super_block *ncp_read_super(struct super_block *sb, void *raw_data, int silent); +extern int init_ncp_fs(void); void ncp_invalidate_connection(struct ncp_server *server); int ncp_conn_is_valid(struct ncp_server *server); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index b30246c2ac1d..3ba9a174d702 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -98,6 +98,7 @@ extern int nfs_rpc_call(struct nfs_server *server, int *start, int *end, int siz extern struct super_block *nfs_read_super(struct super_block *sb, void *data,int); +extern int init_nfs_fs(void); extern struct inode *nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle, struct nfs_fattr *fattr); extern void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr); diff --git a/include/linux/optcd.h b/include/linux/optcd.h index 036d4a3da921..fb96ea20f871 100644 --- a/include/linux/optcd.h +++ b/include/linux/optcd.h @@ -1,200 +1,48 @@ +/* linux/include/linux/optcd.h - Optics Storage 8000 AT CDROM driver + $Id: optcd.h,v 1.2 1996/01/15 18:43:44 root Exp root $ -/* Defines for the Optics Storage 8000AT CDROM drive. */ - -#ifndef _LINUX_OPTCD_H - -#define _LINUX_OPTCD_H - -/* Drive registers */ -#define OPTCD_PORTBASE 0x340 -/* Read */ -#define DATA_PORT optcd_port /* Read data/status */ -#define STATUS_PORT optcd_port+1 /* Indicate data/status availability */ -/* Write */ -#define COMIN_PORT optcd_port /* For passing command/parameter */ -#define RESET_PORT optcd_port+1 /* Write anything and wait 0.5 sec */ -#define HCON_PORT optcd_port+2 /* Host Xfer Configuration */ + Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl) -/* Command completion/status read from DATA register */ -#define ST_DRVERR 0x80 -#define ST_DOOR_OPEN 0x40 -#define ST_MIXEDMODE_DISK 0x20 -#define ST_MODE_BITS 0x1c -#define ST_M_STOP 0x00 -#define ST_M_READ 0x04 -#define ST_M_AUDIO 0x04 -#define ST_M_PAUSE 0x08 -#define ST_M_INITIAL 0x0c -#define ST_M_ERROR 0x10 -#define ST_M_OTHERS 0x14 -#define ST_MODE2TRACK 0x02 -#define ST_DSK_CHG 0x01 -#define ST_L_LOCK 0x01 -#define ST_CMD_OK 0x00 -#define ST_OP_OK 0x01 -#define ST_PA_OK 0x02 -#define ST_OP_ERROR 0x05 -#define ST_PA_ERROR 0x06 + Configuration file for linux/drivers/cdrom/optcd.c +*/ -/* Error codes (appear as command completion code from DATA register) */ -/* Player related errors */ -#define ERR_ILLCMD 0x11 /* Illegal command to player module */ -#define ERR_ILLPARM 0x12 /* Illegal parameter to player module */ -#define ERR_SLEDGE 0x13 -#define ERR_FOCUS 0x14 -#define ERR_MOTOR 0x15 -#define ERR_RADIAL 0x16 -#define ERR_PLL 0x17 /* PLL lock error */ -#define ERR_SUB_TIM 0x18 /* Subcode timeout error */ -#define ERR_SUB_NF 0x19 /* Subcode not found error */ -#define ERR_TRAY 0x1a -#define ERR_TOC 0x1b /* Table of Contents read error */ -#define ERR_JUMP 0x1c -/* Data errors */ -#define ERR_MODE 0x21 -#define ERR_FORM 0x22 -#define ERR_HEADADDR 0x23 /* Header Address not found */ -#define ERR_CRC 0x24 -#define ERR_ECC 0x25 /* Uncorrectable ECC error */ -#define ERR_CRC_UNC 0x26 /* CRC error and uncorrectable error */ -#define ERR_ILLBSYNC 0x27 /* Illegal block sync error */ -#define ERR_VDST 0x28 /* VDST not found */ -/* Timeout errors */ -#define ERR_READ_TIM 0x31 /* Read timeout error */ -#define ERR_DEC_STP 0x32 /* Decoder stopped */ -#define ERR_DEC_TIM 0x33 /* Decoder interrupt timeout error */ -/* Function abort codes */ -#define ERR_KEY 0x41 /* Key -Detected abort */ -#define ERR_READ_FINISH 0x42 /* Read Finish */ -/* Second Byte diagnostic codes */ -#define ERR_NOBSYNC 0x01 /* No block sync */ -#define ERR_SHORTB 0x02 /* Short block */ -#define ERR_LONGB 0x03 /* Long block */ -#define ERR_SHORTDSP 0x04 /* Short DSP word */ -#define ERR_LONGDSP 0x05 /* Long DSP word */ +#ifndef _LINUX_OPTCD_H +#define _LINUX_OPTCD_H -/* Status availability flags read from STATUS register */ -#define FL_EJECT 0x20 -#define FL_WAIT 0x10 /* active low */ -#define FL_EOP 0x08 /* active low */ -#define FL_STEN 0x04 /* Status available when low */ -#define FL_DTEN 0x02 /* Data available when low */ -#define FL_DRQ 0x01 /* active low */ -#define FL_RESET 0xde /* These bits are high after a reset */ -#define FL_STDT (FL_STEN|FL_DTEN) +/* I/O base of drive. Drive uses base to base+2. + This setting can be overridden with the kernel or insmod command + line option 'optcd='. Use address of 0 to disable driver. */ +#define OPTCD_PORTBASE 0x340 -/* Transfer mode, written to HCON register */ -#define HCON_DTS 0x08 -#define HCON_SDRQB 0x04 -#define HCON_LOHI 0x02 -#define HCON_DMA16 0x01 +/* enable / disable parts of driver by define / undef */ +#define MULTISESSION /* multisession support (ALPHA) */ +#define PROBE_ISP16 /* ISP16 interface card probing */ +/* ISP16 probing can also be suppressed with kernel command line option + 'noisp16', or with insmod parameter 'noisp16=1'. */ -/* Drive command set, written to COMIN register */ -/* Quick response commands */ -#define COMDRVST 0x20 /* Drive Status Read */ -#define COMERRST 0x21 /* Error Status Read */ -#define COMIOCTLISTAT 0x22 /* Status Read; reset disk changed bit */ -#define COMINITSINGLE 0x28 /* Initialize Single Speed */ -#define COMINITDOUBLE 0x29 /* Initialize Double Speed */ -#define COMUNLOCK 0x30 /* Unlock */ -#define COMLOCK 0x31 /* Lock */ -#define COMLOCKST 0x32 /* Lock/Unlock Status */ -#define COMVERSION 0x40 /* Get Firmware Revision */ -#define COMVOIDREADMODE 0x50 /* Void Data Read Mode */ -/* Read commands */ -#define COMFETCH 0x60 /* Prefetch Data */ -#define COMREAD 0x61 /* Read */ -#define COMREADRAW 0x62 /* Read Raw Data */ -#define COMREADALL 0x63 /* Read All 2646 Bytes */ -/* Player control commands */ -#define COMLEADIN 0x70 /* Seek To Lead-in */ -#define COMSEEK 0x71 /* Seek */ -#define COMPAUSEON 0x80 /* Pause On */ -#define COMPAUSEOFF 0x81 /* Pause Off */ -#define COMSTOP 0x82 /* Stop */ -#define COMOPEN 0x90 /* Open Tray Door */ -#define COMCLOSE 0x91 /* Close Tray Door */ -#define COMPLAY 0xa0 /* Audio Play */ -#define COMPLAY_TNO 0xa2 /* Audio Play By Track Number */ -#define COMSUBQ 0xb0 /* Read Sub-q Code */ -#define COMLOCATION 0xb1 /* Read Head Position */ -/* Audio control commands */ -#define COMCHCTRL 0xc0 /* Audio Channel Control */ -/* Miscellaneous (test) commands */ -#define COMDRVTEST 0xd0 /* Write Test Bytes */ -#define COMTEST 0xd1 /* Diagnostic Test */ +/* Change 0 to 1 to debug various parts of the driver */ +#define DEBUG_DRIVE_IF 0 /* Low level drive interface */ +#define DEBUG_CONV 0 /* Address conversions */ +#define DEBUG_BUFFERS 0 /* Buffering and block size conversion */ +#define DEBUG_REQUEST 0 /* Request mechanism */ +#define DEBUG_STATE 0 /* State machine */ +#define DEBUG_TOC 0 /* Q-channel and Table of Contents */ +#define DEBUG_MULTIS 0 /* Multisession code */ +#define DEBUG_VFS 0 /* VFS interface */ +/* Various timeout loop repetition counts. Don't touch unless you know + what you're doing. */ #define BUSY_TIMEOUT 10000000 /* for busy wait */ -#define SLEEP_TIMEOUT 400 /* for timer wait */ +#define FAST_TIMEOUT 100000 /* ibid. for probing */ +#define SLEEP_TIMEOUT 3000 /* for timer wait */ +#define MULTI_SEEK_TIMEOUT 500 /* for timer wait */ #define READ_TIMEOUT 3000 /* for poll wait */ -#define RESET_WAIT 1000 - -#define SET_TIMER(func, jifs) \ - delay_timer.expires = jiffies+(jifs); \ - delay_timer.function = (void *) (func); \ - add_timer(&delay_timer); -#define CLEAR_TIMER del_timer(&delay_timer) - -#define MAX_TRACKS 104 - -struct msf { - unsigned char min; - unsigned char sec; - unsigned char frame; -}; - -struct opt_Play_msf { - struct msf start; - struct msf end; -}; - -struct opt_DiskInfo { - unsigned char first; - unsigned char last; - struct msf diskLength; - struct msf firstTrack; -}; - -struct opt_Toc { - unsigned char ctrl_addr; - unsigned char track; - unsigned char pointIndex; - struct msf trackTime; - struct msf diskTime; -}; - - -#define CURRENT_VALID \ - (CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \ - && CURRENT -> cmd == READ && CURRENT -> sector != -1) - - -#undef DEBUG_DRIVE_IF /* Low level drive interface */ -#undef DEBUG_COMMANDS /* Commands sent to drive */ -#undef DEBUG_VFS /* VFS interface */ -#undef DEBUG_CONV /* Address conversions */ -#undef DEBUG_TOC /* Q-channel and Table of Contents */ -#undef DEBUG_BUFFERS /* Buffering and block size conversion */ -#undef DEBUG_REQUEST /* Request mechanism */ -#undef DEBUG_STATE /* State machine */ - - -/* Low level drive interface */ - -/* Errors that can occur in the low level interface */ -#define ERR_IF_CMD_TIMEOUT 0x100 -#define ERR_IF_ERR_TIMEOUT 0x101 -#define ERR_IF_RESP_TIMEOUT 0x102 -#define ERR_IF_DATA_TIMEOUT 0x103 -#define ERR_IF_NOSTAT 0x104 -/* Errors in table of contents */ -#define ERR_TOC_MISSINGINFO 0x120 -#define ERR_TOC_MISSINGENTRY 0x121 +#define STOP_TIMEOUT 1000 /* for poll wait */ +#define RESET_WAIT 1000 /* busy wait at drive reset */ -/* End .h defines */ #endif _LINUX_OPTCD_H diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index e70875f23540..086fe4eeefc0 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -110,6 +110,13 @@ static inline void add_page_to_inode_queue(struct inode * inode, struct page * p *p = page; } +extern void __wait_on_page(struct page *); +static inline void wait_on_page(struct page * page) +{ + if (page->locked) + __wait_on_page(page); +} + extern void update_vm_cache(struct inode *, unsigned long, const char *, int); #endif diff --git a/include/linux/pci.h b/include/linux/pci.h index b64001aee940..f23ea0c5522e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -296,6 +296,7 @@ #define PCI_DEVICE_ID_FD_36C70 0x0000 #define PCI_VENDOR_ID_SI 0x1039 +#define PCI_DEVICE_ID_SI_6201 0x0001 #define PCI_DEVICE_ID_SI_6202 0x0002 #define PCI_DEVICE_ID_SI_503 0x0008 #define PCI_DEVICE_ID_SI_501 0x0406 diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 58cf6ea5a6b2..05524b69fbc8 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -98,6 +98,7 @@ enum net_directory_inos { enum scsi_directory_inos { PROC_SCSI_SCSI = 256, + PROC_SCSI_ADVANSYS, PROC_SCSI_EATA, PROC_SCSI_EATA_PIO, PROC_SCSI_AHA152X, @@ -223,6 +224,7 @@ static inline int proc_scsi_unregister(struct proc_dir_entry *driver, int x) } extern struct super_block *proc_read_super(struct super_block *,void *,int); +extern int init_proc_fs(void); extern struct inode * proc_get_inode(struct super_block *, int, struct proc_dir_entry *); extern void proc_statfs(struct super_block *, struct statfs *, int); extern void proc_read_inode(struct inode *); diff --git a/include/linux/quota.h b/include/linux/quota.h index 7c3979763dfe..e7b2588b05b5 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -192,8 +192,6 @@ struct dquot { /* * declaration of quota_function calls in kernel. */ -int quota_off (kdev_t dev, short type); -int sync_dquots (kdev_t dev, short type); extern void dquot_initialize(struct inode *inode, short type); extern void dquot_drop(struct inode *inode); diff --git a/include/linux/sched.h b/include/linux/sched.h index 8504c455e20b..1ff5b69c914e 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -316,6 +316,8 @@ extern unsigned long * prof_buffer; extern unsigned long prof_len; extern unsigned long prof_shift; +extern int securelevel; /* system security level */ + #define CURRENT_TIME (xtime.tv_sec) extern void sleep_on(struct wait_queue ** p); diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h index 1eda0af96b76..f3294d18ebb1 100644 --- a/include/linux/smb_fs.h +++ b/include/linux/smb_fs.h @@ -114,6 +114,7 @@ int smb_ioctl (struct inode * inode, struct file * filp, /* linux/fs/smbfs/inode.c */ struct super_block *smb_read_super(struct super_block *sb, void *raw_data, int silent); +extern int init_smb_fs(void); int smb_notify_change(struct inode *inode, struct iattr *attr); void smb_invalidate_connection(struct smb_server *server); int smb_conn_is_valid(struct smb_server *server); diff --git a/include/linux/soundcard.h b/include/linux/soundcard.h index ce2de61d6220..c4035bc90390 100644 --- a/include/linux/soundcard.h +++ b/include/linux/soundcard.h @@ -147,6 +147,16 @@ #define SNDCTL_TMR_METRONOME _IOW ('T', 7, int) #define SNDCTL_TMR_SELECT _IOW ('T', 8, int) +/* + * Endian aware patch key generation algorithm. + */ + +#if defined(_AIX) || defined(AIX) +# define _PATCHKEY(id) (0xfd00|id) +#else +# define _PATCHKEY(id) ((id<<8)|0xfd) +#endif + /* * Sample loading mechanism for internal synthesizers (/dev/sequencer) * The following patch_info structure has been designed to support @@ -155,9 +165,10 @@ */ struct patch_info { - short key; /* Use GUS_PATCH here */ -#define GUS_PATCH 0x04fd -#define OBSOLETE_GUS_PATCH 0x02fd + unsigned short key; /* Use GUS_PATCH here */ +#define GUS_PATCH _PATCHKEY(0x04) +#define OBSOLETE_GUS_PATCH _PATCHKEY(0x02) + short device_no; /* Synthesizer number */ short instr_no; /* Midi pgm# */ @@ -236,8 +247,8 @@ struct patch_info { struct sysex_info { short key; /* Use GUS_PATCH here */ -#define SYSEX_PATCH 0x05fd -#define MAUI_PATCH 0x06fd /* For future use */ +#define SYSEX_PATCH _PATCHKEY(0x05) +#define MAUI_PATCH _PATCHKEY(0x06) short device_no; /* Synthesizer number */ long len; /* Size of the sysex data in bytes */ unsigned char data[1]; /* Sysex data starts here */ @@ -488,9 +499,9 @@ struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */ typedef unsigned char sbi_instr_data[32]; struct sbi_instrument { - unsigned short key; /* Initialize to FM_PATCH or OPL3_PATCH */ -#define FM_PATCH 0x01fd -#define OPL3_PATCH 0x03fd + unsigned short key; /* FM_PATCH or OPL3_PATCH */ +#define FM_PATCH _PATCHKEY(0x01) +#define OPL3_PATCH _PATCHKEY(0x03) short device; /* Synth# (0-4) */ int channel; /* Program# to be initialized */ sbi_instr_data operators; /* Register settings for operator cells (.SBI format) */ @@ -507,6 +518,7 @@ struct synth_info { /* Read only */ int synth_subtype; #define FM_TYPE_ADLIB 0x00 #define FM_TYPE_OPL3 0x01 +#define MIDI_TYPE_MPU401 0x401 #define SAMPLE_TYPE_GUS 0x10 @@ -628,6 +640,7 @@ typedef struct buffmem_desc { } buffmem_desc; #define SNDCTL_DSP_MAPINBUF _IOR ('P', 19, buffmem_desc) #define SNDCTL_DSP_MAPOUTBUF _IOR ('P', 20, buffmem_desc) +#define SNDCTL_DSP_SETSYNCRO _IO ('P', 21) #define SOUND_PCM_READ_RATE _IOR ('P', 2, int) #define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int) @@ -650,6 +663,7 @@ typedef struct buffmem_desc { #define SOUND_PCM_GETCAPS SNDCTL_DSP_GETCAPS #define SOUND_PCM_GETTRIGGER SNDCTL_DSP_GETTRIGGER #define SOUND_PCM_SETTRIGGER SNDCTL_DSP_SETTRIGGER +#define SOUND_PCM_SETSYNCRO SNDCTL_DSP_SETSYNCRO #define SOUND_PCM_GETIPTR SNDCTL_DSP_GETIPTR #define SOUND_PCM_GETOPTR SNDCTL_DSP_GETOPTR #define SOUND_PCM_MAPINBUF SNDCTL_DSP_MAPINBUF @@ -739,11 +753,19 @@ typedef struct copr_msg { #define SOUND_ONOFF_MIN 28 #define SOUND_ONOFF_MAX 30 #define SOUND_MIXER_MUTE 28 /* 0 or 1 */ -#define SOUND_MIXER_ENHANCE 29 /* Enhanced stereo (0, 40, 60 or 80) */ #define SOUND_MIXER_LOUD 30 /* 0 or 1 */ /* Note! Number 31 cannot be used since the sign bit is reserved */ + +/* + * SOUND_MIXER_ENHANCE is an unsupported and undocumented call which + * will be removed from the API in future. + */ +#define SOUND_MIXER_ENHANCE 29 /* Enhanced stereo (0, 40, 60 or 80) */ + + + #define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \ "Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", \ "Line1", "Line2", "Line3"} diff --git a/include/linux/swapctl.h b/include/linux/swapctl.h index 9dd64cec9e85..a8a29fefdc19 100644 --- a/include/linux/swapctl.h +++ b/include/linux/swapctl.h @@ -42,6 +42,17 @@ typedef struct kswapd_control_v1 typedef kswapd_control_v1 kswapd_control_t; extern kswapd_control_t kswapd_ctl; +typedef struct swapstat_v1 +{ + int wakeups; + int pages_reclaimed; + int pages_shm; + int pages_mmap; + int pages_swap; +} swapstat_v1; +typedef swapstat_v1 swapstat_t; +extern swapstat_t swapstats; + #define SC_VERSION 1 #define SC_MAX_VERSION 1 diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index b4c23df794c5..e6c3654eba23 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -54,6 +54,7 @@ struct __sysctl_args { #define KERN_NRFILE 11 #define KERN_MAXFILE 12 #define KERN_MAXID 13 +#define KERN_SECURELVL 14 /* int: system security level */ /* CTL_VM names: */ #define VM_SWAPCTL 1 /* struct: Set vm swapping control */ diff --git a/include/linux/sysv_fs.h b/include/linux/sysv_fs.h index daa2bba2241c..cfe6b106eb74 100644 --- a/include/linux/sysv_fs.h +++ b/include/linux/sysv_fs.h @@ -390,6 +390,7 @@ extern int sysv_file_read(struct inode *, struct file *, char *, int); extern void sysv_truncate(struct inode *); extern void sysv_put_super(struct super_block *); extern struct super_block *sysv_read_super(struct super_block *,void *,int); +extern int init_sysv_fs(void); extern void sysv_write_super(struct super_block *); extern void sysv_read_inode(struct inode *); extern int sysv_notify_change(struct inode *, struct iattr *); diff --git a/include/linux/umsdos_fs.h b/include/linux/umsdos_fs.h index 3702d6294826..b25f0c31e0b2 100644 --- a/include/linux/umsdos_fs.h +++ b/include/linux/umsdos_fs.h @@ -136,6 +136,7 @@ extern struct file_operations umsdos_file_operations; extern struct inode_operations umsdos_file_inode_operations; extern struct inode_operations umsdos_file_inode_operations_no_bmap; extern struct inode_operations umsdos_symlink_inode_operations; +extern int init_umsdos_fs(void); #include diff --git a/include/linux/wrapper.h b/include/linux/wrapper.h new file mode 100644 index 000000000000..64ec739bf9e8 --- /dev/null +++ b/include/linux/wrapper.h @@ -0,0 +1,40 @@ +#ifndef _WRAPPER_H_ +#define _WRAPPER_H_ +#define wait_handle struct wait_queue +#define file_handle struct file +#define inode_handle struct inode +#define select_table_handle select_table +#define vm_area_handle struct vm_area_struct +#define file_operation_handle file_operations + +#define connect_wrapper(x) 0 +#define current_got_fatal_signal() (current->signal & ~current->blocked) +#define current_set_timeout(val) current->timeout = val + +#define module_interruptible_sleep_on interruptible_sleep_on +#define module_wake_up wake_up +#define module_select_wait select_wait +#define module_register_chrdev register_chrdev +#define module_unregister_chrdev unregister_chrdev +#define module_register_blkdev register_blkdev +#define module_unregister_blkdev unregister_blkdev + +#define inode_get_rdev(i) i->i_rdev +#define inode_get_count(i) i->i_count +#define inode_inc_count(i) i->i_count++ +#define inode_dec_count(i) i->i_count-- + +#define file_get_flags(f) f->f_flags + +#define vma_set_inode(v,i) v->vm_inode = i +#define vma_get_flags(v) v->vm_flags +#define vma_get_offset(v) v->vm_offset +#define vma_get_start(v) v->vm_start +#define vma_get_end(v) v->vm_end +#define vma_get_page_prot(v) v->vm_page_prot + +#define mem_map_reserve(p) mem_map[p].reserved = 1 +#define mem_map_unreserve(p) mem_map[p].reserved = 0 +#define mem_map_inc_count(p) mem_map[p].count++ +#define mem_map_dec_count(p) mem_map[p].count-- +#endif diff --git a/include/linux/xia_fs.h b/include/linux/xia_fs.h index 908360976eaf..f43419e337bc 100644 --- a/include/linux/xia_fs.h +++ b/include/linux/xia_fs.h @@ -95,6 +95,7 @@ extern struct buffer_head * xiafs_bread(struct inode *, int, int); extern void xiafs_truncate(struct inode *); extern void xiafs_put_super(struct super_block *); extern struct super_block *xiafs_read_super(struct super_block *,void *,int); +extern int init_xiafs_fs(void); extern void xiafs_read_inode(struct inode *); extern void xiafs_write_inode(struct inode *); extern void xiafs_put_inode(struct inode *); diff --git a/include/net/route.h b/include/net/route.h index 637cc7c18006..a2a9c39201f3 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -26,6 +26,8 @@ #ifndef _ROUTE_H #define _ROUTE_H +#include + /* * 0 - no debugging messages * 1 - rare events and bugs situations (default) diff --git a/init/main.c b/init/main.c index 5e483f7d3ff0..d3bcead2dc72 100644 --- a/init/main.c +++ b/init/main.c @@ -62,6 +62,7 @@ extern void xd_setup(char *str, int *ints); extern void floppy_setup(char *str, int *ints); extern void st_setup(char *str, int *ints); extern void st0x_setup(char *str, int *ints); +extern void advansys_setup(char *str, int *ints); extern void tmc8xx_setup(char *str, int *ints); extern void t128_setup(char *str, int *ints); extern void pas16_setup(char *str, int *ints); @@ -201,6 +202,9 @@ struct { #ifdef CONFIG_SCSI { "max_scsi_luns=", scsi_luns_setup }, #endif +#ifdef CONFIG_SCSI_ADVANSYS + { "advansys=", advansys_setup }, +#endif #if defined(CONFIG_BLK_DEV_HD) { "hd=", hd_setup }, #endif @@ -489,6 +493,7 @@ static void parse_options(char *line) extern void setup_arch(char **, unsigned long *, unsigned long *); +extern void arch_syms_export(void); #ifndef __SMP__ @@ -635,6 +640,7 @@ asmlinkage void start_kernel(void) apm_bios_init(); #endif dquot_init(); + arch_syms_export(); sti(); check_bugs(); diff --git a/ipc/msg.c b/ipc/msg.c index aad0973ecf45..1f131c9544f9 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -6,7 +6,7 @@ * */ -#include +#include #include #include #include @@ -190,7 +190,7 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty return -EIDRM; if ((msgflg & IPC_KERNELD) == 0) /* - * Non-root processes may recieve from kerneld! + * Non-root processes may receive from kerneld! * i.e. no permission check if called from the kernel * otoh we don't want user level non-root snoopers... */ @@ -554,7 +554,7 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) /* * We do perhaps need a "flush" for waiting processes, * so that if they are terminated, a call from do_exit - * will minimize the possibility of orphaned recieved + * will minimize the possibility of orphaned received * messages in the queue. For now we just make sure * that the queue is shut down whenever kerneld dies. */ diff --git a/ipc/util.c b/ipc/util.c index c2d3dc883a78..89a7c3359b9f 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -118,4 +118,7 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) return -ENOSYS; } +void kerneld_exit(void) +{ +} #endif /* CONFIG_SYSVIPC */ diff --git a/kernel/ksyms.c b/kernel/ksyms.c index e16721d0e7a3..3c5b4315e72c 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -41,28 +41,10 @@ #include #include #include +#include extern unsigned char aux_device_present, kbd_read_mask; -#ifdef __alpha__ -# include -# include - -extern void bcopy (const char *src, char *dst, int len); -extern struct hwrpb_struct *hwrpb; - -/* these are C runtime functions with special calling conventions: */ -extern void __divl (void); -extern void __reml (void); -extern void __divq (void); -extern void __remq (void); -extern void __divlu (void); -extern void __remlu (void); -extern void __divqu (void); -extern void __remqu (void); - -#endif - #ifdef CONFIG_NET #include #include @@ -84,9 +66,6 @@ extern void __remqu (void); #include #include #include -#if defined(CONFIG_PPP) || defined(CONFIG_SLIP) -#include "../drivers/net/slhc.h" -#endif #endif #ifdef CONFIG_NET_ALIAS #include @@ -96,10 +75,6 @@ extern void __remqu (void); #include #include #endif -#if defined(CONFIG_MSDOS_FS) && !defined(CONFIG_UMSDOS_FS) -#include -#endif - #if defined(CONFIG_PROC_FS) #include #endif @@ -111,6 +86,19 @@ extern void __remqu (void); #include #endif +#ifndef CONFIG_SCSI +#if defined(CONFIG_PROC_FS) +/* + * This is all required so that if we load all of scsi as a module, + * that the scsi code will be able to talk to the /proc/scsi handling + * in the procfs. + */ +extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start, + off_t offset, int length, int inout); +extern struct inode_operations proc_scsi_inode_operations; +#endif +#endif + extern char *get_options(char *str, int *ints); extern void set_device_ro(int dev,int flag); extern struct file_operations * get_blkfops(unsigned int); @@ -124,17 +112,6 @@ extern void *sys_call_table; #include "../drivers/net/8390.h" #endif -#ifdef CONFIG_SCSI -#include "../drivers/scsi/scsi.h" -#include "../drivers/scsi/scsi_ioctl.h" -#include "../drivers/scsi/hosts.h" -#include "../drivers/scsi/constants.h" -#include "../drivers/scsi/sd.h" -#include - -extern int generic_proc_info(char *, char **, off_t, int, int, int); -#endif - extern int sys_tz; extern int request_dma(unsigned int dmanr, char * deviceID); extern void free_dma(unsigned int dmanr); @@ -154,30 +131,6 @@ struct symbol_table symbol_table = { SYMBOL_NAME_STR (Using_Versions) }, #endif - /* platform dependent support */ -#ifdef __alpha__ - X(_inb), - X(_inw), - X(_inl), - X(_outb), - X(_outw), - X(_outl), - X(bcopy), /* generated by gcc-2.7.0 for string assignments */ - X(hwrpb), - X(__divl), - X(__reml), - X(__divq), - X(__remq), - X(__divlu), - X(__remlu), - X(__divqu), - X(__remqu), - X(strlen), /* used by ftape */ - X(memcmp), - X(memmove), - X(__constant_c_memset), -#endif - /* stackable module support */ X(rename_module_symbol), X(register_symtab), @@ -361,9 +314,6 @@ struct symbol_table symbol_table = { X(interruptible_sleep_on), X(schedule), X(current_set), -#if defined(__i386__) && defined(__SMP__) - X(apic_reg), /* Needed internally for the I386 inlines */ -#endif X(jiffies), X(xtime), X(do_gettimeofday), @@ -431,15 +381,6 @@ struct symbol_table symbol_table = { X(ethdev_init), X(NS8390_init), #endif -#if defined(CONFIG_PPP) || defined(CONFIG_SLIP) - /* VJ header compression */ - X(slhc_init), - X(slhc_free), - X(slhc_remember), - X(slhc_compress), - X(slhc_uncompress), - X(slhc_toss), -#endif #ifdef CONFIG_NET_ALIAS #include #endif @@ -484,50 +425,24 @@ struct symbol_table symbol_table = { X(tty_register_ldisc), X(kill_fasync), #endif -#ifdef CONFIG_SCSI - /* Supports loadable scsi drivers - * technically some of this stuff could be moved to scsi.c, but - * scsi.c is initialized before the memory manager is set up. - * So we add it here too. There is a duplicate set in scsi.c - * that is used when the entire scsi subsystem is a loadable - * module. - */ - X(scsi_register_module), - X(scsi_unregister_module), - X(scsi_free), - X(scsi_malloc), - X(scsi_register), - X(scsi_unregister), - X(scsicam_bios_param), - X(allocate_device), - X(scsi_do_cmd), - X(scsi_command_size), - X(scsi_init_malloc), - X(scsi_init_free), - X(scsi_ioctl), - X(scsi_mark_host_bus_reset), - X(print_command), - X(print_msg), - X(print_status), - X(print_sense), - X(dma_free_sectors), - X(kernel_scsi_ioctl), - X(need_isa_buffer), - X(request_queueable), - X(generic_proc_info), - X(scsi_devices), - X(gendisk_head), /* Needed for sd.c */ - X(resetup_one_dev), /* Needed for sd.c */ -#if defined(CONFIG_PROC_FS) - X(proc_print_scsidevice), -#endif -#else +#ifndef CONFIG_SCSI /* * With no scsi configured, we still need to export a few * symbols so that scsi can be loaded later via insmod. + * Don't remove this unless you are 100% sure of what you are + * doing. If you want to remove this, you don't know what + * you are doing! */ X(gendisk_head), X(resetup_one_dev), +#if defined(CONFIG_PROC_FS) + /* + * This is required so that if we load scsi later, that the + * scsi code can attach to /proc/scsi in the correct manner. + */ + X(proc_scsi_inode_operations), + X(dispatch_scsi_info_ptr), +#endif #endif /* Added to make file system as module */ X(set_writetime), @@ -547,38 +462,6 @@ struct symbol_table symbol_table = { X(insert_inode_hash), X(event), X(__down), -#if defined(CONFIG_MSDOS_FS) && !defined(CONFIG_UMSDOS_FS) - /* support for umsdos fs */ - X(msdos_bmap), - X(msdos_create), - X(msdos_file_read), - X(msdos_file_write), - X(msdos_lookup), - X(msdos_mkdir), - X(msdos_mmap), - X(msdos_put_inode), - X(msdos_put_super), - X(msdos_read_inode), - X(msdos_read_super), - X(msdos_readdir), - X(msdos_rename), - X(msdos_rmdir), - X(msdos_smap), - X(msdos_statfs), - X(msdos_truncate), - X(msdos_unlink), - X(msdos_unlink_umsdos), - X(msdos_write_inode), -#endif -#ifdef CONFIG_PROC_FS - X(proc_register), - X(proc_unregister), - X(in_group_p), - X(generate_cluster), - X(proc_scsi), - X(proc_net_inode_operations), - X(proc_net), -#endif /* all busmice */ X(add_mouse_randomness), X(fasync_helper), diff --git a/kernel/sched.c b/kernel/sched.c index 7567374b5a1d..116668f6f6b6 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -38,6 +38,9 @@ /* * kernel variables */ + +int securelevel = 0; /* system security level */ + long tick = 1000000 / HZ; /* timer interrupt period */ volatile struct timeval xtime; /* The current time */ int tickadj = 500/HZ; /* microsecs */ diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 105a89c437e7..32eb3db8d356 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -5,7 +5,7 @@ * Added /proc support, Dec 1995 */ -#include +#include #include #include #include @@ -81,6 +81,9 @@ static void register_proc_table(ctl_table *, struct proc_dir_entry *); static void unregister_proc_table(ctl_table *, struct proc_dir_entry *); #endif +static int do_securelevel_strategy (ctl_table *, int *, int, void *, size_t *, + void *, size_t, void **); + /* The default sysctl tables: */ static ctl_table root_table[] = { @@ -108,6 +111,8 @@ static ctl_table kern_table[] = { 0444, NULL, &proc_dointvec}, {KERN_MAXFILE, "file-max", &max_files, sizeof(int), 0644, NULL, &proc_dointvec}, + {KERN_SECURELVL, "securelevel", &securelevel, sizeof(int), + 0444, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy}, {0} }; @@ -293,6 +298,27 @@ int do_sysctl_strategy (ctl_table *table, return 0; } +/* + * This function only checks permission for changing the security level + * If the tests are successfull, the actual change is done by + * do_sysctl_strategy + */ +static int do_securelevel_strategy (ctl_table *table, + int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) +{ + int level; + + if (newval && newlen) { + if (newlen != sizeof (int)) + return -EINVAL; + memcpy_fromfs (&level, newval, newlen); + if (level < securelevel && current->pid != 1) + return -EPERM; + } + return 0; +} struct ctl_table_header *register_sysctl_table(ctl_table * table, int insert_at_head) diff --git a/mm/filemap.c b/mm/filemap.c index d1323e9aab1b..9774a630e765 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -43,14 +43,20 @@ struct page * page_hash_table[PAGE_HASH_SIZE]; void invalidate_inode_pages(struct inode * inode, unsigned long start) { - struct page ** p = &inode->i_pages; + struct page ** p; struct page * page; +repeat: + p = &inode->i_pages; while ((page = *p) != NULL) { unsigned long offset = page->offset; /* page wholly truncated - free it */ if (offset >= start) { + if (page->locked) { + wait_on_page(page); + goto repeat; + } inode->i_nrpages--; if ((*p = page->next) != NULL) (*p)->prev = page->prev; @@ -107,7 +113,7 @@ int shrink_mmap(int priority, unsigned long limit) page->referenced = 1; else if (page->referenced) page->referenced = 0; - else if (page->count) { + else if (page->count && !page->locked) { /* The page is an old, unshared page --- try to discard it. */ if (page->inode) { @@ -179,13 +185,15 @@ static unsigned long try_to_read_ahead(struct inode * inode, unsigned long offse { struct page * page; + offset &= PAGE_MASK; if (!page_cache) { page_cache = __get_free_page(GFP_KERNEL); if (!page_cache) return 0; } -#ifdef readahead_makes_sense_due_to_asynchronous_reads - offset = (offset + PAGE_SIZE) & PAGE_MASK; + if (offset >= inode->i_size) + return page_cache; +#if 1 page = find_page(inode, offset); if (page) { page->count--; @@ -202,11 +210,8 @@ static unsigned long try_to_read_ahead(struct inode * inode, unsigned long offse add_page_to_inode_queue(inode, page); add_page_to_hash_queue(inode, page); - /* - * And start IO on it.. - * (this should be asynchronous, but currently isn't) - */ inode->i_op->readpage(inode, page); + free_page(page_cache); return 0; #else @@ -214,17 +219,41 @@ static unsigned long try_to_read_ahead(struct inode * inode, unsigned long offse #endif } +/* + * Wait for IO to complete on a locked page. + */ +void __wait_on_page(struct page *page) +{ + struct wait_queue wait = { current, NULL }; + + page->count++; + add_wait_queue(&page->wait, &wait); +repeat: + current->state = TASK_UNINTERRUPTIBLE; + if (page->locked) { + schedule(); + goto repeat; + } + remove_wait_queue(&page->wait, &wait); + page->count--; + current->state = TASK_RUNNING; +} + + /* * This is a generic file read routine, and uses the * inode->i_op->readpage() function for the actual low-level * stuff. */ +#define READAHEAD_PAGES 3 +#define MAX_IO_PAGES 4 int generic_file_read(struct inode * inode, struct file * filp, char * buf, int count) { - int read = 0; + int read = 0, newpage = 0; unsigned long pos; unsigned long page_cache = 0; - + int pre_read = 0; + if (count <= 0) return 0; @@ -232,6 +261,8 @@ int generic_file_read(struct inode * inode, struct file * filp, char * buf, int do { struct page *page; unsigned long offset, addr, nr; + int i; + off_t p; if (pos >= inode->i_size) break; @@ -278,21 +309,49 @@ int generic_file_read(struct inode * inode, struct file * filp, char * buf, int add_page_to_inode_queue(inode, page); add_page_to_hash_queue(inode, page); - /* - * And start IO on it.. - * (this should be asynchronous, but currently isn't) - */ inode->i_op->readpage(inode, page); + /* We only set "newpage" when we encounter a + completely uncached page. This way, we do no + readahead if we are still just reading data out of + the cache (even if the cached page is not yet + uptodate --- it may be currently being read as a + result of previous readahead). -- sct */ + newpage = 1; found_page: addr = page_address(page); if (nr > count) nr = count; - if (!page->uptodate) { - page_cache = try_to_read_ahead(inode, offset, page_cache); - if (!page->uptodate) - sleep_on(&page->wait); + /* We have two readahead cases. First, do data + pre-read if the current read request is for more + than one page, so we can merge the adjacent + requests. */ + if (newpage && nr < count) { + if (pre_read > 0) + pre_read -= PAGE_SIZE; + else { + pre_read = (MAX_IO_PAGES-1) * PAGE_SIZE; + if (pre_read > (count - nr)) + pre_read = count - nr; + for (i=0, p=pos; if_reada + && !((pos + nr) & ~PAGE_MASK)) { + for (i=0, p=pos; i inode->i_size - pos) nr = inode->i_size - pos; memcpy_tofs(buf, (void *) (addr + offset), nr); @@ -304,6 +363,7 @@ found_page: } while (count); filp->f_pos = pos; + filp->f_reada = 1; if (page_cache) free_page(page_cache); if (!IS_RDONLY(inode)) { @@ -315,7 +375,7 @@ found_page: /* * Find a cached page and wait for it to become up-to-date, return - * the page address. + * the page address. Increments the page count. */ static inline unsigned long fill_page(struct inode * inode, unsigned long offset) { @@ -344,8 +404,7 @@ static inline unsigned long fill_page(struct inode * inode, unsigned long offset add_page_to_hash_queue(inode, page); inode->i_op->readpage(inode, page); found_page: - if (!page->uptodate) - sleep_on(&page->wait); + wait_on_page(page); return page_address(page); } diff --git a/mm/swap.c b/mm/swap.c index 1e10b326af82..155d6fb05ed0 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -58,6 +58,8 @@ swap_control_t swap_control = { RCL_ROUND_ROBIN /* Balancing policy */ }; +swapstat_t swapstats = {0}; + /* General swap control */ /* Parse the kernel command line "swap=" option at load time: */ diff --git a/mm/vmscan.c b/mm/vmscan.c index 016d988ba56a..ae24853056c9 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -3,7 +3,9 @@ * * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds * - * Swap reorganised 29.12.95, + * Swap reorganised 29.12.95, Stephen Tweedie. + * kswapd added: 7.1.96 sct + * Version: $Id: vmscan.c,v 1.3.2.3 1996/01/17 02:43:11 linux Exp $ */ #include @@ -357,6 +359,7 @@ int try_to_free_page(int priority, unsigned long limit) int kswapd(void *unused) { int i; + char *revision="$Revision: 1.3.2.3 $", *s, *e; current->session = 1; current->pgrp = 1; @@ -380,15 +383,21 @@ int kswapd(void *unused) namings for POSIX.4 realtime scheduling priorities. */ - printk ("Started kswapd v$Revision: 1.1.2.3 $\n"); init_swap_timer(); + if ((s = strchr(revision, ':')) && + (e = strchr(s, '$'))) + s++, i = e - s; + else + s = revision, i = -1; + printk ("Started kswapd v%.*s\n", i, s); + while (1) { kswapd_awake = 0; current->signal = 0; interruptible_sleep_on(&kswapd_wait); kswapd_awake = 1; - + swapstats.wakeups++; /* Do the background pageout: */ for (i=0; i < kswapd_ctl.maxpages; i++) try_to_free_page(GFP_KERNEL, ~0UL); diff --git a/net/Config.in b/net/Config.in index 59ec5aca61d4..9058928e438b 100644 --- a/net/Config.in +++ b/net/Config.in @@ -20,3 +20,4 @@ bool 'Kernel/User network link driver(ALPHA)' CONFIG_NETLINK if [ "$CONFIG_NETLINK" = "y" ]; then bool 'Routing messages' CONFIG_RTNETLINK fi +endmenu diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 0d5550f462a6..0cda2653b19f 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -30,7 +30,6 @@ * 2 of the License, or (at your option) any later version. */ #include -#include #include #include #include diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 2cec29174255..863024a9d05a 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -256,7 +256,7 @@ * * Use of PSH (4.2.2.2) * MAY aggregate data sent without the PSH flag. (does) - * MAY queue data recieved without the PSH flag. (does) + * MAY queue data received without the PSH flag. (does) * SHOULD collapse successive PSH flags when it packetizes data. (doesn't) * MAY implement PSH on send calls. (doesn't, thus:) * MUST NOT buffer data indefinitely (doesn't [1 second]) @@ -281,12 +281,12 @@ * [Follows BSD 1 byte of urgent data] * * TCP Options (4.2.2.5) - * MUST be able to recieve TCP options in any segment. (does) + * MUST be able to receive TCP options in any segment. (does) * MUST ignore unsupported options (does) * * Maximum Segment Size Option (4.2.2.6) * MUST implement both sending and receiving MSS. (does) - * SHOULD send an MSS with every SYN where recieve MSS != 536 (MAY send + * SHOULD send an MSS with every SYN where receive MSS != 536 (MAY send * it always). (does, even when MSS == 536, which is legal) * MUST assume MSS == 536 if no MSS received at connection setup (does) * MUST calculate "effective send MSS" correctly: @@ -798,7 +798,7 @@ static void reset_xmit_timer(struct sock *sk, int why, unsigned long when) { del_timer(&sk->retransmit_timer); sk->ip_xmit_timeout = why; - if((int)when < 0) + if((long)when < 0) { when=3; printk("Error: Negative timer in xmit_timer\n"); @@ -3643,10 +3643,10 @@ extern __inline__ int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1; if (sk->rto > 120*HZ) sk->rto = 120*HZ; - if (sk->rto < 20) /* Was 1*HZ, then 1 - turns out we must allow about + if (sk->rto < HZ/5) /* Was 1*HZ, then 1 - turns out we must allow about .2 of a second because of BSD delayed acks - on a 100Mb/sec link .2 of a second is going to need huge windows (SIGH) */ - sk->rto = 20; + sk->rto = HZ/5; } } @@ -3743,8 +3743,8 @@ extern __inline__ int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1; if (sk->rto > 120*HZ) sk->rto = 120*HZ; - if (sk->rto < 20) /* Was 1*HZ - keep .2 as minimum cos of the BSD delayed acks */ - sk->rto = 20; + if (sk->rto < HZ/5) /* Was 1*HZ - keep .2 as minimum cos of the BSD delayed acks */ + sk->rto = HZ/5; sk->backoff = 0; } flag |= (2|4); /* 2 is really more like 'don't adjust the rtt diff --git a/scripts/Configure b/scripts/Configure index feb8ffdd7095..e172e30ffd8c 100644 --- a/scripts/Configure +++ b/scripts/Configure @@ -48,6 +48,9 @@ function mainmenu_option () { function mainmenu_name () { : } +function endmenu () { + : +} # # help prints the corresponding help text from Configure.help to stdout @@ -268,6 +271,35 @@ function int () { esac done } +# +# define_hex sets the value of a hexadecimal argument +# +# define_hex define value +# +function define_hex () { + echo "$1=$2" >>$CONFIG + echo "#define $1 0x$2" >>$CONFIG_H + eval "$1=$2" +} + +# +# hex processes an hexadecimal argument +# +# hex question define default +# +function hex () { + def=$(eval echo "\${$2:-$3}") + while :; do + readln "$1 ($2) [$def] " "$def" + case "$ans" in + [1-9] | [1-9][0-9] | [1-9][0-9][0-9] | [1-9][0-9][0-9][0-9] ) + define_hex "$2" "$ans" + break;; + * ) help "$2" + ;; + esac + done +} # # choice processes a choice list (1-out-of-n) diff --git a/scripts/tkparse.c b/scripts/tkparse.c index 8c30ae82c9eb..445b76e2d7c7 100644 --- a/scripts/tkparse.c +++ b/scripts/tkparse.c @@ -381,6 +381,11 @@ int parse(char * pnt) { tok = tok_fi; pnt += 2; } + else if (strncmp(pnt, "endmenu", 7) == 0) + { + tok = tok_endmenu; + pnt += 7; + } if( tok == tok_unknown) { @@ -476,6 +481,7 @@ int parse(char * pnt) { case tok_else: case tok_fi: case tok_sound: + case tok_endmenu: break; case tok_if: /* @@ -692,6 +698,7 @@ main(int argc, char * argv[]) dump_if(cfg->cond); break; case tok_nop: + case tok_endmenu: break; default: printf("\n"); diff --git a/scripts/tkparse.h b/scripts/tkparse.h index a4c302fbf99c..d2e9f64730c7 100644 --- a/scripts/tkparse.h +++ b/scripts/tkparse.h @@ -15,7 +15,9 @@ enum token { tok_define, tok_choose, tok_choice, + tok_endmenu, tok_unknown + }; enum operator { -- 2.39.5